Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[MSAN] Instrument libatomic load/store calls
These calls are neither intercepted by compiler-rt nor is libatomic.a naturally instrumented. This patch uses the existing libcall mechanism to detect a call to atomic_load or atomic_store, and instruments them much like the preexisting instrumentation for atomics. Calls to _load are modified to have at least Acquire ordering, and calls to _store at least Release ordering. Because this needs to be converted at runtime, msan injects a LUT (implemented as a vector with extractelement). Differential Revision: https://reviews.llvm.org/D83337
- Loading branch information
Showing
3 changed files
with
219 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -latomic -DTEST_STORE -O0 %s -o %t && %run %t 2>&1 | ||
// RUN: %clangxx_msan -fsanitize-memory-track-origins=0 -latomic -DTEST_LOAD -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK | ||
// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -latomic -DTEST_LOAD -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-SHADOW | ||
|
||
#include <sanitizer/msan_interface.h> | ||
#include <stdatomic.h> | ||
|
||
typedef struct __attribute((packed)) { | ||
uint8_t val[3]; | ||
} i24; | ||
|
||
void copy(i24 *dst, i24 *src); | ||
|
||
int main() { | ||
i24 uninit; | ||
i24 init = {0}; | ||
|
||
__msan_check_mem_is_initialized(&init, 3); | ||
copy(&init, &uninit); | ||
__msan_check_mem_is_initialized(&init, 3); | ||
} | ||
|
||
void copy(i24 *dst, i24 *src) { | ||
#ifdef TEST_LOAD | ||
__atomic_load(src, dst, __ATOMIC_RELAXED); | ||
|
||
// CHECK: MemorySanitizer: use-of-uninitialized-value | ||
// CHECK: #0 {{0x[a-f0-9]+}} in main{{.*}}libatomic.c:[[@LINE-8]] | ||
|
||
// CHECK-SHADOW: Uninitialized value was stored to memory at | ||
// CHECK-SHADOW: #0 {{0x[a-f0-9]+}} in copy{{.*}}libatomic.c:[[@LINE-6]] | ||
#endif | ||
#ifdef TEST_STORE | ||
// Store always writes a clean shadow | ||
__atomic_store(src, dst, __ATOMIC_RELAXED); | ||
#endif | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
; RUN: opt < %s -msan-check-access-address=0 -S -passes=msan 2>&1 | FileCheck %s | ||
; RUN: opt < %s -msan-check-access-address=0 -msan-track-origins=2 -S -passes=msan 2>&1 | FileCheck %s -check-prefixes=CHECK,CHECK-ORIGIN | ||
; RUN: opt < %s -msan -msan-check-access-address=0 -S | FileCheck %s | ||
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" | ||
target triple = "x86_64-unknown-linux-gnu" | ||
|
||
declare void @__atomic_load(i64, i8*, i8*, i32) | ||
declare void @__atomic_store(i64, i8*, i8*, i32) | ||
|
||
define i24 @odd_sized_load(i24* %ptr) sanitize_memory { | ||
; CHECK: @odd_sized_load(i24* {{.*}}[[PTR:%.+]]) | ||
; CHECK: [[VAL_PTR:%.*]] = alloca i24, align 1 | ||
; CHECK-ORIGIN: @__msan_set_alloca_origin | ||
; CHECK: [[VAL_PTR_I8:%.*]] = bitcast i24* [[VAL_PTR]] to i8* | ||
; CHECK: [[PTR_I8:%.*]] = bitcast i24* [[PTR]] to i8* | ||
; CHECK: call void @__atomic_load(i64 3, i8* [[PTR_I8]], i8* [[VAL_PTR_I8]], i32 2) | ||
|
||
; CHECK: ptrtoint i8* [[PTR_I8]] | ||
; CHECK: xor | ||
; CHECK: [[SPTR_I8:%.*]] = inttoptr | ||
; CHECK-ORIGIN: add | ||
; CHECK-ORIGIN: and | ||
; CHECK-ORIGIN: [[OPTR:%.*]] = inttoptr | ||
|
||
; CHECK: ptrtoint i8* [[VAL_PTR_I8]] | ||
; CHECK: xor | ||
; CHECK: [[VAL_SPTR_I8:%.*]] = inttoptr | ||
; CHECK-ORIGIN: add | ||
; CHECK-ORIGIN: and | ||
; CHECK-ORIGIN: [[VAL_OPTR:%.*]] = inttoptr | ||
|
||
; CHECK: call void @llvm.memcpy{{.*}}(i8* align 1 [[VAL_SPTR_I8]], i8* align 1 [[SPTR_I8]], i64 3 | ||
|
||
; CHECK-ORIGIN: [[ARG_ORIGIN:%.*]] = load i32, i32* [[OPTR]] | ||
; CHECK-ORIGIN: [[VAL_ORIGIN:%.*]] = call i32 @__msan_chain_origin(i32 [[ARG_ORIGIN]]) | ||
; CHECK-ORIGIN: call void @__msan_set_origin(i8* [[VAL_PTR_I8]], i64 3, i32 [[VAL_ORIGIN]]) | ||
|
||
; CHECK: [[VAL:%.*]] = load i24, i24* [[VAL_PTR]] | ||
; CHECK: ret i24 [[VAL]] | ||
%val_ptr = alloca i24, align 1 | ||
%val_ptr_i8 = bitcast i24* %val_ptr to i8* | ||
%ptr_i8 = bitcast i24* %ptr to i8* | ||
call void @__atomic_load(i64 3, i8* %ptr_i8, i8* %val_ptr_i8, i32 0) | ||
%val = load i24, i24* %val_ptr | ||
ret i24 %val | ||
} | ||
|
||
define void @odd_sized_store(i24* %ptr, i24 %val) sanitize_memory { | ||
; CHECK: @odd_sized_store(i24* {{.*}}[[PTR:%.+]], i24 {{.*}}[[VAL:%.+]]) | ||
; CHECK: [[VAL_PTR:%.*]] = alloca i24, align 1 | ||
; CHECK: store i24 [[VAL]], i24* [[VAL_PTR]] | ||
; CHECK: [[VAL_PTR_I8:%.*]] = bitcast i24* [[VAL_PTR]] to i8* | ||
; CHECK: [[PTR_I8:%.*]] = bitcast i24* [[PTR]] to i8* | ||
|
||
; CHECK: ptrtoint i8* [[PTR_I8]] | ||
; CHECK: xor | ||
; CHECK: [[SPTR_I8:%.*]] = inttoptr | ||
; CHECK: call void @llvm.memset{{.*}}(i8* align 1 [[SPTR_I8]], i8 0, i64 3 | ||
|
||
; CHECK: call void @__atomic_store(i64 3, i8* [[VAL_PTR_I8]], i8* [[PTR_I8]], i32 3) | ||
; CHECK: ret void | ||
%val_ptr = alloca i24, align 1 | ||
store i24 %val, i24* %val_ptr | ||
%val_ptr_i8 = bitcast i24* %val_ptr to i8* | ||
%ptr_i8 = bitcast i24* %ptr to i8* | ||
call void @__atomic_store(i64 3, i8* %val_ptr_i8, i8* %ptr_i8, i32 0) | ||
ret void | ||
} | ||
|