(Yes, I realize Linux is the kernel, etc.)
(Yes, I realize Linux is the kernel, etc.)
But even then I'm not convinced that anything here is non-standard, at worse maybe we're in a bit of a grey area. As long as the kernel maintains its smoke and mirrors whether and how it allocates memory is irrelevant from the point of view of the standard. The C language has a rather simplistic memory model, it doesn't impose a lot on the implementation.
Now the problem occurs when the program attempts to access virtually-allocated memory and the kernel realizes that it can't find any physical memory to map it to. In this situation several things can happen but in general the process will be killed. Is it against the standard for the OS to kill a program for arbitrary reasons? I can't imagine why. It could also freeze the program, waiting for more memory to become available. Again, not against the standard as far as I can tell. Or maybe kill some other program to free memory.
If you have some specific part of the C standard in mind please do tell, I always find these language lawyering arguments interesting, somehow.
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.
We're not, and we never were, debating the situation where dereferencing the non-null pointer returned by malloc succeeds but takes long time due to your Amazon order. We've been talking about the situation where it fails. malloc is not allowed to return a non-null pointer to a memory block that cannot be written to. Linux does it anyway, and in doing so blatantly violates the standard.
char *b = malloc(2);
if (b == NULL) {
return 0;
}
b[0] = 'A';
b[1] = '\0';
printf("%s\n", b);
free(b);
The standard tells me that if the malloc succeeds then the following code, if allowed to run, will display "A" on stdout. The C standard cannot and does not guarantee that a C program can't be interrupted however. For the sake of the argument we could imagine a kernel that instead of killing the program freezes it indefinitely on disk waiting for RAM to be available. It's functionally the same thing. As long as the kernel doesn't let code run with broken invariants it's fine. This is completely outside of the scope of a language standard to define.Or, to try one last time from a different direction, if you consider that the C standard mandates that accessing memory returned successfully by malloc has to be successful and I happen to press ^C when that happens in a program, should the kernel refuse to kill the program? This is obviously absurd, but it's effectively the same thing: the kernel reacts to some external state and decides to terminate the program.
P.S. I don't think indefinite hold is "functionally the same thing" as termination. A caller system(), for one, would need to return in one case, but not the other.
See 5.2.4.1 in http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1548.pdf
However, it's true that not any old instance of this malloc problem demonstrates such a nonconformance. If it happens in a large program that has allocated gobs of memory, then no.
Basically if the system is low on memory that it can no longer support the execution of a small C program with modest memory use, then it becomes nonconforming.
However, the mere property that memory can be doled out by malloc which might later not be used doesn't make it ipso facto nonconforming.
Moreover, a system with any kind of memory management (including management that earnestly reports null for "out of memory") can be come a nonconforming C implementation if it is low on memory.
Both the hardware burning after memory allocation and lack of availability of physical memory after memory allocation are outside the scope of the standard. The standard says nothing about them. A C program can fail in these scenarios without violating the standard.
Maybe it's more accurate to say that Linux is a kernel that assumes many features and semantics of the C runtime. But it certainly seems more deeply intertwined than you're willing to address here.
We may be able to argue that it doesn't. ISO C says in 1. Scope, this:
This International Standard does not specify
[...]
— the size or complexity of a program and its data that will exceed the capacity of any specific data-processing system or the capacity of a particular processor.
It seems that these weasel words have an interpretation that can be bent around overcommitted memory allocation.
For an implementation to be deemed conforming, it just has to be demonstrated to successfully translate and execute one program that tests each of the minimum implementation limits.
See 5.2.4.1 in http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1548.pdf
Only if no such program can be found can we then conclude that the implementation is nonconforming (and if the reason for not finding such a program is this overcommit issue, then we can blame that issue).
Your Linux system is indeed nonconforming if it is so low on memory that, for instance, no C program can allocate a 65535 byte object (that can be actually initialized, and used: a real object). Basically the memory situation has to be so severe that it takes the implementation below the minimum limits, whereby we can clearly demonstrate nonconformance.
> 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 actually allocating.
> 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".
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.
> 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.
Exactly! That's why once virtual memory is allocated, malloc() is allowed to consider the operation successful. The standard does not care at all whether it is virtual memory allocation or physical memory allocation. It is completely unspecified in the standard what sort of memory must be allocated. So no spec in the standard is being violated by returning non-null pointer for virtual memory allocation.
So once again, can you cite the exact section number from the standard that you think is being violated here?
Ironically, it's a memory model that greatly reduces the performance of modern systems, and als impacts its safety.
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.
Linux (the kernel) doesn't have malloc. It's part of the C library, which is a completely separate project. What Linux implements is brk and mmap.