3

In my C program I am trying to allocate some memory with malloc() function, like this:

char *buf = (char *)malloc(size);

but the problem is that malloc() always returns non-NULL pointer. Even if I try to allocate enormous (size is 1E+13) amount of memory, it returns valid buf pointer. Of course after that program crashes.

But how can I detect that requested amount of memory is too large and will be not available, if returned buf value is not NULL?

Edit:

In comments I see that my question may be not clear. So this is more expanded sample:

unsigned long size = very_large_calculated_value;
char *buf = (char *)malloc(size);
if (buf == NULL) i_know_it_fails;
...

but Xcode runs this code and buf is never NULL whatever requested size is. So, very soon program crashes. How can I detect memory allocation failure if buf is not NULL, but obviously unuseable?

Edit:

To those who marked the question as a duplicate: There is no answer for the question "How can I detect memory allocation failure?", because the solution like "change some settings in your OS" is not an answer - I am asking for C code to detect memory allocation error, or something like "it is not possible to make programmatically".

dbush
  • 205,898
  • 23
  • 218
  • 273
Kibernetik
  • 2,947
  • 28
  • 35
  • http://en.cppreference.com/w/c/memory/malloc – juanchopanza Aug 11 '15 at 16:58
  • 3
    What do you mean when you say " it returns valid buf pointer. Of course after that program crashes". Do you have code that exhibits this behavior? – dbush Aug 11 '15 at 16:59
  • 2
    Standard warning: Do not cast `void *` as returned by `malloc` & friends. C is **not** C++! – too honest for this site Aug 11 '15 at 17:01
  • [MCVE](http://stackoverflow.com/help/mcve) please! – Paul R Aug 11 '15 at 17:04
  • Please clarify if you really mean "will fail" (future) or "has failed" (past). – too honest for this site Aug 11 '15 at 17:06
  • @Olaf how else would you convert the result of a `malloc` to an `int*`? As far as I know, `int*` is implicitly convertible to `void*`, but not the other way around. – Jashaszun Aug 11 '15 at 17:07
  • 3
    @Jashaszun a `void *` can be assigned to or from any non-function pointer safely without a cast. – dbush Aug 11 '15 at 17:12
  • 2
    @Jashaszun: Please read the [standard](http://port70.net/~nsz/c/c11/n1570.html#6.3.2.3p1). That's why I added the last sentence. – too honest for this site Aug 11 '15 at 17:16
  • @Olaf Thanks for the link. I'm just wondering, how do you find stuff like that? I wouldn't have been able to find it from the table of contents. – Jashaszun Aug 11 '15 at 17:17
  • 2
    @Jashaszun: Just search for "C11 standard" or have a look at Wikipedia; they link such. And once found, I have bookmarked the site. After some months at SO I think I now know pretty well where to find the relevant sections. The standard is actually not that hard to understand. – too honest for this site Aug 11 '15 at 17:19
  • @Olaf: that malloc() *has failed* to allocate memory. It reports that buf != NULL, but in fact it cannot allocate requested amount. – Kibernetik Aug 11 '15 at 17:22
  • 1
    @Kibernetik: No! Per definition, `malloc` **does** return a _null pointer_ on failure. So if it does return anything else, the reverse applies: `malloc` (i.e. allocation) did not fail! Read about optimistic allocation or overcommit as answered by @bluemoon. I agree, however, that is a problematic situation, but quite similar to the modern finance system. – too honest for this site Aug 11 '15 at 17:28
  • 1
    @Jashaszun: Look at the "conversions" section (6.3). Very useful! – too honest for this site Aug 11 '15 at 17:30

4 Answers4

3

There's no way to predict the memory allocation failure. The only way is to check the return value of malloc() for null pointer.

It seems your question is really about memory overcommit done by the kernel. Using which the kernel never returns null pointer. The default is to always overcommit. So to disable it on Linux-like systems do:

echo 2 > /proc/sys/vm/overcommit_memory

Or you could do the same using sysctl:

sysctl vm.overcommit_memory=2

Both are equivalent.

The value 2 is to ensure that malloc returns null pointer in case the requested memory exceeds the available physical memory (plus swap space).

P.P
  • 117,907
  • 20
  • 175
  • 238
  • if'n you are using a kernel that cares about /proc and accepts those options, etc, certainly isn't bound by the scope of the tags, (C, XCode)... – Grady Player Aug 11 '15 at 17:27
  • @GradyPlayer Even the dont-like-proc-BSDs allow certain changes through sysctl. Tags are meant to be a guideline for relevance. If what's being asked is clear whether the actual tags are correct or not, then I don't see any issue in answering it. If OP clarifies that this is _not_ the case then I am happy to delete my answer. – P.P Aug 11 '15 at 17:34
  • your point about overcommit is totally correct, and it frames the question... I am just pointing out that your remedy is very specific to one type of system – Grady Player Aug 11 '15 at 17:40
  • @Blue Moon: so, what code should be written in C program to disable memory overcommit? – Kibernetik Aug 11 '15 at 17:41
  • @Kibernetik You could open `/proc/sys/vm/overcommit_memory` and write into it: `int fd=open("/proc/sys/vm/overcommit_memory", O_WRONLY|O_CREAT|O_TRUNC, 0666); write(fd, "2\n", 2)` – P.P Aug 11 '15 at 18:06
  • 1
    @GradyPlayer The problem is specific to systems that *do* overcommit. So the solution can't be portable. The only C standard way is to check for return value of malloc() -- which is of no help here. – P.P Aug 11 '15 at 18:11
  • @Kibernetik You can change it through sysctl if it supports (not sure if it does). Other option is to use `calloc()` will force zero'ing the memory (or memset'ing the memory). – P.P Aug 11 '15 at 18:29
  • @Blue Moon calloc() behaves exactly as malloc() in this case - it also always returns not NULL – Kibernetik Aug 11 '15 at 18:34
  • @Kibernetik If sysctl doesn't support and calloc does the same then tough! There may be other configurable options. See this post which suggests completely disabling vmm on macOS: http://hints.macworld.com/article.php?story=201106020948369 – P.P Aug 11 '15 at 18:41
  • @Blue Moon Thank you very much for your input! You helped me a lot. OS-hacking solutions are not suitable. I have found a programmatic solution for this problem, but someone marked my question as duplicate, and now I cannot post my answer here. Anyway, my problem is solved. Thank you once again! – Kibernetik Aug 11 '15 at 18:49
  • @Kibernetik If it's incorrectly closed as duplicate then I can re-open it. Nothing is set in stone. You should be able to post an answer and accept it yourself as long as it solves the problem. – P.P Aug 11 '15 at 18:52
  • @Blue Moon if it is possible, I can post a solution – Kibernetik Aug 11 '15 at 18:55
  • @Kibernetik I re-opened the question. You can post an answer now. But please make sure your answer is reasonably complete (i.e. useful to others) and correct :) – P.P Aug 11 '15 at 18:55
