Debugging clobbered static variable in C (is gdb broken?)

I programmed a lot, but not very much in C, and I need some advice on debugging. I have a static variable (file area) that crashes after 10-100 seconds of running a multithreaded program (using pthreads in OS X 10.4). My code looks something like this:

static float some_values[SIZE];
static int * addr;

addrpoints to a valid memory address for a while, and then gets clobbered with some value (sometimes 0, sometimes other than zero), thereby causing segfault when dereferenced. With the help of gdbI checked that it is addrlaid out in memory immediately after some_values, as expected, so I assume that I used an index outside the borders to write to some_values. However, this is a tiny file, so it’s easy to verify that this is not a problem.

An obvious debugging technique would be to set the watchpoint on a variable addr. But this seems to create erratic and inexplicable behavior in gdb. The observation point is triggered upon first appointment addr; then after I continue execution, I immediately get a pointless segfault in another thread ... presumably, segfault to access the address of a static variable in another part of the program! But then gdbit allows me to read and write to this memory address interactively.

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x001d5bd0
0x0000678d in receive (arg = 0x0) at mainloop.c: 39
39 sample_buf_cleared ++;
(gdb) p & sample_buf_cleared
$ 17 = (int *) 0x1d5bd0
(gdb) p sample_buf_cleared
$ 18 = 1
(gdb) set sample_buf_cleared = 2
(gdb) 

gdbobviously confusing. Does anyone know why? Or does anyone have suggestions for debugging this error without using watchpoints?

+3
source share
6 answers
  • You can put a uint array between some_values ​​and addr and determine if you are overflowing some_values ​​or if corruption affects more addresses, then you first thought. I would initialize a DEADBEEF add-on or some other obvious scheme that is easy to distinguish and is unlikely to happen in a program. If the value in the add-on changes, then throw it on the float and see if the value matters as a float.

static float some_values ​​[SIZE]; static unsigned int padding [1024]; static int * addr;

  1. . , .

  2. , . , , , . . . .

+3

static .

( ), , , addr. .

:

  • addr ;
  • addr, , .
+2

valgrind; valgrind OS X, , " valgrind" - , , "clobbered".

+1

, , - , - addr . :

static int * volatile addr;  // volatile here is important, and must be after the *
void *addr_thread_proc(void *arg)
{
    while(1)
    {
        int *old_value = addr;
        while(addr == old_value) /* spin */;
        __asm__("int3");  // break the debugger, or raise SIGTRAP if no debugger
    }
}
...
pthread_t spin_thread;
pthread_create(&spin_thread, NULL, &addr_thread_proc, NULL);

, , addr, int3, , .

+1

gdb . ( ) printf() , , . , .

0

OSX, GDB Linux: , GDB , / .

, GDB ; , ​​ GDB / ptrace(), . IOW, ( ) .

, , GDB - .

One of the methods that you can use is mmapspace, some_valuesinstead of statically allocating space for them, arrange the completion of the array at the page border and arrange the inaccessibility of the next page (through mprotect).

If any code tries to access the end some_values, it will get an exception (effectively you set an unwritten “watchpoint” just past some_values).

0
source

Source: https://habr.com/ru/post/1710643/


All Articles