-
Notifications
You must be signed in to change notification settings - Fork 14.6k
Description
If I have one program composed of 2 C source files, reallocarray_test.c and reallocarray.c, with the following contents:
reallocarray_test.c:
#include <errno.h>
#include <stdio.h>
void *reallocarray(void *optr, size_t nmemb, size_t size);
int
main(void)
{
errno = 0;
reallocarray(0, 0, 0);
printf("1st errno val after return: %d\n", errno);
printf("2nd errno val after return: %d\n", errno);
return 0;
}
reallocarray.c:
#include <errno.h>
#include <stdio.h>
void *
reallocarray(void *optr, size_t nmemb, size_t size)
{
errno = 1;
printf(" errno val before return: %d\n", errno);
return NULL;
}
And if I compile and run it with builtins off and then builtins on, the program's output is different:
$ clang -O2 -fno-builtin -o builtin_off reallocarray_test.c reallocarray.c
$ ./builtin_off
errno val before return: 1
1st errno val after return: 1
2nd errno val after return: 1
$ clang -O2 -o builtin_on reallocarray_test.c reallocarray.c
$ ./builtin_on
errno val before return: 1
1st errno val after return: 0
2nd errno val after return: 1
Here's a diff:
--- /tmp/builtin_off.txt 2025-07-16 14:18:18.140908085 +0000
+++ /tmp/builtin_on.txt 2025-07-16 14:18:22.365877065 +0000
@@ -1,3 +1,3 @@
errno val before return: 1
-1st errno val after return: 1
+1st errno val after return: 0
2nd errno val after return: 1
Strangely, when builtins are enabled, the first read of errno is 0, while the 2nd read is 1, even though at the C level there is no write to errno between these 2 reads. The compiled program isn't actually calling the builtin reallocarray (nor should it), as evidenced by looking at the program's output and disassembling the program.
I can confirm this behavior on the following versions of clang:
clang version 22.0.0git (https://github.com/llvm/llvm-project.git 968d38d1d7d9de2d5717457876bba2663b36f620)
clang version 20.1.7
This bug is very finnicky. If I join the source files and create a single-file program, it no longer happens. If I comment out errno = 0;
from reallocarray_test.c's main()
, it won't happen either.