2

malloc() always returns non-NULL pointer

That's not quite true.

In case malloc() fails, it will return NULL. You need to check the return value of malloc() (the pointer) against NULL to ensure malloc() is success.

To quote the man page, (emphasis mine)

The malloc() and calloc() functions return a pointer to the allocated memory that is suitably aligned for any kind of variable. On error, these functions return NULL. [...]


Note; [Following the comments]

If you're talking about the optimistic allocation techniques used by malloc() to return the pointer, in that case, there is no standard way to check or predict the future failure, in case malloc() has returned non-NULL pointer. If you want to be sure about the availability of memory, you can consider using calloc() instead.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • 5
    He's looking for a way to predict the failure because on some systems, `malloc()` will succeed whether there's enough free memory or not (such systems may not actually grab the memory until you *access* it, which is when you'll get an error if there isn't enough). – Dmitri Aug 11 '15 at 17:02
  • The point that on some systems `malloc` might return something virtual, and then fail on access. Let me dig up for the related discussion... – Eugene Sh. Aug 11 '15 at 17:03
  • @Dmitri I don't think that's the case _here_, please notice the statement "malloc() always returns non-NULL pointer" – Sourav Ghosh Aug 11 '15 at 17:04
  • You should cite the [standard](http://port70.net/~nsz/c/c11/n1570.html), not a Linux manpage, unless necessary. Note the "xcode" tag. – too honest for this site Aug 11 '15 at 17:04
  • @Olaf I understand that sir, but this is a _trivial_ case, and most of the time, man page should be sufficient. – Sourav Ghosh Aug 11 '15 at 17:06
  • Here it is http://stackoverflow.com/questions/29610445/how-come-this-c-program-does-not-crash/29610502#comment47367263_29610502 – Eugene Sh. Aug 11 '15 at 17:13
  • Well, There is actually a difference how to behave with a [`0` size](http://port70.net/~nsz/c/c11/n1570.html#7.22.3p1). And OS-X might behave differently from Linux/glibc. In fact, the Linux man-page might specifiy the _implementation defined_ behaviour the standard leaves open. – too honest for this site Aug 11 '15 at 17:13
  • @SouravGhosh It was too much effort to find it, so I'll leave it here :) – Eugene Sh. Aug 11 '15 at 17:15
  • @Olaf sorry sir, but here we're talking about malloc failure, aren't we? malloc(0) is a diferent case altogether. – Sourav Ghosh Aug 11 '15 at 17:16
  • Read the linked paragraph. What to return for `0` size is left to the implementation. Linux/glibc and OS-X are actually two different, so might behave different here. However, as OP has clarified now, he seems to be after optimistic allocation, not fail-on-call. So let's settle this (for now ;-). – too honest for this site Aug 11 '15 at 17:22
  • @SouravGhosh I'm not sure `calloc()` is any safer... it could link the whole block to a single page of 0's and use copy on write. – Dmitri Aug 11 '15 at 17:27
  • @Sourav Ghosh: calloc() behaves exactly the same - it is optimistic about memory allocation, but actually fails to allocate. – Kibernetik Aug 11 '15 at 17:30
  • @Dmitri sir, as discussed [here](http://stackoverflow.com/a/1585987/2173917), I feel, if success, `calloc()` can be considered _safer_. What do you say? – Sourav Ghosh Aug 11 '15 at 18:22
  • @SouravGhosh Note the top comment under the answer you just linked. Despite the answer being upvoted alot, the assumption it's based on isn't necessarily true. – Dmitri Aug 11 '15 at 18:28
  • @Dmitri Yes, I have read that, but I thought that is from efficiency perspective. From allocation perspective, it can be considered safer, or am I missing anything? (Sorry if I'm being annoying) – Sourav Ghosh Aug 11 '15 at 18:33
  • @SouravGhosh The zero pages that `calloc()` gets from the OS may all be the same physical page initially (then the same virtual page can be remapped to a new copy of the zeroed page on write). If so, and if `calloc()` relies on them being already zeroed and doesn't write to them, you can have the same optimistic allocation issue as with `malloc()`. – Dmitri Aug 11 '15 at 18:48
2

Expanding on BlueMoon's answer, here's what the man page for malloc has to say about overcomitting:

BUGS

By default, Linux follows an optimistic memory allocation strategy. This means that when malloc() returns non-NULL there is no guarantee that the memory really is available. This is a really bad bug. In case it turns out that the system is out of memory, one or more processes will be killed by the infamous OOM killer. In case Linux is employed under circumstances where it would be less desirable to suddenly lose some randomly picked processes, and moreover the kernel version is suf- ficiently recent, one can switch off this overcommitting behavior using a command like # echo 2 > /proc/sys/vm/overcommit_memory
See also the kernel Documentation directory, files vm/overcommit-accounting and sysctl/vm.txt.

dbush
  • 205,898
  • 23
  • 218
  • 273
1

After numerous tests it seems to be an Xcode debugging issue. The result is dependent on whether the breakpoints are used and on their position in code.

In general, if to remove all breakpoints then code runs as it should, without any problems. But if some breakpoints are inserted (influence of their position in code is unclear to me) then Xcode becomes unstable and crashes after memory allocation functions.

Kibernetik
  • 2,947
  • 28
  • 35
  • "I have found a programmatic solution for this problem" -- This does not seem at all like the exciting programmatic solution that this question was reopened for. Disappointing.... – ad absurdum Sep 20 '17 at 11:17