Live data from Hacker News

Malloc Never Fails (2012)

scvalex.net

61–70 of 165 posts

Re: Malloc Never Fails (2012)

#61
post #7

The title here is just blatantly false; there are certainly some scenarios in which it won't fail, but many in which it will. The author is aware of this since he fixes the claim toward the end: > To clarify, the surprising behaviour malloc has does not mean we should ignore its return value. We just need to be careful because malloc returning successfully does not always mean that we can use the requested memory. It…

n.b. turning over-commit off comes with its own set of problems, such as causing programs to fail long before all memory has really been exhausted.

For example, fork() will have to ensure that there is enough memory for a complete copy of the running process. If you have a large process, e.g. using 4GB of a 8GB machine, then fork() won't be able to run, even if you just want to fork and run a tiny program.

With over-commit turned on, the fork() would work (because of copy-on-write) and the program could then happily exec() the new program.

The work-around is to allocate huge amounts of swap space so that the OS can be confident that it can reserve all the potentially required memory from fork(), even if it never normally has to use all that memory.

Re: Malloc Never Fails (2012)

#62
post #39

Translation: This is a euphemism for saying Linux blatantly violates the language specification with no remorse. (Yes, I realize Linux is the kernel, etc.)

> [...] Linux blatantly violates the language specification [...] We can't expect a kernel to be aware of all language specifications. Yes, I know that in this case C is both the program's and the Kernel's language in this example but even then. Languages go through iterations (versions) and a Kernel can't be required to obey all languages which might run under it.

If you're suggesting Linux did not intend its malloc implement the corresponding function in the C standard then you're just lying to yourself. That's exactly why it's there and that's exactly what it's used for.

Re: Malloc Never Fails (2012)

#63
post #50

Translation: This is a euphemism for saying Linux blatantly violates the language specification with no remorse. (Yes, I realize Linux is the kernel, etc.)

Linux is a kernel, not a C runtime so that's not really relevant. You say you realize that but then what are you arguing for exactly? Arguably you could complain that the glibc (or whatever libc you're using) is not working around that by, for instance, scrubbing the pages in malloc() to force the kernel to allocate memory. But even then I'm not convinced that anything here is non-standard, at worse maybe we're in a…

> If you have some specific part of the C standard in mind please do tell

See here: https://news.ycombinator.com/item?id=20145604

Also note the POSIX standard:

Upon successful completion with size not equal to 0, malloc() shall return a pointer to the allocated space. If size is 0, either a null pointer or a unique pointer that can be successfully passed to free() shall be returned. Otherwise, it shall return a null pointer and set errno to indicate the error.

In neither case is there any provision for returning a non-null pointer to anything other than an allocated block of memory of at least the given size.

Re: Malloc Never Fails (2012)

#64

Earlier quoted context omitted.

I had a look, and the C standard doesn't actually say anything about indicating failure. Here is all it says about malloc: > The malloc function allocates space for an object whose size is specified by size and whose value is indeterminate. > The malloc function returns either a null pointer or a pointer to the allocated space. I think it's certainly debatable whether overcommitting while lazily allocating counts as…

> I had a look, and the C standard doesn't actually say anything about indicating failure. > The malloc function returns either a null pointer or a pointer to the allocated space. Uhm, either malloc returns a pointer to the allocated space, or it returns null. I don't see what's so complicated about this. There's no provision for "return a non-null pointer to unallocated space".

The malloc() function requests memory from the kernel using mmap(). If mmap() returns successfully, it means that the kernel is saying that the memory is allocated. So from malloc()'s perspective the memory allocation has been successful and it must return a non-null pointer to the caller. The standard does not require malloc() to distrust what the kernel said and try to actually write to that memory to double-check if there is any physical memory mapped to it or not. The standard also does not impose anything on the kernel. I see no section of the standard being violated here.

Section 7.22.3.1:

The order and contiguity of storage allocated by successive calls to the aligned_alloc, calloc, malloc, and realloc functions is unspecified. The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement and then used to access such an object or an array of such objects in the space allocated (until the space is explicitly deallocated). The lifetime of an allocated object extends from the allocation until the deallocation. Each such allocation shall yield a pointer to an object disjoint from any other object. The pointer returned points to the start (lowest byte address) of the allocated space. If the space cannot be allocated, a null pointer is returned. If the size of the space requested is zero, the behavior is implementation-defined: either a null pointer is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object.

Section 7.22.3.4:

The malloc function allocates space for an object whose size is specified by size and whose value is indeterminate.

Re: Malloc Never Fails (2012)

#65

Earlier quoted context omitted.

> I had a look, and the C standard doesn't actually say anything about indicating failure. > The malloc function returns either a null pointer or a pointer to the allocated space. Uhm, either malloc returns a pointer to the allocated space, or it returns null. I don't see what's so complicated about this. There's no provision for "return a non-null pointer to unallocated space".

