Skip to content

builtin causing strange errno corruption for function named reallocarray #149108

@guijan

Description

@guijan

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    llvm:analysisIncludes value tracking, cost tables and constant foldingllvm:transformsquestionA question, not bug report. Check out https://llvm.org/docs/GettingInvolved.html instead!

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions