<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/62633>62633</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[SimpleLoopUnswitch] hides use-of-uninitialized-value bugs from msan
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
caojoshua
</td>
</tr>
</table>
<pre>
[Reproducer](https://godbolt.org/z/bv6Mo5fY3)
```
#include "stdio.h"
#include "time.h"
void a() { printf("hi\n"); }
void b() { printf("bye\n"); };
bool f() { return time(NULL) > 0; } // always true, but compiler does not know that
class A {
public:
A(unsigned x) : x(x) {}
unsigned x;
};
// Apparently without this template, C++ requires us to init a.
// With the template, it is possible that a is uninitialized.
template <typename t>
class B {
public:
t foo;
B() {} // a, and a.x not initialized in default constructor
B(t foo) : foo(foo) {}
};
void foo(unsigned n, B<unsigned> myB) {
unsigned c;
for (unsigned i = 0; i < n; ++i ) {
// Need a condtional. LoopUnswitch only inserts a freeze if the loop-invariant
// condition is not guaranteed to execute.
if (f()) {
// myB.foo is loop-invariant and gets unswitched
// msan emits an error, since myB.foo is uninit, and branching on unint is UB
if (myB.foo) {
a();
} else {
b();
}
}
}
}
/*
After loop unswitch, looks something like
if (myB.foo) {
for (...) {
if (f())
a();
}
} else {
for (...) {
if (f())
b();
}
}
myB.foo gets 'frozen' after unswitching. msan does not check frozen operations, so no UB is caught.
*/
int main() {
B<unsigned> myB; // myB.foo not initialized
foo(1, myB);
return 0;
}
```
```
archlinux [~/src/llvm-test/unswitch-ub]$ clang++ -fsanitize=memory -O2 -fno-inline -fno-discard-value-names -g0 foo.cpp
archlinux [~/src/llvm-test/unswitch-ub]$ ./a.out
==5305==WARNING: MemorySanitizer: use-of-uninitialized-value
#0 0x555ba28bded6 in foo(unsigned int, B<unsigned int>) (/home/josh/src/llvm-test/unswitch-ub/a.out+0xa7ed6)
#1 0x555ba28bdf1c in main (/home/josh/src/llvm-test/unswitch-ub/a.out+0xa7f1c)
#2 0x7f8d9b23c78f (/usr/lib/libc.so.6+0x2378f) (BuildId: 4a4bec3d95a1804443e852958fe59ed461135ce9)
#3 0x7f8d9b23c849 in __libc_start_main (/usr/lib/libc.so.6+0x23849) (BuildId: 4a4bec3d95a1804443e852958fe59ed461135ce9)
#4 0x555ba2835294 in _start (/home/josh/src/llvm-test/unswitch-ub/a.out+0x1f294)
SUMMARY: MemorySanitizer: use-of-uninitialized-value (/home/josh/src/llvm-test/unswitch-ub/a.out+0xa7ed6) in foo(unsigned int, B<unsigned int>)
Exiting
archlinux [~/src/llvm-test/unswitch-ub]$ clang++ -fsanitize=memory -O3 -fno-inline -fno-discard-value-names -g0 foo.cpp
archlinux [~/src/llvm-test/unswitch-ub]$ ./a.out
hi
archlinux [~/src/llvm-test/unswitch-ub]$
```
When compiling with `O2`, non-trivial loop unswitching is not turned on, and msan emits an error. When compiling with `-O3`, loop unswitching inserts a freeze on the undefined value, and msan does not catch the error.
I think that we need to either:
1. don't perform unswitching on functions with `sanitize_memory` attribute (preferred)
2. be WAY more conservative on unswitching when `sanitize_memory` attribute is present. The unswitched condition must be non-undef-or-poison.
This issue was discussed in https://reviews.llvm.org/D138526/new/.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzEWF9vo7oS_zTOyyiI2JDAQx-SZnO10v6Rdk-12qfKwBB8CjbXNk3Th_vZr2wghbS7R-fuXp2qQo6xZ34z8_PMGG6MOErEGxLvSLxf8M5WSt_kXP2pTNXxRaaKs3v5BVutii5HTeI9oUllbWsI2xJ6IPRwVEWmahsofST08EzoIXtcf1Rx-Z0RmpJwT8Lt8FyHw3__kzIh87orEAilxhZCBRWh9K23VjQ4femfj0oUwAlNCE2BbHbQaiFt6SdoJUh8K90OmhK2A7LZT3ZlP9iVnfH1Nrbrd2ZK1VBOdmq0nZbgwBGafLr78MG_Ye8gHPZC7yPg9YmfDVjdIaG3kHUWctW0okYNhUIDUll4kOoEtuJ2amRec2Ng6_T1E9B2WS1y5__-NwBsCU066cNZwFMPYusGydOA9WK-Wz5ZOto2tXMMgEe-bVuuUdr6DCdhK9VZsJUwYLFpa269ObeE7gh1_vh3JzQa6AxYBUIKCzyYifsmbAW2wtl-YUEYaJUxIqvRuwC4m-qkkyF4LZ6xGASNG4GwW3tuUfIGwRL2buqv3cRfAG-5zEKp1MVkN7N7iew0cg4glwXw4MlHaYIIhIQCS97VLpzSWN3lVum5yF7REBI_TMaJSVhe-9_ztF9_iZd0YHaE3Y4zjmvNeTdKex3hfGZiqTRM5QkgbN-T1Q1vQXre-mgKeCXV_Q1u-YRYAHdWF1YoyesAPijV3klzEjavQMn6DEIa1NYAh1IjPiOI0se-VqpdCvnIteByYPso2EkUTqSLv_P3seOaS-v0WQX4hHlnMZiDEqUzaziac9iD2Oa8C0qlnNC5dh_bI1pHth47FnPhE6sbwyVgI5xNElBrpV1EjJA5TlX0vB2Zk2ku80rIIyjpX3m6340Ie_DD7jd9Pv4NuW4W0gvCzR6wNjjZnf18-VVcLxMzTl4nhGG8LS1q78mL25y1tVIPBoxq0Hp7a_GAUxE_N3VgZxAEb3rhOsivjXrln6kp1975HQpfefiHvvPPkSGeboRuSq2eURK6Ae79ObpSyGPQc-1SG_IK8wfoN4BqUXN3RoxnnwKp4G7nSJXz7ljZS8r1MZv6X1pouJCTTNfjfiun-EwwOzxX6W_qSJemVg5Nn41mnBvKZDgrNm92BG9Ncp1XtZDdE5B49x9CD0bnhB7q-rFZWjSW0MPot2WX-Q4lgrzm8jhUpWVpuAP9jITtG2yUPsPyM4VlKdVSyFpI7MeFMDnXxfKR1x0uXV0xsDyGzrogb9tfgBMQeuCB6sbKzvaE7WMWxv3o2_bLp_ef_uUKxEeP7-sAWLupzuBSlctZLewxXlIcCyF8iuM44zTJCizWrjJd1Q4h7XX18HPsnaeCY8ShUq6TObj-7y8tGy2iu_CJb7BYz04IoWw1xVSucofJke-XdZWr_FoXhfBpUyZFmlGWb5ISBiWd0U6syPpnHhgVrL0YyjbuaHvLd52oi_eFc3bEowxzVqQxXyVhFEUMk5imcVJinGIRrVcrFueYXgNgUwBJlDpj7--dyntjubb3E8t_BiqJ0t8HKnqJAItpGnlQHs4vxmBV0jS66u6_3n38uP3y_W-T-DdR7-8yvgf97klYIY__10zD_sFMU4n_XdZPUvS3CuVwgXFl3l0MgKzDz9Sto7cglVxaLR4Fr-dNgls99HWuJmABSo5t0hvNVQA_0LT8zAZVr8VfN51K-qazkwWWwqnsc-dU60uZ5a55dct7_VOj37uLj3zorycnBDm2pMJWnuTTxasACmfaxkKLulS6mYFUEspO5r6GX4wayXPfU4esQ-DWapF11p-SVmOJWmNxoS8NIEP4tv0OjdLo7yCoH7kVj9j3mi8aT86Rf6XE3cI0GpQ2gD-8z8aWeNKXN52xTq0LsnfqUullq4RRMoCpD_5w90RhTIdw4gYc6Ttj-mvT_BuCxkeBJxM4Pg4fEvYrlsR0TehB4onQQwCL4oYVKUv5Am9W64St03VMw0V1s9mUmzQNiyxKCr6ONiHPsqhM-CpMN0m2zhbihoaUhfEqDGOaRGGQU8aTlHFehiuWbRiJQmy4qC8AFh72zZquGVvUPMPa-M8klEo89TYRSkm8X-gbf4iy7mhIFNbC2BczFlbY2n9f-SqatsbpDYnEe6hE4S_LP0yNTqpr-hpP00Wn65urjy_CVl0W5KoZTvN4qFut_sTcnWsP1hB68Mb8NwAA___BFVMw">