The malloc() function requests memory from the kernel using mmap(). If mmap() returns successfully, it means that the kernel is saying that the memory is allocated. So from malloc()'s perspective the memory allocation has been successful and it must return a non-null pointer to the caller. The standard does not require malloc() to distrust what the kernel said and try to actually write to that memory to double-check…

The standard literally could not care less if there's a kernel underneath. It doesn't care how malloc is implemented or what the kernel, if any, looks like "from its perspective". The perspective that has relevance is that of the caller of malloc. From your own quotes:

> The pointer returned if the allocation succeeds is suitably aligned so that [...]

> If the space cannot be allocated, a null pointer is returned.

If you use mmap and "from your perspective" that's considered success then it's your perspective that's faulty. The standard is literally telling you right here^ there are 2 possibilities: either you allocate the space and return a pointer to the space, or you don't and you return null. There is no third option of "space cannot be allocated but you return non-null anyway". That's quite literally the end of the story.

Re: Malloc Never Fails (2012)

#66
post #51
post #26

Earlier quoted context omitted.

An exception-safe C++ program can do the same through a std::bad_alloc exception. If the out-of-memory was caused by something simple like accidentally loading 2G of data because of some odd data in an network request or a user selected file, and it rolls back to the start of the UI action or the incoming network request, the application may still work fine. (I usually connected other out-of-resource conditions such…

> If the out-of-memory was caused by something simple like accidentally loading 2G of data because of some odd data in an network request or a user selected file, and it rolls back to the start of the UI action or the incoming network request, the application may still work fine. If you have a system that handles independent requests, it might be more robust to model each request as its own process, and then simply a…

It's certainly more robust, but a lot of overhead for what should be a very uncommon situation.

In eg an application server, requests themselves may be independent, but still share a lot of cached data - and as long as locking overhead doesn't overwhelm you, a single process is still the fastest way to share data between (worker) threads.

Re: Malloc Never Fails (2012)

#67

How does one guarantee that allocated memory is real? Can you easily wrap malloc to zero/poke the memory in a way that catches all exceptions and guarantees yay or nay ?

Jens Gustedt suggested the following: memset(malloc(size), 0, 1) The program will crash if malloc returns NULL or the memory is not writable.

And then memory deduplication comes along, finds out a huge number of identical pages (all zero) and decides to deduplicate them. So if you want your memory to stay real, I suppose you'd better fill it with random data or something.

Re: Malloc Never Fails (2012)

#68
This assumption lead to Rust's standard library not having a way to catch allocation failures (which is only now being rectified, and only partially).

It's very Linux-centric and presumes a certain config+usage pattern. Not true on Windows. Not quite true on macOS. Not true in WASM. Definitely not true on embedded platforms.

Re: Malloc Never Fails (2012)

#69
post #54

Earlier quoted context omitted.

> what would you do if you run out of memory while making the fourth button in a toolbar? Rollback what I’d created so far, evict caches, ask malloc to trim, try again, if that failed roll back again and ask the user to reduce the volume of application data open by closing views or documents or whatever before they try again. But yeah it’s a lot of engineering.

> ask the user You just failed to create a toolbar button, how are you going to ask a user do something if you already failed to create a tiny UI element?

I guess you pre-allocate these UI elements when you start your application.

Re: Malloc Never Fails (2012)

#70
post #50

Earlier quoted context omitted.

Linux is a kernel, not a C runtime so that's not really relevant. You say you realize that but then what are you arguing for exactly? Arguably you could complain that the glibc (or whatever libc you're using) is not working around that by, for instance, scrubbing the pages in malloc() to force the kernel to allocate memory. But even then I'm not convinced that anything here is non-standard, at worse maybe we're in a…

> If you have some specific part of the C standard in mind please do tell See here: https://news.ycombinator.com/item?id=20145604 Also note the POSIX standard: Upon successful completion with size not equal to 0, malloc() shall return a pointer to the allocated space. If size is 0, either a null pointer or a unique pointer that can be successfully passed to free() shall be returned. Otherwise, it shall return a null…

Thank you for your reply but I still don't buy it. As far as the program is concerned it is returned a memory block, what this "memory" is effectively behind the scenes is none of the standard's business. As long as the implementation manages to maintain the illusion it's perfectly fine AFAIK. The problem is when this breaks down and the kernel realizes that it can no longer maintain the masquerade. If at this point it did something stupid like map this block nowhere or remap something that's already been allocated and let the program continue like this, then yes that would be a clear violation of the contract. But it does no such thing, it kills the program instead. If there's no program then there's no problem. At no point did a single C instruction get executed in an environment that did not maintain a coherent memory model. >In neither case is there any provision for returning a non-null pointer to anything other than an allocated block of memory of at least the given size. A pointer to virtual memory is a pointer to memory. The rest is an implementation detail. If, when dereferenced, the kernel issues an order to Amazon for more RAM and waits for it to be installed to resume the execution, that's none of the C standard's business.
Post reply on HN