2010-03-30 4 views
5

Мое приложение использует lseek() для поиска желаемой позиции для записи данных. Файл успешно открыт с использованием open(), и мое приложение смогло использовать lseek() и write() много раз.lseek/write вдруг возвращает -1 с errno = 9 (Bad file descriptor)

В данный момент для некоторых пользователей и нелегко воспроизводится lseek() возвращает -1 с errno из 9. Файл не закрывается до этого, и дескриптор файла (int) не сбрасывается.

После этого создается другой файл; open() снова в порядке, и lseek() и write() снова работает.

Чтобы сделать это еще хуже, этот пользователь снова попробовал полную последовательность, и все было хорошо.

Итак, мой вопрос: может ли ОС закрыть файл для меня по какой-то причине? Что может быть причиной этого? Файл индексатор или сканер файлов?

Каков наилучший способ решить эту проблему? является ли этот псевдокод лучшим решением? (не говоря уже о раскладке коды, будет создавать функции для него)

int fd=open(...); 
if (fd>-1) { 
    long result = lseek(fd,....); 
    if (result == -1 && errno==9) { 
     close(fd..); //make sure we try to close nicely 
     fd=open(...); 

     result = lseek(fd,....); 
    } 
} 

опыта кто-нибудь с чем-то подобным?

Реферат: Файл ищет и пишет работает нормально для данного fd и внезапно возвращает errno = 9 без причины.

+0

Мой код не будет компилироваться, если я попытаюсь открыть (...); Странный. –

+1

Вы знаете псевдокод правильно? –

+0

Если lseek() терпит неудачу с EBADF, вы можете быть уверены, что close() в том же файловом дескрипторе также завершится с EBADF. И поскольку вы не проверяете свои повторные открытия или повторные вызовы, все может произойти. –

ответ

1

Я не знаю, какой тип установки у вас есть, но в следующем сценарии я мог бы создать такой эффект (или другой подобный ему). Я не проверял это, чтобы проверить, поэтому, пожалуйста, возьмите его с солью.

Если файл/устройство, которое вы открываете, реализовано как серверное приложение (например, NFS), подумайте, что может произойти, если серверное приложение отключится/перезагрузится/перезагрузится. Дескриптор файла, хотя он был первоначально действителен на стороне клиента, может больше не сопоставляться с допустимым дескриптором файла на сервере. Это может привести к последовательности событий, в которых клиент получит EBADF.

Надеюсь, это поможет.

+0

Вы прямо здесь. Все ручки файлов, где все в порядке. Отсутствие закрытия дескрипторов файлов. В моем коде не было никаких проблем, только osx отмечал fh недействительным. Повторное заполнение файла также вернуло идентификатор fd. Смешные вещи. –

2

ОС не должна закрывать файловые манипуляции случайным образом (я предполагаю Unix-подобную систему). Если ваш дескриптор файла закрыт, значит, что-то не так с вашим кодом, скорее всего в другом месте (благодаря языку C и Unix API это может быть действительно в любом месте кода и может быть вызвано, например, небольшим буфером переполнение в некотором фрагменте кода, который действительно выглядит не связанным).

Ваш псевдокод - наихудшее решение, так как это создаст впечатление о том, что проблема устранена, в то время как ошибка все еще скрывается.

Предлагаю вам добавить отладочные отпечатки (т. Е. printf() звонки), где бы вы ни открывали и не закрывали файл или сокет. Также попробуйте Valgrind.

(У меня только вчера произошло жуткий переполнения буфера, который повредил наименее значимый байт временного слота, сгенерированного компилятором, чтобы сохранить регистр ЦП, косвенным эффектом было то, что появилась структура в другой функции чтобы меня переместили на несколько байтов. Мне потребовалось некоторое время, чтобы понять, что происходит, включая некоторое тщательное чтение кода сборки Mips).

+0

