llvm / llvm/llvm-project

Missing stack unpoisoning for alloca

Open
#178,576 3 comments 0 reactions 0 assignees View on GitHub
compiler-rt:asan miscompilation
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

```c++
#include

[[clang::noinline]]
void func(uintptr_t** ptr) {
if (*ptr)
__builtin_trap();
}

void func2() {
uintptr_t* ptr = nullptr;
func(&ptr);
}
```

The above code compiled with `clang++ -fsanitize=address -S -o - -emit-llvm /tmp/test.cc -O1` will produce

```llvm
define dso_local void @_Z4funcPPm(ptr noundef readonly captures(none) %ptr) local_unnamed_addr #0 {
entry:
%0 = ptrtoint ptr %ptr to i64
%1 = lshr i64 %0, 3
%2 = add i64 %1, 2147450880
%3 = inttoptr i64 %2 to ptr
%4 = load i8, ptr %3, align 1
%5 = icmp ne i8 %4, 0
br i1 %5, label %6, label %7

6: ; preds = %entry
call void @__asan_report_load8(i64 %0) #5
unreachable

7: ; preds = %entry
%8 = load ptr, ptr %ptr, align 8, !tbaa !10
%tobool.not = icmp eq ptr %8, null
br i1 %tobool.not, label %if.end, label %if.then

if.then: ; preds = %7
call void @__asan_handle_no_return()
tail call void @llvm.trap()
unreachable

if.end: ; preds = %7
ret void
}

; Function Attrs: cold nobuiltin noreturn nounwind
declare void @llvm.trap() #1

; Function Attrs: mustprogress nobuiltin nounwind sanitize_address uwtable
define dso_local void @_Z5func2v() local_unnamed_addr #2 {
entry:
%ptr = alloca ptr, align 8, !annotation !13 ;; NO UNPOISONING HERE
call void @llvm.lifetime.start.p0(ptr nonnull %ptr) #6
store ptr null, ptr %ptr, align 8, !tbaa !10
call void @_Z4funcPPm(ptr noundef nonnull %ptr)
call void @llvm.lifetime.end.p0(ptr nonnull %ptr) #6
ret void
}
```

IR is not emitted for `func2` to either unpoison shadow corresponding to the `%ptr` alloca, nor is the IR for the stack malloc and poisoning of redzones emitted. When `func` is called, the instrumentation will check shadow for `%ptr` but since it wasn't unpoisoned, its shadow could be any value, potentially leading to a false positive.

I suspect this alloca isn't instrumented because it's not seen as an "interesting" alloca because it's "safe" according to `StackSafetyGlobalInfo::isSafe`:

```
bool IsInteresting =
...
// safe allocas are not interesting
!(SSGI && SSGI->isSafe(AI)));
```

If I disable `StackSafetyGlobalInfo` via `-mllvm -asan-use-stack-safety=0` then I see the expected instrumentation for that alloca.

I don't see this at `-O0` so it could also be there's a bad optimization elsewhere.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.