JuvenalUrbino
This is the simplest kind of memory-related bug to diagnose. Since you seem to be well up on your gdb
fundamentals, I'll walk you through the GDB debugging-session so that you can figure out this class of bug on your own in the future:
$ gdb /tmp/inn/bin/innbind
Reading symbols from /tmp/inn/bin/innbind...
(gdb) run "3,10,127.0.0.1,119"
Starting program: /tmp/inn/bin/innbind "3,10,127.0.0.1,119"
Program received signal SIGSEGV, Segmentation fault.
0x0000756e3c422d39 in vector_split (string=0x7f7fffb24b95 "3,10,127.0.0.1,119", separator=44 ',', vector=0x756e3c771020)
at vector.c:269
269 vector->strings[i++] = xstrndup(start, p - start);
(gdb) l
264 vector_resize(vector, count);
265
266 /* Walk the string and create the new strings with xstrndup. */
267 for (start = string, p = string, i = 0; *p != '\0'; p++)
268 if (*p == separator) {
269 vector->strings[i++] = xstrndup(start, p - start);
270 start = p + 1;
271 }
272 vector->strings[i++] = xstrndup(start, p - start);
273 vector->count = i;
(gdb) p vector
$1 = (struct vector *) 0x756e3c771020
(gdb) p *vector
$3 = {count = 0, allocated = 4, strings = 0x3c771040}
OK, notice how the address of vector
and that of strings
inside vector
seem to differ wildly. But, look closer and you can discern a pattern: if you mask out some of the high-order bits, then the 2 addresses are in fact pretty close to each other--as they should be. At this point you go: "Ah...I know what this is" because:
It's unlikely to be a fault in reallocarray()
because a) that would've been noticed long ago, and b) reallocarray()
will either return a NULL
or SIGSEGV inside itself if you give it the wrong address--it won't return a wrong address like this.
It's unlikely to be a GCC bug (for similar reasons)
You notice the similarity in the LSB of the returned addresses (and have been bitten by this bug before).
At this point you can write a short test program, then check the function prototype in /usr/include/stdlib.h
and you pretty much know what's going on, but, let's continue anyway. Looking at the code we know that we have to check the return value of reallocarray()
in vector_resize()
. Put a couple of breakpoints before and after the function call:
(gdb) b vector.c:263
Breakpoint 1 at 0x756e3c422cad: file vector.c, line 263.
(gdb) b vector.c:265
Breakpoint 2 at 0x756e3c422cce: file vector.c, line 267.
(gdb) run "3,10,127.0.0.1,119"
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /tmp/inn/bin/innbind "3,10,127.0.0.1,119"
Breakpoint 1, vector_split (string=0x7f7fff2f0475 "3,10,127.0.0.1,119", separator=44 ',', vector=0x73bc3a1c5020) at vector.c:263
263 if (vector->allocated < count)
(gdb) print *vector
$4 = {count = 0, allocated = 1, strings = 0x73bc3a1c7008}
vector->strings
look OK at this point. Continue:
(gdb) n
264 vector_resize(vector, count);
(gdb) n
Breakpoint 2, vector_split (string=0x7f7fff2f0475 "3,10,127.0.0.1,119", separator=44 ',', vector=0x73bc3a1c5020) at vector.c:267
267 for (start = string, p = string, i = 0; *p != '\0'; p++)
(gdb) print *vector
$5 = {count = 0, allocated = 4, strings = 0x3a1c5040}
Now strings
is clearly thrashed. You can set a breakpoint on vector_resize
and single-step, checking the value of vector->strings
as you go along, but, we know what's going on here by now...
(gdb) quit
A debugging session is active.
Inferior 1 [process 5088] will be killed.
Quit anyway? (y or n) y
$