Ожидала эту реакцию, которая, безусловно, является наиболее очевидной. Не быть дерзким, но я почти уверен, что утечки памяти нет. Идентификатор дескриптора файла остается тем же (проверено), и lseek и записывается непосредственно перед тем, как он работает нормально. Между операциями записи нет ничего динамического (разумного по памяти). Весь файл IO-кода регистрируется (NSlog), и все идет хорошо, до тех пор, пока внезапно в некоторых ситуациях (не воспроизводимый второй раз) -1 встречается с errno = 9. Вы должны согласиться с тем, что всякий раз, когда fd не изменяется, наиболее вероятно, что errno = 9 появится правильно? По какой-то причине это происходит. –

+0

@Thomas: +1 Я больше не мог согласиться. Ошибки должны быть исправлены, а не скрыты. @Ger, как вы можете быть уверены, что у вас нет стека или кучи? Это звучит как зловещая ошибка, которая нуждается в исправлении –

+0

Конечно, я согласен, лучше найти причину. Но на первый взгляд кажется, что причина не в моих масштабах. Это все еще кажется таким, потому что нет никакого способа, чтобы текущий fd был перезаписан другим значением. –

0

Нет, ОС не должна закрывать дескрипторы файлов именно так, а другие приложения (сканеры файлов и т. Д.) Не должны быть , способным сделать это.

Не обходите проблему, найдите ее источник. Если вы не знаете, в чем причина вашей проблемы, вы никогда не узнаете, действительно ли ваш обходной способ делает работы.

  1. Проверьте свои предположения. Действительно ли errno установлен на 0 перед вызовом? Действительно ли fd действительно в момент вызова?(Я знаю, что вы это сказали, но сделали ли вы check?)
  2. Каков объем производства puts(strerror(9)); на вашей платформе?
+0

errno равно 0, и результат lseek внезапно равен -1. fd ДЕЙСТВИТЕЛЬНО ДЕЙСТВИТЕЛЬНО открыто, потому что записи работают раньше в той же итерации. –

+0

Хорошо, продолжайте проверять свои предположения. Вы знаете свой код лучше меня. Печать значения fd перед каждым вызовом будет моим следующим шагом. – DevSolar

+0

Хорошая идея, а также предложение о том, что происходит, когда (сетевой) привод отключается по какой-либо причине. –

7

Итак, мой вопрос: может ли ОС закрыть файл для меня по какой-то причине? Что может вызвать это? Файл индексатор или сканер файлов?

Нет, этого не произойдет.

Каков наилучший способ решить эту проблему; этот псевдокод - лучшее решение? (не говоря уже о раскладке коды, будет создавать функции для него)

Нет, лучший способ, чтобы найти ошибку и исправить ее.

У кого-нибудь опыт с чем-то подобным?

Я видел FDS получать перепутались много раз, в результате чего EBADF в некоторых случаях, и раздутия эффектно в других, это было:

  • переполнение буфера - переполнение что-то и записывая бессмысленное значение в 'int fd;' переменная.
  • глупые ошибки, которые происходят из-за какой-то угол случай кто-то сделал if(fd = foo[i].fd) когда они имели в виду if(fd == foo[i].fd)
  • Raceconditions между нитями, какой-то поток закрывает неправильный дескриптор файла, другой поток хочет использовать.

Если вы можете найти способ воспроизвести эту проблему, запустите свою программу под «strace», чтобы вы могли видеть, что происходит.

+0

Я согласен найти ошибку. Я сделаю еще несколько обзоров кода, но я проверю, что произойдет, если отключен сетевой диск. Возможно, это приведет к дескриптору Bad File? –

+0

После тщательного осмотра fd вообще не изменяется, и только один поток выполняет диск IO (вся обработка файлов). Я могу предположить, что если я не закрываю fd, то fd останется тем же, что и я не должен получить правильное значение errno и -1? Это действительно так. –

+0

Хотя какая-то конкретная ОС, использующая определенную файловую систему/сеть IO, может иметь некоторую ошибку в случае возникновения ошибки в углу, которая заставляет это произойти, возможно, это просто догадки. strace всех потоков, когда это произойдет, было бы очень полезно, хотя – nos

Смежные вопросы