C malloc "cannot allocate region" but cannot play GDB?

How can I debug a C application that doesn't crash when connecting using gdb

and run

inside gdb?

On crash when offline, it crashes on crash - even the same debug build!


Some of us are getting this error with a C program written for BSD / Linux and we compile on macOS with OpenSSL.

app(37457,0x7000017c7000) malloc: *** mach_vm_map(size=13835058055282167808) failed (error code=3)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
ERROR: malloc(buf->length + 1) failed!

      

I know not useful.

Re-compiling the application with using -g -rdynamic

gives the same error. So now we know that this is not due to the creation of the release as it continues to fail.

It works when running in a debug session gdb

though !!

$ sudo gdb app
(gdb) b malloc_error_break
Function "malloc_error_break" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (malloc_error_break) pending.
(gdb) run -threads 8
Starting program: ~/code/app/app -threads 8
[New Thread 0x1903 of process 45436]
warning: unhandled dyld version (15)

      

And it works for hours. CTRL-C and run ./app -threads 8

and it will crash after a second or two (several million iterations).

Obviously there is a problem in one of the threads. But these workers for threads are quite large (several hundred lines of code). Nothing stands out.

Note that the threads iterate over loops at about 20 million per second.

  • macOS 10.12.3
  • Homebrew w / GNU gcc and openssl (link to crypto)

Ps not too familiar with C - especially any type of debugging. Be kind and expressive / detailed in your answers. :)

+3


source to share


2 answers


One debugging technique that is sometimes overlooked involves debugging fingerprints in the code, of course it has its drawbacks, but it also has its advantages. What you have to keep in mind though in the face of abnormal termination is to make sure that the printouts do indeed print. This is often enough to print to stderr

(but if that doesn't do the trick, the fflush

stream may need to be explicitly needed ).

Another trick is to stop the program before the error occurs. This requires you to know when the program is about to crash, preferably as close as possible. You do this using a raise:

raise(SIGSTOP);

      

This does not terminate the program, but simply pauses execution. Now you can connect with using gdb

the command gdb <program-name> <pid>

(use ps

to find the pid of the process). Now in gdb

you must tell him to ignore SIGSTOP

:



> handle SIGSTOP ignore

      

Then you can set breakpoints. You can also exit the function raise

with a command finish

(it may take several times to get back to your code).

This method makes the program run normally until the moment you decide to stop it, hopefully the final part, when running under, gdb

will not change enuogh's behavior.

The third option is to use valgrind

. Usually, when you see errors like this, errors related to what valgrind

will be picked up. These are out of range access and uninitialized variables.

+3


source


Many memory managers initialize memory to a known bad value in order to detect such problems (for example, Microsoft CRT will use a range of values ​​(0xCD means uninitialised, 0xDD means already free, etc.).

After each use of malloc, try memset'ing memory at 0xCD (or some other constant value). This will make it easier for you to identify uninitialized memory using the debugger. do not use 0x00 as this is a "normal" value and it will be harder to determine if it is wrong (this will probably "fix" your problem as well).

Something like:



void *memory = malloc(sizeof(my_object));
memset(memory, 0xCD, sizeof(my_object));

      

If you know the size of the blocks, you can do something like this before the free one (it's sometimes trickier if you don't know the size of your objects or keep track of it in some way):

memset(memory, 0xDD, sizeof(my_object));
free(memory);

      

0


source







All Articles