-
Notifications
You must be signed in to change notification settings - Fork 13.4k
clang++ should always emit @llvm.trap()
when flowing off the end of a non-void function
#75797
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
@llvm/issue-subscribers-clang-codegen Author: Jan Schultke (Eisenwave)
Currently, when optimizations are enabled, flowing off the end of a function in C++ mode emits `unreachable`. This means that a function such as:
```cpp
int get(int x) {
if (x == 0) { }
else std::abort();
}
```
... is equivalent to simply calling `abort()`, which is caused by emitting `unreachable` at the end of the function, and having `SimplifyCFG` eliminate the `x == 0` branch. This behavior does not reflect developer intent, and it's possible to fall through into other code sections as a result of simply treating this as optimizable UB.
On debug builds, Even with no warning flags enabled, clang emits Flowing off the end of a function is a common developer mistake and basically never intentional. It should not be hidden by the optimizer because it may result in security vulnerabilities such as CVE-2014-9296. If a developer actually wants the current behavior, they can simply write: int get(int x) {
if (x == 0) {
__builtin_unreachable(); // or, since C++23
std::unreachable(); // or, alternatively
[[assume(false)]];
}
else std::abort();
} There is zero motivation for violating programmer intent and emitting security vulnerabilities here. This offers no optimization opportunities that could not be trivially obtained with more explicit code. |
There are several cases in which invoking undefined behavior can get us into this unenviable position: #48943 This was also discussed here: https://discourse.llvm.org/t/can-we-keep-must-progress-optimizations-around-infinite-loop-in-c-while-avoiding-some-surprising-behavior/69205/5 I think the fix could be simple but measurement and testing is required to make sure this does not cause unintended regressions. |
If that is true (and I think it is), the we should (additionally?) make that frontend warning ( |
GCC defaults to trapping at -O0 and -Og (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104642). |
@Eisenwave wrote:
Agreed, now that C++23 Sometimes a path of execution isn't actually reachable but the compiler isn't able to prove that. Having the compiler waste code size on a So there is an optimization opportunity, but agreed that it should be opt-in with an explicit "we intentionally don't return" statement before the closing @tbaederr wrote:
Making it a runtime trap (x86 We could make it a compile-time error, but that would be inconsistent with how clang and other compilers handle other cases of compile-time-visible UB. Refusing to compile a valid C++ program is a big deal, not a step to be taken lightly. What could perhaps be useful is a The warning message for |
Currently, when optimizations are enabled, flowing off the end of a function in C++ mode emits
unreachable
. This means that a function such as:... is equivalent to simply calling
abort()
, which is caused by emittingunreachable
at the end of the function, and havingSimplifyCFG
eliminate thex == 0
branch. This behavior does not reflect developer intent, and it's possible to fall through into other code sections as a result of simply treating this as optimizable UB.On debug builds,
@llvm.trap()
is emitted at the end of the function, which generates aud2
pseudo-instruction on x86-64. This should also be done with optimizations enabled.Even with no warning flags enabled, clang emits
Flowing off the end of a function is a common developer mistake and basically never intentional. It should not be hidden by the optimizer because it may result in security vulnerabilities such as CVE-2014-9296.
If a developer actually wants the current behavior, they can simply write:
There is zero motivation for violating programmer intent and emitting security vulnerabilities here. This offers no optimization opportunities that could not be trivially obtained with more explicit code.
The text was updated successfully, but these errors were encountered: