LINUX.ORG.RU

обнаружение некорректных вызовов close

 , ,


0

0

Подскажите пожалуйста утилиту, которая подсказывала бы неправильные вызовы close на уже закрытых дескрипторах. Недавно в проекте очень неприятный баг нашли, когда данные «читались» из файла, дескриптор которого ранее был ошибочно закрыт.

Последовательность воспроизведения ошибки такая. В некой забагованной библиотеке вызывается open для работы с портом ввода-вывода устройства. Когда работа завершается, вызывается соотв. close. Потом тот же самый дескриптор (по значению) перевыдается по вызову fopen в другой части программы, там читаются данные из файла. Во время чтения этих данных, по ошибке, в забагованной бибилиотеке вызывается close по тому же (по значению) дескрипотру. Из файла начинает читаться мусор.

Было бы неплохо иметь утилиту, которая обнаруживала подобные ошибке в заданном процессе. Например мы не нашли опции у valgrind, которые находили бы такие огрехи.



Последнее исправление: dmitryshm (всего исправлений: 1)

Из закрытого файлового дескриптора не может читаться мусора - read вернёт -1 и установит errno в EBADF. Или дескриптор был переоткрыт, или вы не умеете проверять возвращаемое read'ом значение. close тоже умеет EBADF, и если вы будете проверять и его, то двойной close рано или поздно отловите.

slovazap ★★★★★
()
Последнее исправление: slovazap (всего исправлений: 3)

Systemtap. Процессу потом можно послать фатальный сигнал, чтобы была корка для анализа, если оное надо.

mv ★★★★★
()

std::shared_ptr <FILE, void (*) (FILE *) > file (fopen(...), fclose);

anonymous
()

Дизайн лечите, а не ошибки, им спровоцированные.

Тут правильно про std::shared_ptr говорят - 1. используйте нормальные классы для I/O, а не голый libc. Чтобы файл закрывался в деструкторе, а не как попало. 2. оберните этот класс в shared_ptr и у вас подобных проблем не будет как таковых.

Pavval ★★★★★
()

Подскажите пожалуйста утилиту, которая подсказывала бы неправильные вызовы close на уже закрытых дескрипторах. Недавно в проекте очень неприятный баг нашли, когда данные «читались» из файла, дескриптор которого ранее был ошибочно закрыт.

Последовательность воспроизведения ошибки такая. В некой забагованной библиотеке вызывается open для работы с портом ввода-вывода устройства. Когда работа завершается, вызывается соотв. close. Потом тот же самый дескриптор (по значению) перевыдается по вызову fopen в другой части программы, там читаются данные из файла. Во время чтения этих данных, по ошибке, в забагованной бибилиотеке вызывается close по тому же (по значению) дескрипотру. Из файла начинает читаться мусор.

Было бы неплохо иметь утилиту, которая обнаруживала подобные ошибке в заданном процессе. Например мы не нашли опции у valgrind, которые находили бы такие огрехи.

Не совсем понятно как именно это реализовать. Если ваш баг _всегда_ приводит к такому поведению (работа с «посторонним» дескриптором с тем же номером), то это абсолютно валидная работа с дескриптором. Никакой автоматический анализатор кода не будет способен понять - работа с дескриптором ведётся из правильного места в коде или нет.

Если же такое поведение проявляется не всегда со 100% вероятностью, то вам нужно просто найти все вызовы close (банально, грепом) и удостовериться, что возвращаемое значение проверяется и в случае ошибки эта ошибка передаётся дальше каким-нибудь способом.

Deleted
()

мы не нашли опции у valgrind, которые находили бы такие огрехи

valgrind -v --track-origins=yes --trace-children=yes --leak-check=full

?

deep-purple ★★★★★
()
Ответ на: комментарий от deep-purple

Неправильные параметры. С ними некорректный close не отловите.

dmitryshm
() автор топика
Ответ на: комментарий от Pavval

Описывается ситуация, которая уже случилась. Все эти советы «надо было использовать нормальные классы» это фуфло, т.к. вопрос задается для решения проблемы, которая уже случилась.

А про RAII и прочее все и так знают. Просто так бывает, что в проектах часть кода достается от подрядчика, и пока нет ресурсов его полностью переписывать. А бывает что библиотека вообще без исходников достается.

Так что ответы про «перелопатить весь исходник» или про «правильный дизайн» они понятны, и такие ответы не работают.

dmitryshm
() автор топика
Ответ на: комментарий от Pavval

если я правильно понял автора, они нашли баг в сторонней либе, поэтому, совет не поможет.

next_time ★★★★★
()
Ответ на: комментарий от slovazap

Понятно, что самого процесса чтения из закрытого дескриптора не будет. Просто буферы, не заполненные данными в коде, который не проверяет результат read, будут трактоваться как данные, и это будет мусор.

dmitryshm
() автор топика
Ответ на: комментарий от yoghurt

Ну и как конкретно воспользоваться strace-ом, чтобы отловить обозначенную проблему? Просто указать утилиту, которая может все подряд показывать это не ответ.

dmitryshm
() автор топика
Ответ на: комментарий от slovazap

Когда возникла такая ситуация, от этот EDADF получите совсем не в том месте кода, где реальная ошибка. В одной части проекта ошибки проверяются, а в другой этого не делают. Я задал вопрос, что может существует утилита, которая поможет нормально локализовать эту проблему. Чтобы пришлось меньше «лопатить весть исходник» и чтобы не впасть в перманентный рефакторинг.

dmitryshm
() автор топика
Ответ на: комментарий от dmitryshm

Ну и как конкретно воспользоваться strace-ом, чтобы отловить обозначенную проблему? Просто указать утилиту, которая может все подряд показывать это не ответ.

нужно набрать «man strace» и внимательно прочитать возникший на экране набор буковок

Harald ★★★★★
()

При закрытии дескриптора, заменяйте его на -1 в переменной, откуда он берётся. Делов-то. Если нужно, добавьте mutex к этому.

Krieger_Od ★★
()

у вас проблема в архитектуре а не в дескрипторах.

MikeDM ★★★★★
()
Ответ на: комментарий от Harald

спасибо

strace является наиболее близким к правде ответом. Хотя Systemtap пока не пробовал. Спасибо.

dmitryshm
() автор топика

делай fs = NULL; после fclose(3).

emulek
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.