lseek / write неожиданно возвращает -1 с errno = 9 (неверный дескриптор файла) - PullRequest
5 голосов
/ 30 марта 2010

Мое приложение использует lseek() для поиска нужной позиции для записи данных. Файл успешно открыт с помощью open(), и мое приложение могло использовать lseek() и write() много раз.

В определенный момент времени для некоторых пользователей, которые трудно воспроизвести, 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 без причины.

Ответы [ 4 ]

7 голосов
/ 30 марта 2010

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

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

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

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

Кто-нибудь сталкивался с чем-то похожим?

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

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

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

2 голосов
/ 30 марта 2010

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

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

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

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

1 голос
/ 30 марта 2010

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

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

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

0 голосов
/ 30 марта 2010

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

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

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