Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to switch off local array merging in clang?

There is simple code, where clang and gcc behave differently.

int t;
extern void abort (void);

int f(int t, const int *a)
{
 const int b[] = { 1, 2, 3};
 if (!t)
   return f(1, b);
 return b == a;
}

int main(void)
{
 if (f(0, 0))
   abort ();
 return 0;
}

Clang:

> clang -v
clang version 4.0.1 (tags/RELEASE_401/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
> clang test.c
> ./a.out
Aborted

GCC:

> gcc -v
Target: x86_64-suse-linux
Thread model: posix
gcc version 7.2.0 (GCC)
> gcc test.c
> ./a.out
> echo $?
0

Reason is pretty obvious: behavior is implementation defined and clang merges constant local arrays to global one.

But lets say I want consistent behavior. Can I turn some switch on or off in clang to disable this optimization and make it honestly create different local arrays (even constant ones) for different stack frames?

like image 436
Konstantin Vladimirov Avatar asked Sep 03 '25 02:09

Konstantin Vladimirov


2 Answers

The option in clang you're looking for is -fno-merge-all-constants. And you can enable it in gcc with -fmerge-all-constants if you want to achieve the opposite. But the documentation of the option in gcc makes me curious:

Languages like C or C++ require each variable, including multiple instances of the same variable in recursive calls, to have distinct locations, so using this option results in non-conforming behavior.

The only bit that somehow might suggest that clang is allowed to get away with this is (C11, 6.5.2.4):

  1. String literals, and compound literals with const-qualified types, need not designate distinct objects.

The problem here is that your code doesn't have a compound literal.

There is in fact a bug report for clang about this and it appears that the developers are aware that this is non-conforming: https://bugs.llvm.org/show_bug.cgi?id=18538

The interesting comment in there is:

This is the only case I can think of (off the top of my head) where clang deliberately does not conform to the standard by default, and has a flag to make it conform. There are a few other places where we deliberately don't conform because we think the standard is wrong (and generally we try to get the standard fixed in those cases).

like image 85
Art Avatar answered Sep 04 '25 15:09

Art


It does appear that clang is reusing the same array for variable b in both local scopes of f(), but that cannot be justified on the basis of implementation-defined behavior. Implementation-defined behaviors are explicitly called out in the standard, and conforming implementations document their actual behavior for each area of implementation-defined behavior. This is not an area where the standard grants such latitude.

On the contrary, the behavior of the clang-generated program is non-conforming, and Clang is non-conforming for producing such code. The standard specifically says that

For [an object with automatic storage duration] that does not have a variable length array type, its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way. (Entering an enclosed block or calling a function suspends, but does not end, execution of the current block.) If the block is entered recursively, a new instance of the object is created each time.

(C2011, 6.2.4/6; emphasis added)

The objects in question in this case do have automatic storage duration and do not have variable-length array type, so the standard specifies that they be distinct objects. That they are arrays with a const-qualifed element type does not permit clang to reuse the array.

But lets say I want consistent behavior. Can I turn some switch on or off in clang to disable this optimization and make it honestly create different local arrays (even constant ones) for different stack frames?

You can and should reported a bug against Clang, unless this issue has already been reported. The time frame for that bug being fixed is probably longer than you want to wait, but I do not find documentation of any command-line flag that would modulate this behavior.

The other answer suggests that there is in fact an option controlling this behavior. I'm entirely prepared to believe that, as I have previously found Clang's documentation to be incomplete in other ways, but it should not be necessary to explicitly turn off such an option to achieve language conformance.

like image 33
John Bollinger Avatar answered Sep 04 '25 17:09

John Bollinger