| Issue |
204041
|
| Summary |
[ASan] False-positive use-after-poison at -O2 when reading guarded std::optional members
|
| Labels |
new issue
|
| Assignees |
|
| Reporter |
rvandermeulen
|
## Summary
At -O2, clang-cl produces a false-positive `use-after-poison` (shadow byte `f7`) ASan report when code accesses `std::optional` members that are correctly guarded behind `has_value()` checks. The crash does not occur at -O0 with the same annotations active.
The bug reproduces on clang 20, 21, and 22 (tested up to 22.1.6).
## Description
MSVC STL 14.51 (VS 2026 18.6) added `__asan_poison_memory_region` / `__asan_unpoison_memory_region` instrumentation to `<optional>`. When an `optional<T>` is disengaged, its `_Value` storage is poisoned; when engaged, it is unpoisoned.
Given a struct with multiple `optional<>` members where some are disengaged, code that processes all members with a guarded pattern like:
```cpp
PACL UnwrapAcl(const std::optional<AccessControlList>& acl) {
if (!acl) return nullptr;
return acl->get();
}
auto result = SetSD(...,
UnwrapAcl(sd.dacl()), // dacl_ is disengaged (storage poisoned)
UnwrapAcl(sd.sacl())); // sacl_ is engaged (storage clean)
```
triggers a `use-after-poison` report at -O2. The source code never dereferences a disengaged optional, yet ASan reports a read from poisoned storage.
## Concrete failure
This reproduces 100% on every Windows ASan CI run in the Firefox build when compiling the in-tree Chromium sandbox code against MSVC STL 14.51.
- Crash site: `base::win::SetSecurityDescriptor` at `security_descriptor.cc:166`
- Trigger: `sandbox::HardenTokenIntegrityLevelPolicy` creates a `SecurityDescriptor` with four `optional<>` members; only `sacl_` is engaged, the other three are disengaged (poisoned)
- Shadow pattern at the struct: `f7 f7 f7 00 f7 f7 f7 00 f7 f7 f7 00 [f7] 00` (three disengaged + one engaged)
ASan report (clang 22.1.6 / clang-cl):
```
==NNNN==ERROR: AddressSanitizer: use-after-poison on address 0x... at pc 0x...
READ of size 8 at 0x... thread T0
#0 in base::win::`anonymous namespace'::SetSecurityDescriptor
security_descriptor.cc:166
#1 in SecurityDescriptor::WriteToHandle ...
#2 in sandbox::HardenTokenIntegrityLevelPolicy ...
```
## Standalone reproduction
We were unable to create a minimal standalone reproducer. The bug appears to depend on optimization decisions (inlining, scheduling) that only manifest in the context of the larger binary. The Firefox CI failure is 100% reliable and we can provide build artifacts and full ASan logs on request.
## Environment
- clang-cl 20.1, 21.1, and 22.1.6 (all reproduce identically)
- MSVC STL 14.51.36231 (VS 2026 18.6)
- x64 Windows, `-fsanitize=address -O2 -Oy-`
- Does NOT reproduce at -O0
## Related
- [microsoft/STL#6291](https://github.com/microsoft/STL/issues/6291) - originally filed as an STL bug. The STL maintainers responded that the optimizer should not be attempting to move reads outside of the branch, pointing to this as a compiler issue.
## Workaround
MSVC STL provides `-D_DISABLE_OPTIONAL_ANNOTATION` which disables the `<optional>` poisoning. This eliminates the crash but loses all optional-related ASan coverage.
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs