[clang] [analyzer] Fix crash when copying uninitialized data in function named "swap" (PR #178923)
Balázs Benics via cfe-commits
cfe-commits at lists.llvm.org
Fri Jan 30 09:41:24 PST 2026
================
@@ -40,9 +40,12 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
// Do not report assignments of uninitialized values inside swap functions.
// This should allow to swap partially uninitialized structs
if (const FunctionDecl *EnclosingFunctionDecl =
- dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl()))
- if (C.getCalleeName(EnclosingFunctionDecl) == "swap")
+ dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl())) {
+ if (C.getCalleeName(EnclosingFunctionDecl) == "swap") {
+ C.generateSink(C.getState(), C.getPredecessor());
----------------
steakhal wrote:
It turns out I can't just sink here, because that would reduce coverage in tests:
```c++
void swap(struct MyStr *To, struct MyStr *From) {
// This is not really a swap but close enough for our test.
To->x = From->x;
To->y = From->y; // expected-note{{Uninitialized value stored to field 'y'}}
}
int test_undefined_member_assignment_in_swap(struct MyStr *s2) {
struct MyStr s1;
s1.x = 5;
swap(s2, &s1); // expected-note{{Calling 'swap'}}
// expected-note at -1{{Returning from 'swap'}}
return s2->y; // expected-warning{{Undefined or garbage value returned to caller}}
// expected-note at -1{{Undefined or garbage value returned to caller}}
}
```
Namely, the `Undefined or garbage value returned to caller` wouldn't be detected, because we would sink inside `swap`, and never reach the `return s2->y;`.
Before I inserted the sink, the checker would just not report inside `swap`, but lead the execution path to `return s2->y;` and detect the use of undef there.
I figure, this unusual but fine. If the hardened Store can handle the bind, that still resolves the crash, so I think I'll opt for only doing that.
https://github.com/llvm/llvm-project/pull/178923
More information about the cfe-commits
mailing list