Ревизия кода, хоть и сложный шаг, но, кроме исправления ошибок, позволяет улучшить внутреннюю структуру приложения. Порой это позволяет в будущем сэкономить даже больше времени на разработке остального функционала, чем было затрачено на саму ревизию.
Однопоточное - уже проще.
И какие проблемы? Собираетесь с опцией -g, запускаетесь под gdb, падаете, смотрите стек (набрав bt), а дальше втыкаете вывод отладочной информации по всем имеющим отношение к упадению переменным - кто их поменял, почему поменял, кто поменял того кто поменял и тд. Довольно быстро расковыривается.
есть у меня переменная state которая изменяется «загадочным» образом в неположеном месте. Я в дебагере ставлю на нее watchpoint и обнаруживаю что эта переменная была изменена вызовом malloc(). насколько я понимаю это связано с тем что какойто код попортил структуры используемые malloc(). но так как malloc() библиотечная ф-я то я теряюсь в догадках как поставить watchpoint на используемые им структуры чтобы отловить изменяющий их код. Хуже всего что нет никакой гарантии что эти изменения вызывает именно мой код, а не чужой, так как я делаю часть нехилой аппликухи.
Отлаживать программы отладчиками - самое последнее дело. Я ими последной раз пользовался лет 10 назад и больше нет потребности. И без них всё отлаживается прекрасно и гораздо лучше.
Посмотри на аргументы этого маллока? И на тех, кто их формирует.
Вообще тут чего то не то. Переменная стековая? watchpoint конечно круто, но куда надежней (мб я конечно gdb пользоваться не уменю) поставить тупой вывод (в лог, на stdout, на stderr) этой самой переменной до вызова маллока и после. Я не очень понимаю, как непосредственно вызов маллока может засохатить стек, если тока кадр стека не был разрушен до вызова. А вот при формировании аргументов такое возможно.
Еще хороший рецепт - попытаться вычленить минимальный кусок кода приводящего к ошибке. Выкинуть все, оставить только то, что валится. Это должно быть что то простое, иначе бы ошибка не вопроизводилась с такой стабильностью на разных системах. И то что валгринд ничего не говорит... очень странно, он придирчивая зараза.
> есть у меня переменная state которая изменяется «загадочным» образом в неположеном месте. Я в дебагере ставлю на нее watchpoint и обнаруживаю что эта переменная была изменена вызовом malloc(). насколько я понимаю это связано с тем что какойто код попортил структуры используемые malloc(). но так как malloc() библиотечная ф-я то я теряюсь в догадках как поставить watchpoint на используемые им структуры чтобы отловить изменяющий их код. Хуже всего что нет никакой гарантии что эти изменения вызывает именно мой код, а не чужой, так как я делаю часть нехилой аппликухи.
А структура, содержащая эту переменную, не была случайно удалена до вызова malloc?
валгринд бы это засек сразу. И потом ошибка бы тогда не воспроизводилась стабильно на разных ОС, а была бы плавающей. Распределение памяти вещь случайная и когда там пеерекроется освожденный участок одному Бэббиджу известно;-)
Я в дебагере ставлю на нее watchpoint и обнаруживаю что эта переменная была изменена вызовом malloc(). насколько я понимаю это связано с тем что какойто код попортил структуры используемые malloc()
Есть много сценариев. Например, структура изначальна могла получить неправильный адрес (залезла на структуры heap'а).
так мы ж о формировании аргументов для передачи в ф-ю. а это выражение вне всякого сомнения запорет стек. но и valgrind кажется без проблем такое отлавливает.
Это был пример. Вполне возможно сформировать аргумент, сносящий что то рядом, мне помнится такое удавалось. А на каком то хитром выражении валгринд может и не сработать - у себя ж в данных гадишь, откуда он знает что это баг а не фича?
Симптоматика странная, если б это была классическая ошибка с адресной арифметикой то и валгринд бы чирикнул, и главное ошибка была бы плавающей. Ну конечно гипотетически может быть какой то странный алиасинг, когда у тебя одинаковые смещения в итоге получаются, но я себе такого представить не могу.
В общем - если знаешь точно какой маллок валится, обвешай его диагностикой. И для начала попытайся вместо него воткнуть пустышку с теми же аргументами.
Багов в malloc() скорее всего нет, вероятность поймать такую очень низкая. Так же не стоит расчитывать на баги в gcc по аналогичной причине, если конечно не используешь совсем новый gcc из транка или тестовую версию.
Намекаю на stack smash или что-то в подобном роде. Например, выделил память
char *ptr = malloc(...);
Далее произошёл stack smash и уже неправильное значение ptr записываешь в постоянную структуру. Или такое могло случиться сразу на объекте.
valgrind такое может не заметить, т.к. из байткода ельзя сделать правильный и однозначный вывод о валидном использовании указателей в си.
В википедии показан один из возможных примеров когда valgrind не увидит проблемы.
Нужно следить за указателем с самого начала его создания, от malloc()'а.
Вероятность всегда есть. Electric fence насколько я помню, заменяет libc'шные *alloc. Если в вашем случае корраптятся структуры кучи, это может помочь уронить с SIGSEGV программу раньше, чем сейчас. В идеальном случае в момент повреждения памяти.
С этой целью может помочь любая альтернативная реализация malloc().
malloc() и так выделает память через mmap() если кусок достаточно большой (по умлочанию 128кб). Порог можно поменять через mallopt(). Но в этом нет особого смысла.