LINUX.ORG.RU

[C] как отследить memory corruption?

 


0

0

Всем привет. Недавно наткнулся на такой баг в своей программе: Код делал запись в неправильное место на куче(выход за границы массива) в результате чего программа непредсказуемо глючила в рандомных и совсем безобидных местах. Есть ли способ находить такие ошибки?

valgrind --leak-check такие ошибки не отлавливает. Пробовал watch в gdb, это оказалось неудобным.

★★★★★

valgrind такие ошибки отлавливает, leack-check для этого в принципе не 
нужен. Ищи в выводе сообщения типа

==9059== Invalid write of size 4
==9059==    at 0x80484CA: main (t.cpp:5)
==9059==  Address 0x42c0054 is 4 bytes after a block of size 40 alloc'd
==9059==    at 0x402309E: operator new[](unsigned) (vg_replace_malloc.c:268)
==9059==    by 0x80484C0: main (t.cpp:4)

$cat t.cpp
#include <stdio.h>
int main()
{
  int *n = new int[10];
  n[11] = 1;
  return 0;
}

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

не совсем. это если Вам повезёт и выход за границы попадёт в не занятую память. если он попадает в занятый блок - то valgrind этого не замечает. например:

#include <stdio.h>
#include <stdlib.h>
int main()
{
const size_t c = 10;
char *n1 = calloc(c, 1);
char *n2 = calloc(c, 1);
size_t space_pad = n2 - n1 - c;
printf("n1: %p, n2: %p, space pad bytes between n2 and n1: %zu\n", n1, n2, space_pad);
n1[c + space_pad + 5 /* выходим за границы n1 и попадаем в n2[5] */] = 11;
printf("n2[5] = %d\n", n2[5]);
free(n2);
free(n1);
return 0;
}

$ gcc -std=c99 -W -Wall -Wextra -g -g3 -ggdb -ggdb3 -pedantic a.c
$ valgrind ./a.out
==31633== Memcheck, a memory error detector.
==31633== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
==31633== Using LibVEX rev 1854, a library for dynamic binary translation.
==31633== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
==31633== Using valgrind-3.3.1-Debian, a dynamic binary instrumentation framework.
==31633== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
==31633== For more details, rerun with: -v
==31633==
n1: 0x41a5028, n2: 0x41a5068, space pad bytes between n2 and n1: 54
n2[5] = 11
==31633==
==31633== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 13 from 1)
==31633== malloc/free: in use at exit: 0 bytes in 0 blocks.
==31633== malloc/free: 2 allocs, 2 frees, 20 bytes allocated.
==31633== For counts of detected errors, rerun with: -v
==31633== All heap blocks were freed -- no leaks are possible.

Eshkin_kot ★★
()

хоть я и не программер..

valgrind --tool=memcheck

как-то так..

twosev ★★
()

а leak-check, насколько я помню, показывает утечки, а не некорректные запись и чтение

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

Лучше использовать ключ --db-attach=yes тогда на каждую такую ошибку тебе будет предложено подключить gdb.

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

> это если Вам повезёт и выход за границы попадёт в не занятую память

Вот как раз мой случай :((( Из-за совершенно тупой одной опечатки получил баги по всей программе в неожиданнейших местах. Жесть.

>хоть я и не программер.. valgrind --tool=memcheck

Увы, это я первым делом посмотрел, оно такое не ловит: http://valgrind.org/docs/manual/mc-manual.html#mc-manual.bugs

Эх, вот бы сказать gcc чтобы данные на куче шли не друг за другом а с интервалом. Такое аллокатор памяти умеет?

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

> Из-за совершенно тупой одной опечатки получил баги по всей программе в неожиданнейших местах. Жесть.

А опцию -fmudflap не пробовал?

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

> А опцию -fmudflap не пробовал?

O_O я забыл об этом. Да, это лечит проблему, большое спасибо.

Но! Если просто запускать прогу собранную с -fmudflap -lmudflap то
ничего не происходит, а если valgrind натравить то оно срабатывает как и задуманно. Почему я пока не понял.

n1: 0x428a668, n2: 0x428adf0, space pad bytes between n2 and n1: 1918
n2[5] = 11
*******
mudflap violation 1 (unregister): time=1230111501.285960 ptr=0x428ab60 size=0
pc=0x4043e36
Nearby object 1: checked region begins 656B before and ends 656B before
mudflap dead object 0x428ae50: name=`calloc region'
bounds=[0x428adf0,0x428adf9] size=10 area=heap-init check=0r/1w liveness=1
alloc time=1230111501.149297 pc=0x40442ed
      /usr/lib/libmudflap.so.0(__mf_register+0x3d) [0x40442ed]
      /usr/lib/libmudflap.so.0(calloc+0xfe) [0x4045a8e]
      ./a.out(main+0x54) [0x8048848]
      /usr/lib/libmudflap.so.0(__wrap_main+0x4f) [0x404434f]
dealloc time=1230111501.205759 pc=0x4043e36
number of nearby objects: 1


В то же время на таком коде mudflap срабатывает всегда:
int a[10];
int b[10];

int main(void) {
   return a[11];
}

Буду дальше разбираться с mudflap.

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

ott, буду пробовать. mudflap меня уже расстроил, глючит вот подобным образом http://gcc.gnu.org/bugzilla/show_bug.cgi?id=19319

Глючит на строке fprinf(stderr, "test string"). Причём, похоже, только когда библиотека через dlopen подгружается, в обычной ситуации всё нормально.

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