1

Normally, one tests for the result of malloc to not be NULL to known whether memory allocation succeeded. With a series of malloc calls, this becomes a lengthy or tedious set of comparisons.

Instead, could one set errno = 0 at the top of the series of malloc calls, and then test for errno == ENOMEM at the end?
This assumes if any allocation fails, the program or function can't proceed and has to return/bail out. It also assumes the malloc calls are sequential and continuous, and that, as per the manual, malloc can only set errno to ENOMEM.

An example would be something like the following code:

#include <stdlib.h>
#include <errno.h>
#include <stdio.h>

#define N (1 << 20)

int main()
{
        double *a = NULL;
        double *b = NULL;
        double *c = NULL;

        errno = 0;
        a = malloc(N * sizeof *a);
        b = malloc(N * sizeof *b);
        c = malloc(N * sizeof *c);
        if (errno == ENOMEM) {
                perror(NULL);
                free(a);
                free(b);
                free(c);
                return EXIT_FAILURE;
        }
        errno = 0;

        /* Do interesting stuff */

        free(a);
        free(b);
        free(c);
        return EXIT_SUCCESS;
}

(The example uses main(), but it could also be another function that simply can't be run, but the program might proceed otherwise, and no actual exit from the program happens, and the free() calls are necessary.)

I don't see any reason why this can't be done safely, but it's not an idiom I have come across, hence the question.

9769953
  • 10,344
  • 3
  • 26
  • 37
  • My best guess to an answer is either that this is indeed safe, or that malloc setting errno to ENOMEM is less standard across malloc implementations than malloc returning NULL. – 9769953 Mar 28 '19 at 10:07
  • 1
    If malloc for a succeded but failed for b and c, wouldn't free(b) and free(c) give error? I know it does not give error for c++ but I am not sure about C compilers. – Nevus Mar 28 '19 at 10:10
  • Also interesting: https://stackoverflow.com/questions/6325940/how-detect-malloc-failure – Jabberwocky Mar 28 '19 at 10:10
  • 1
    If your `malloc` implementation sets `errno` upon error (which may not be the case, it's platform dependent), then your code is safe. – Jabberwocky Mar 28 '19 at 10:11
  • 2
    @suvenpandey If `malloc` fails, it will also return `NULL`. Calling `free`with a `NULL` parameter is safe in C. – Gerhardh Mar 28 '19 at 10:16
  • @Jabberwocky Platform dependent, or implementation dependent? – 9769953 Mar 28 '19 at 10:21
  • @9769953 sorry, rather implementation dependent – Jabberwocky Mar 28 '19 at 10:27
  • @Jabberwocky Thanks; that reflects my suspicion in my first comment at the top. – 9769953 Mar 28 '19 at 10:29
  • if (for instance) the first call to `malloc()` fails then the following calls are successful, then `errno` will be set to `success`. In other words, the first failure indication is overlayed by the following calls to c library functions. (in this case the following calls to `malloc()`. Remember, there is only one `errno` variable and every C library function updates it. – user3629249 Mar 28 '19 at 16:43
  • regarding: `errno = 0;` User code 'never' needs to modify the variable `errno` – user3629249 Mar 28 '19 at 16:45
  • @user3629249 The above example is perhaps a bad example for errno, but shouldn't a user, after calling a (library) function and possibly handling its error, set `errno` to `0` again, then calling a next (library) function to test for any errors in there? – 9769953 Mar 28 '19 at 17:27
  • the C library functions do not care about the prior value of `errno`, so there is no need to have the user code modify it – user3629249 Mar 28 '19 at 18:11
  • @user3629249 Good point. But what about two consecutive calls to e.g. `fopen()`? For example, if the program can't find one particular file (`errno` will be set), it will try a backup file, and will need to check if that second `fopen()` doesn't fall. Of course, the file pointer would be `NULL`, but `errno` could have more information why it failed: file not found, no read permission etc. – 9769953 Mar 28 '19 at 21:00
  • 1
    @user3629249 I can answer that last question myself, I realise: check for `fp == NULL`, then check the value of `errno` to see what the actual error is. – 9769953 Mar 28 '19 at 21:05
  • rather than checking the value of `errno`, just call `perror( "your error message");` as that will output to `stderr`, both your error message and text reason the system thinks the error occurred – user3629249 Mar 28 '19 at 22:15

2 Answers2

2

No, you can not safely do this in a portable manner.

Per 7.5 Errors <errno.h>, paragraph 3 of the C standard:

The value of errno in the initial thread is zero at program startup (the initial value of errno in other threads is an indeterminate value), but is never set to zero by any library function. The value of errno may be set to nonzero by a library function call whether or not there is an error, provided the use of errno is not documented in the description of the function in this International Standard.

Since malloc() is not documented to set errno by the C standard, it's free to munge errno on success.

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
1

Instead, could one set errno = 0 at the top of the series of malloc calls, and then test for errno == ENOMEM at the end?

Yes you could as long as your implementation of malloc is documented to set errno to ENOMEM. The specification in the C11 standard (§ 7.22.3.4) only mentions that the pointer returned will be NULL, not that errno will be set, so your code is technically not portable.

The default implementation of malloc in macOS, Windows and in Linux does set errno so that's most of the computers in the World covered. However, if true portability is required, at the end just write

if (a == NULL || b == NULL || c == NULL)
{
    // Handle the failure
}

Addendum: There's no need to reset errno back to zero after the mallocs.

JeremyP
  • 84,577
  • 15
  • 123
  • 161
  • Just for completeness, is there a link to the relevant section in the standard, or is that not possible? – 9769953 Mar 28 '19 at 10:31
  • @9769953 [here](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf). – Alexey Frunze Mar 28 '19 at 10:34
  • @9769953 I've added the section number. There's no handy HTML version of the standard available on the Internet without handing over a wodge of cash. I have a PDF of a late draft which I got [here](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1548.pdf) and is, to all intents and purposes identical. – JeremyP Mar 28 '19 at 10:36
  • @AlexeyFrunze and JeremyP: Thanks for the addition/link! – 9769953 Mar 28 '19 at 10:38