diff options
author | Kunqiu Chen <camsyn@foxmail.com> | 2025-07-14 15:45:08 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-07-14 15:45:08 +0800 |
commit | a6e1700fa622f75436c3c3ead23b1eefb67e88ea (patch) | |
tree | 83cf16981b362fdcad1150945e75e170f7eb19a1 /llvm/lib/Transforms/Utils/Local.cpp | |
parent | cad62df49a79df5e5136cfad280c5abc9f62c60b (diff) | |
download | llvm-a6e1700fa622f75436c3c3ead23b1eefb67e88ea.zip llvm-a6e1700fa622f75436c3c3ead23b1eefb67e88ea.tar.gz llvm-a6e1700fa622f75436c3c3ead23b1eefb67e88ea.tar.bz2 |
[Utils][Local] Preserve !nosanitize in combineMetadata when merging instructions (#148376)
`combineMetadata` helper currently drops `!nosanitize` metadata when
merging two instructions, even if both originally carried `!nosanitize`.
This is problematic because `!nosanitize` is a key mechanism used by
sanitizer (e.g., ASan) to suppress instrumentation. Removing it can lead
to unintended sanitizer behavior.
This patch adds `nosanitize` to the whitelist in combineMetadata,
preserving it only if both instructions carry `!nosanitize`; otherwise,
it is dropped. This patch also adds corresponding tests in a test file
and regenerates it.
---
### Details
**Example (see [Godbolt](https://godbolt.org/z/83P5eWczx) for
details**):
```llvm
%v1 = load i32, ptr %p, !nosanitize
%v2 = load i32, ptr %p, !nosanitize
```
When merged via `combineMetadata(%v1, %v2, ...)`, the resulting
instruction loses its `!nosanitize` metadata.
Tools such as UBSan and AFL rely on `nosanitize` to prevent unwanted
transformations or checks. However, the current implementation of
combineMetadata mistakenly drops !nosanitize. This may lead to
unintended behavior during optimization.
For example, under `-fsanitize=address,undefined -O2`, IR emitted by
UBSan may lose its `!nosanitize` metadata due to the incorrect metadata
merging in optimization. As a result, ASan could unexpectedly instrument
those instructions.
> Note: due to the current UBSan handlers having relatively
coarse-grained attributes, this specific case is difficult to reproduce
end-to-end from source code—UBSan currently inhibits such optimizations
(refer to #135135 for details).
Still, I believe it's necessary to fix this now, to support future
versions of UBSan that might allow such optimizations, and to support
third-party tools (such as AFL-based fuzzers) that rely on the presence
of !nosanitize.
Diffstat (limited to 'llvm/lib/Transforms/Utils/Local.cpp')
-rw-r--r-- | llvm/lib/Transforms/Utils/Local.cpp | 6 |
1 files changed, 5 insertions, 1 deletions
diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index f5208d5..81d8537 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -3381,7 +3381,11 @@ static void combineMetadata(Instruction *K, const Instruction *J, K->setMetadata(Kind, MDNode::getMostGenericNoaliasAddrspace(JMD, KMD)); break; - } + case LLVMContext::MD_nosanitize: + // Preserve !nosanitize if both K and J have it. + K->setMetadata(Kind, JMD); + break; + } } // Set !invariant.group from J if J has it. If both instructions have it // then we will just pick it from J - even when they are different. |