21

I was experimenting with realloc, giving it larger and larger sizes and checking whether the same block was reused or not:

int main ( void )
{
  char * newstr, * prevstr = NULL;
  size_t newsize, prevsize = 0;
  printf ("We play with realloc\n");
  while (1) {
    newsize = prevsize + 1 + prevsize/3; /* add 33% */
    newstr = realloc(prevstr, newsize);
    if (newstr == NULL) {
      printf ("could not alloc newsize=%zu. Sorry\n", newsize);
      break;
    } else {
      printf ("newsize=%zu successfully alloc'ed\n", newsize);
      if (newstr == prevstr) {
        printf ("newstr = prevstr:\tSame block reused\n");
      } else {
        printf ("newstr != prevstr:\tNew block alloc'ed\n");
      }
      prevstr = newstr; prevsize = newsize;
    }
  }
  return (EXIT_SUCCESS);
}

As expected, one eventually reaches a point where the size is too large and realloc cannot answer the request. According to the manual, realloc should return NULL and set errno = ENOMEM when it does not succeed.

This is not what happens when I run the above code on my machine, a Mac with "Darwin Kernel Version 15.0.0". Instead of returning NULL, the code crashes and says

malloc: *** mach_vm_map(size=153288611651584) failed (error code=3)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
could not alloc newsize=153288611651277. Sorry

Is this normal? Something I did not understand when reading the man page?

This is not crucial for my code at the moment but I can imagine situations where I'd like to test whether memory can be alloc'ed without risking a crash. Is there a standard way of testing whether alloc will work without risking such crash?

ADDED after mystery is solved (see answers below): there is no crash, just some system error message from malloc that gets in the way of the expected output. See below on how to avoid that.

phs
  • 541
  • 3
  • 18
  • 1
    Looks like something is not conforming the standard here.. – Eugene Sh. Nov 05 '15 at 15:57
  • 19
    It doesn't seem to really crash. It just outputs some additional diagnostics and returns NULL (the message "could not alloc newsize" is printed by your code when `newstr == NULL`). – Blagovest Buyukliev Nov 05 '15 at 16:00
  • 1
    Good point. Does it really crash? – Eugene Sh. Nov 05 '15 at 16:01
  • Thanks !! I did not notice my own message. Indeed the code does not crash. However the error message is ... annoying. Can it be inhibited? – phs Nov 05 '15 at 16:03
  • 2
    I believe it is going to `stderr`, which you can redirect.. Or even turn it off using some macro. Something like [here](http://stackoverflow.com/questions/6750815/how-to-turn-off-glibc-run-time-protections) – Eugene Sh. Nov 05 '15 at 16:04
  • Have you actually tried setting a breakpoint and debugging it? Your code clearly runs, as @BlagovestBuyukliev commented. – xxbbcc Nov 05 '15 at 16:05
  • I'm pretty sure it don't crash. As said by @Blagovest Buyukliev the last printed string comes from the `if (newstr == NULL)` and just after the `printf` it leaves to loop and go to the final `return`. I suppose that it is a warning from the lib itself (btw compiled on my ubuntu I get the same behavior, just without the warning message). A good way to test: just add a printf before final return, so that you'll know if you reach normal end of code. – hexasoft Nov 05 '15 at 16:05
  • BTW: Nice program demonstrating `realloc()`. It would be more illustrative if a `realloc(prevstr, 0)` also occurred. – chux - Reinstate Monica Nov 05 '15 at 16:11
  • Darwin Version 15.0.0 is on El Capitan. – Spotlight Nov 05 '15 at 21:49
  • Question for language lawyers: Is it legal to compare a valid pointer to a potentially invalid pointer as OP does? – Kevin Nov 05 '15 at 21:55
  • 1
    @Kevin yes. C11 6.2.4p2: "The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the end of its lifetime". An "indeterminate value" is defined in 3.19.2 as possibly being valid. (Basically sounds like C going out of its way to allow `malloc` &c. to re-use locations without needing to GC all references to them.) The comparison itself is therefore permitted (no UB in 6.5.9), but not guaranteed to produce meaningful results. – Alex Celeste Nov 06 '15 at 00:26

2 Answers2

15

As the comments have stated, there is no crash on allocation failure, only an error message.

If the message annoys you, you can turn it off by re-directing malloc's log to /dev/null, like this:

export MallocLogFile=/dev/null

Output before setting the environment variable looks like this:

newstr = prevstr:   Same block reused
a.out(4275,0x7fff7146e000) malloc: *** mach_vm_map(size=153288611651584) failed (error code=3)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
could not alloc newsize=153288611651277. Sorry

After setting the variable the output looks like this:

newstr = prevstr:   Same block reused
could not alloc newsize=153288611651277. Sorry

Note: This is highly Mac-specific. See documentation for description of other environment variables that tweak the details of malloc's operation.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
11

Code did not crash as "could not alloc newsize=153288611651277. Sorry" output occurred - just an additional message was printed. @Blagovest Buyukliev

The additional message is likely sent out on stderr rather than stdout. @Eugene Sh.

Community
  • 1
  • 1
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Thanks to you all. Stupid mystery solved. What is SE policy here? Should I remove the question? Edit it (but to say what?) ? – phs Nov 05 '15 at 16:27
  • 2
    @phs There's no reason to remove a question that people find interesting (as you can see from the vote count). You may want to edit the title to not talk about `malloc` crashing, and talk about suppressing the message instead. – Sergey Kalinichenko Nov 05 '15 at 16:31
  • 3
    @phs Suggest leaving. 1) It is a well stated problem. 2) It demos the problem of error messages (`stderr`) obfuscating normal output `stdout`. 3) I like the `realloc()` demo code as [commented](http://stackoverflow.com/questions/33549070/memory-allocation-fails-but-why-does-it-crash/33549566?noredirect=1#comment54878525_33549070) – chux - Reinstate Monica Nov 05 '15 at 16:31
  • 2
    @phs - "Wrong" questions are often more educational than "right" questions because other people may be running into the same thing. People rarely post to say "Why is this working exactly as I expected it to", so it's useful to see questions like "Why isn't this working correctly", even when it turns out that it *was* working correctly, just not obviously so. – Johnny Nov 06 '15 at 00:06