<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/60588>60588</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[clang] Function with empty loop has no return, has a duplicate address
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
SvizelPritula
</td>
</tr>
</table>
<pre>
Consider the following code sample:
```c
#include <stdlib.h>
#include <stdio.h>
void a()
{
for (unsigned int i = 0; i >= 0; i++)
;
}
void b()
{
puts("b");
}
```
Function `a` contains an infinite loop without a constant controlling expression and without side-effects. The C11 and C17 standards allow implementations to assume that such a loop terminates. This code also happens to be valid C++ code. In C++11 and later, side-effect free infinite loops may also be assumed to terminate, as any thread can be assumed to eventually terminate or perform some kind of side-effect. The `b` function obviously has no strange or undefined behaviour.
When the function `a` is compiled with either `clang` or `clang++` with at least `-O1` for x86-64, the result will be an instructionless function:
```asm
a: # @a
b: # @b
lea rdi, [rip + .L.str]
jmp puts@PLT # TAILCALL
.L.str:
.asciz "b"
```
This means calling `a` will have the same result as calling `b`. It's unclear whether this is allowed by either standard, as both just say the loop "may be assumed to terminate", not specifically that an infinite loop has undefined behaviour. One could say this only allows a compiler to remove a loop it cannot prove to terminate, not to assume a loop it can prove not to terminate will never be called.
Either way, this has another effect: `a` and `b` now have the same address.
We can append a small `main` function to the above snippet:
```c
typedef void (*fptr)();
fptr identity(fptr f)
{
volatile fptr f2 = f;
return f2;
}
int main()
{
printf("%d %d\n", a == b, identity(a) == identity(b));
}
```
The `identity` function just returns its argument in a way `clang` cannot inline. When we compile (with `-O1` or higher) and run the full program, we get `0 1`, which means `a` and `b` are both identical and different. This seems to be a violation of the spec, since:
a) different functions shouldn't be equal, and
b) two different values shouldn't suddenly become equal after passing them through an identity function.
This was tried with `clang` and `clang++` version 14.0.0-1ubuntu1, and it can be observed to happen in version 15.0.0 through the [Compiler Explorer](https://godbolt.org/).
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJyMV81u4zgSfhr6UoggU7ZjH3xInA7QQIAZYBvYc0ksWeylSC1J2e15-kWRkmMnnZ0JAici6__n-2QMQR8t0V6sn8X6ZYFj7Jzf_-uk_yLzp9dxNLionbrsD84GrchD7AhaZ4w7a3uEximCgP1gSFRPonwR5fy5KfNvMz3LStvGjIpAVIcQldF10Ynq2xfX2t3eps-T0wpQyK2Qu-n88Tn_AwDQOg9CbkebclKgbQQNonqBUlTP6d9v709CPqffyRKI6nm2-fLJaf2l02GMIV3KWkjJMp_tzJW4Nfs62iZqZ0FsShSbEhpnI2obAC1o22qrI4FxboCzjp0bIyDLhIg2JmHvjOEW0K_BUwhsC626SnO3HqhtqYmhgB8dwWG5TBKH5SOwGYVeBUBuJWjuYE82IgcVIDrAEMaeIHYYIYxNB5jDieR7bTFSMqtDngE0wUGHw0BZuyY4odEKDrnQSaqA73Y-mIIxGMkLebiNF1pPdF-EAD1espOaptAU-7lGwzaQq3eB2HlCBQ3aD8J0IhtHNObyrgfOw0C-db6H4HqC_2irwLW3AeX6iU1Zc6fauXWuPmk3BnOBDgNYByF6tMdkcrSKWs1jWFOHLOeL2_7_uyObd-njIKSK9oM2lJsJpGNHnu8bg_bIMu7mMc_xpszCGMEQhsj3D38sU7zOw6_t5mGz4hqxT09hNBHO2phUIZ64EP2YAjEUwjWqr5YaQ59PUFRPIGQFYlViPqr56B_9THr1-zrxjyEErzQHK9bPXg_A81O8FSF6sX65F_7ZD3Ddw1X559uP_-fsx9P3t8PT21u2MZmcU5wFCwyN_osV8k5_vcRp_HtCG6DBvI1zF1NtOzxRKnjA_lp1vBPmiSrgexTyMcBoG0Po4dxRanlk-3raUR6lyzwM8_5OU1-72MHPMUQIeEke06oKKXltvtwYyerWRQgDNbrVTV4N3vhPKMQj_ruhhj8sQeNGoybfOoCz5pKDDgm10jR7du6pdyeaoURHXlIOYPB8_HGf-eYdie6UJo1J4n2bU90tnchz2pwQqbvF-5YLeMZL3gYdUmpoXTrPC5-Geuoko9S8-tadPzQVlWL0vd9tShEmMFSAEHo0hm30qO0dgnDoHQHWnEuwehgo_g2PxstAilpIvJSY56kdomfmyRx15Z_0yXegFdmo40XIbXpuf89lJ2cwakOQhWTizvZqkEU8xdFbaOVXdMmkm9L8kjC9trHNlCnkmnNYK7E-2Gkckb2y45qfbiJHIXfz3c1xnTL_p7Q74fhV_7YZaX9yggF0DID-ODIngraAPDF3GDxNrrZGWyogAfqZ5mnn1iRAfsdh56HTx47pbpemyo8zBRjD83z02HPSZ4IjJQQvgTXTWaebbsKa300mesookFNr0KRrpduWPNk4cXUg6md-Rjjp1HGmsjaP9EBNJmPbfHyhS_W_2ruWLUDoePutkI-RzdJ_RzSpk1bNhCB3EM_uRvuEZqR71TAqRQwcNTXMw8kOYBvJw8AvqvbIMfZM7248dgmipj5eoyk-wfMZA0SvZzK97eBUvw80eiKfXqaWq6IsyoflWI82jsspoxl-agJXB_KnDKr5zYcH5aq-ZvVrsFxdsX4-zFj47ddgnKdEaHLbxTgErrd8FfL16FTtTCycP6aDXbFQ-0rtqh0uaL_cPK4fd5WU5aLbS9mstiuqlltVbZqmqra7Fmtaqlo1aoWbhd7LUlalLB-X23Kz3hSk2l21WrdKrpabci3FqqQetSmMOfXscqFDGGm_Kdfb7cJgTSakrwdSWjpDuuRVXb8s_J51HurxyNRrdIjh3UrU0aTvFbm86xe4vvLmt5p-iJd3arFuWj2ucwJkUONgdMOgPoHsYvRm_6FUOnZjXTSuF_KVfU9_HgbvfjKQy9cUcRDyNWX0vwAAAP__KJAE2Q">