From: Alexey Baturo Date: Wed, 10 Aug 2022 05:41:26 +0000 (+0300) Subject: re-land [RISC-V][HWASAN] Add support for HWASAN code instrumentation for RISC-V X-Git-Tag: upstream/17.0.6~23873 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f87382124f06b3f725b4e364f05a38990e8ce9e8;p=platform%2Fupstream%2Fllvm.git re-land [RISC-V][HWASAN] Add support for HWASAN code instrumentation for RISC-V now with the fixed warning and updated lit tests --- [RISC-V][HWASAN] Add support for HWASAN code instrumentation for RISC-V Reviewed By: vitalybuka Differential Revision: https://reviews.llvm.org/D131575 --- diff --git a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp index 066eca3..07b63c4 100644 --- a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp @@ -43,6 +43,7 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/MDBuilder.h" #include "llvm/IR/Module.h" +#include "llvm/IR/NoFolder.h" #include "llvm/IR/Type.h" #include "llvm/IR/Value.h" #include "llvm/Support/Casting.h" @@ -582,7 +583,8 @@ void HWAddressSanitizer::initializeModule() { UseShortGranules = ClUseShortGranules.getNumOccurrences() ? ClUseShortGranules : NewRuntime; OutlinedChecks = - TargetTriple.isAArch64() && TargetTriple.isOSBinFormatELF() && + (TargetTriple.isAArch64() || TargetTriple.isRISCV64()) && + TargetTriple.isOSBinFormatELF() && (ClInlineAllChecks.getNumOccurrences() ? !ClInlineAllChecks : !Recover); if (ClMatchAllTag.getNumOccurrences()) { @@ -795,7 +797,8 @@ static size_t TypeSizeToSizeIndex(uint32_t TypeSize) { } void HWAddressSanitizer::untagPointerOperand(Instruction *I, Value *Addr) { - if (TargetTriple.isAArch64() || TargetTriple.getArch() == Triple::x86_64) + if (TargetTriple.isAArch64() || TargetTriple.getArch() == Triple::x86_64 || + TargetTriple.isRISCV64()) return; IRBuilder<> IRB(I); @@ -913,6 +916,15 @@ void HWAddressSanitizer::instrumentMemAccessInline(Value *Ptr, bool IsWrite, "{x0}", /*hasSideEffects=*/true); break; + case Triple::riscv64: + // The signal handler will find the data address in x10. + Asm = InlineAsm::get( + FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false), + "ebreak\naddiw x0, x11, " + + itostr(0x40 + (AccessInfo & HWASanAccessInfo::RuntimeMask)), + "{x10}", + /*hasSideEffects=*/true); + break; default: report_fatal_error("unsupported architecture"); } diff --git a/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/alloca-with-calls.ll b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/alloca-with-calls.ll new file mode 100644 index 0000000..e8f1ca4 --- /dev/null +++ b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/alloca-with-calls.ll @@ -0,0 +1,22 @@ +; Test alloca instrumentation when tags are generated by HWASan function. +; +; RUN: opt < %s -passes=hwasan -hwasan-generate-tags-with-calls -S | FileCheck %s + +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" +target triple = "riscv64-unknown-linux" + +declare void @use32(ptr) + +define void @test_alloca() sanitize_hwaddress { +; CHECK-LABEL: @test_alloca( +; CHECK: %[[T1:[^ ]*]] = call i8 @__hwasan_generate_tag() +; CHECK: %[[A:[^ ]*]] = zext i8 %[[T1]] to i64 +; CHECK: %[[B:[^ ]*]] = ptrtoint ptr %x to i64 +; CHECK: %[[C:[^ ]*]] = shl i64 %[[A]], 56 +; CHECK: or i64 %[[B]], %[[C]] + +entry: + %x = alloca i32, align 4 + call void @use32(ptr nonnull %x) + ret void +} diff --git a/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/alloca.ll b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/alloca.ll new file mode 100644 index 0000000..488b8bd --- /dev/null +++ b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/alloca.ll @@ -0,0 +1,78 @@ +; Test alloca instrumentation. +; +; RUN: opt < %s -passes=hwasan -hwasan-with-ifunc=1 -S | FileCheck %s --check-prefixes=CHECK,DYNAMIC-SHADOW,NO-UAR-TAGS +; RUN: opt < %s -passes=hwasan -hwasan-mapping-offset=0 -S | FileCheck %s --check-prefixes=CHECK,ZERO-BASED-SHADOW,NO-UAR-TAGS +; RUN: opt < %s -passes=hwasan -hwasan-with-ifunc=1 -hwasan-uar-retag-to-zero=0 -S | FileCheck %s --check-prefixes=CHECK,DYNAMIC-SHADOW,UAR-TAGS + +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" +target triple = "riscv64-unknown-linux" + +declare void @use32(ptr) + +define void @test_alloca() sanitize_hwaddress !dbg !15 { +; CHECK-LABEL: @test_alloca( +; CHECK: %[[FP:[^ ]*]] = call ptr @llvm.frameaddress.p0(i32 0) +; CHECK: %[[A:[^ ]*]] = ptrtoint ptr %[[FP]] to i64 +; CHECK: %[[B:[^ ]*]] = lshr i64 %[[A]], 20 +; CHECK: %[[BASE_TAG:[^ ]*]] = xor i64 %[[A]], %[[B]] + +; CHECK: %[[X:[^ ]*]] = alloca { i32, [12 x i8] }, align 16 +; CHECK: %[[X_TAG:[^ ]*]] = xor i64 %[[BASE_TAG]], 0 +; CHECK: %[[X1:[^ ]*]] = ptrtoint ptr %[[X]] to i64 +; CHECK: %[[C:[^ ]*]] = shl i64 %[[X_TAG]], 56 +; CHECK: %[[D:[^ ]*]] = or i64 %[[X1]], %[[C]] +; CHECK: %[[X_HWASAN:[^ ]*]] = inttoptr i64 %[[D]] to ptr + +; CHECK: %[[X_TAG2:[^ ]*]] = trunc i64 %[[X_TAG]] to i8 +; CHECK: %[[E:[^ ]*]] = ptrtoint ptr %[[X]] to i64 +; CHECK: %[[F:[^ ]*]] = lshr i64 %[[E]], 4 +; DYNAMIC-SHADOW: %[[X_SHADOW:[^ ]*]] = getelementptr i8, ptr %.hwasan.shadow, i64 %[[F]] +; ZERO-BASED-SHADOW: %[[X_SHADOW:[^ ]*]] = inttoptr i64 %[[F]] to ptr +; CHECK: %[[X_SHADOW_GEP:[^ ]*]] = getelementptr i8, ptr %[[X_SHADOW]], i32 0 +; CHECK: store i8 4, ptr %[[X_SHADOW_GEP]] +; CHECK: %[[X_I8_GEP:[^ ]*]] = getelementptr i8, ptr %[[X]], i32 15 +; CHECK: store i8 %[[X_TAG2]], ptr %[[X_I8_GEP]] +; CHECK: call void @llvm.dbg.value( +; CHECK-SAME: metadata !DIArgList(ptr %[[X]], ptr %[[X]]) +; CHECK-SAME: metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_tag_offset, 0, DW_OP_LLVM_arg, 1, DW_OP_LLVM_tag_offset, 0, +; CHECK: call void @use32(ptr nonnull %[[X_HWASAN]]) + +; UAR-TAGS: %[[BASE_TAG_COMPL:[^ ]*]] = xor i64 %[[BASE_TAG]], 255 +; UAR-TAGS: %[[X_TAG_UAR:[^ ]*]] = trunc i64 %[[BASE_TAG_COMPL]] to i8 +; CHECK: %[[E2:[^ ]*]] = ptrtoint ptr %[[X]] to i64 +; CHECK: %[[F2:[^ ]*]] = lshr i64 %[[E2]], 4 +; DYNAMIC-SHADOW: %[[X_SHADOW2:[^ ]*]] = getelementptr i8, ptr %.hwasan.shadow, i64 %[[F2]] +; ZERO-BASED-SHADOW: %[[X_SHADOW2:[^ ]*]] = inttoptr i64 %[[F2]] to ptr +; NO-UAR-TAGS: call void @llvm.memset.p0.i64(ptr align 1 %[[X_SHADOW2]], i8 0, i64 1, i1 false) +; UAR-TAGS: call void @llvm.memset.p0.i64(ptr align 1 %[[X_SHADOW2]], i8 %[[X_TAG_UAR]], i64 1, i1 false) +; CHECK: ret void + + +entry: + %x = alloca i32, align 4 + call void @llvm.dbg.value(metadata !DIArgList(ptr %x, ptr %x), metadata !22, metadata !DIExpression(DW_OP_LLVM_arg, 0, DW_OP_LLVM_arg, 1, DW_OP_plus, DW_OP_deref)), !dbg !21 + call void @use32(ptr nonnull %x), !dbg !23 + ret void, !dbg !24 +} + +declare void @llvm.dbg.value(metadata, metadata, metadata) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4} +!llvm.ident = !{!14} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 13.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "alloca.cpp", directory: "/") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!14 = !{!"clang version 13.0.0"} +!15 = distinct !DISubprogram(name: "test_alloca", linkageName: "_Z11test_allocav", scope: !1, file: !1, line: 4, type: !16, scopeLine: 4, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!16 = !DISubroutineType(types: !17) +!17 = !{null} +!19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64) +!20 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!21 = !DILocation(line: 0, scope: !15) +!22 = !DILocalVariable(name: "x", scope: !15, file: !1, line: 5, type: !20) +!23 = !DILocation(line: 7, column: 5, scope: !15) +!24 = !DILocation(line: 8, column: 1, scope: !15) diff --git a/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/atomic.ll b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/atomic.ll new file mode 100644 index 0000000..47ad906 --- /dev/null +++ b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/atomic.ll @@ -0,0 +1,28 @@ +; Test basic address sanitizer instrumentation. +; +; RUN: opt < %s -passes=hwasan -S | FileCheck %s + +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" +target triple = "riscv64-unknown-linux" + +define void @atomicrmw(ptr %ptr) sanitize_hwaddress { +; CHECK-LABEL: @atomicrmw( +; CHECK: call void @llvm.hwasan.check.memaccess.shortgranules({{.*}}, ptr %ptr, i32 19) +; CHECK: atomicrmw add ptr %ptr, i64 1 seq_cst +; CHECK: ret void + +entry: + %0 = atomicrmw add ptr %ptr, i64 1 seq_cst + ret void +} + +define void @cmpxchg(ptr %ptr, i64 %compare_to, i64 %new_value) sanitize_hwaddress { +; CHECK-LABEL: @cmpxchg( +; CHECK: call void @llvm.hwasan.check.memaccess.shortgranules({{.*}}, ptr %ptr, i32 19) +; CHECK: cmpxchg ptr %ptr, i64 %compare_to, i64 %new_value seq_cst seq_cst +; CHECK: ret void + +entry: + %0 = cmpxchg ptr %ptr, i64 %compare_to, i64 %new_value seq_cst seq_cst + ret void +} diff --git a/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/basic.ll b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/basic.ll new file mode 100644 index 0000000..cb3667b --- /dev/null +++ b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/basic.ll @@ -0,0 +1,401 @@ +; Test basic address sanitizer instrumentation. +; +; RUN: opt < %s -passes=hwasan -hwasan-recover=0 -hwasan-with-ifunc=1 -hwasan-with-tls=0 -S | FileCheck %s --check-prefixes=CHECK,ABORT +; RUN: opt < %s -passes=hwasan -hwasan-recover=1 -hwasan-with-ifunc=1 -hwasan-with-tls=0 -S | FileCheck %s --check-prefixes=CHECK,RECOVER,RECOVER-DYNAMIC-SHADOW +; RUN: opt < %s -passes=hwasan -hwasan-recover=0 -hwasan-mapping-offset=0 -S | FileCheck %s --check-prefixes=CHECK,ABORT +; RUN: opt < %s -passes=hwasan -hwasan-recover=1 -hwasan-mapping-offset=0 -S | FileCheck %s --check-prefixes=CHECK,RECOVER,RECOVER-ZERO-BASED-SHADOW + +; CHECK: @llvm.used = appending global [1 x ptr] [ptr @hwasan.module_ctor] +; CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @hwasan.module_ctor, ptr @hwasan.module_ctor }] + +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" +target triple = "riscv64-unknown-linux" + +define i8 @test_load8(ptr %a) sanitize_hwaddress { +; CHECK-LABEL: @test_load8( +; RECOVER: %[[A:[^ ]*]] = ptrtoint ptr %a to i64 +; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56 +; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8 +; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935 +; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4 +; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, ptr %.hwasan.shadow, i64 %4 +; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to ptr +; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, ptr %[[E]] +; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]] +; RECOVER: br i1 %[[F]], label %[[MISMATCH:[0-9]*]], label %[[CONT:[0-9]*]], !prof {{.*}} + +; RECOVER: [[MISMATCH]]: +; RECOVER: %[[NOTSHORT:[^ ]*]] = icmp ugt i8 %[[MEMTAG]], 15 +; RECOVER: br i1 %[[NOTSHORT]], label %[[FAIL:[0-9]*]], label %[[SHORT:[0-9]*]], !prof {{.*}} + +; RECOVER: [[FAIL]]: +; RECOVER: call void asm sideeffect "ebreak\0Aaddiw x0, x11, 96", "{x10}"(i64 %[[A]]) +; RECOVER: br label + +; RECOVER: [[SHORT]]: +; RECOVER: %[[LOWBITS:[^ ]*]] = and i64 %[[A]], 15 +; RECOVER: %[[LOWBITS_I8:[^ ]*]] = trunc i64 %[[LOWBITS]] to i8 +; RECOVER: %[[LAST:[^ ]*]] = add i8 %[[LOWBITS_I8]], 0 +; RECOVER: %[[OOB:[^ ]*]] = icmp uge i8 %[[LAST]], %[[MEMTAG]] +; RECOVER: br i1 %[[OOB]], label %[[FAIL]], label %[[INBOUNDS:[0-9]*]], !prof {{.*}} + +; RECOVER: [[INBOUNDS]]: +; RECOVER: %[[EOG_ADDR:[^ ]*]] = or i64 %[[C]], 15 +; RECOVER: %[[EOG_PTR:[^ ]*]] = inttoptr i64 %[[EOG_ADDR]] to ptr +; RECOVER: %[[EOGTAG:[^ ]*]] = load i8, ptr %[[EOG_PTR]] +; RECOVER: %[[EOG_MISMATCH:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[EOGTAG]] +; RECOVER: br i1 %[[EOG_MISMATCH]], label %[[FAIL]], label %[[CONT1:[0-9]*]], !prof {{.*}} + +; RECOVER: [[CONT1]]: +; RECOVER: br label %[[CONT]] + +; RECOVER: [[CONT]]: + +; ABORT: call void @llvm.hwasan.check.memaccess.shortgranules(ptr %.hwasan.shadow, ptr %a, i32 0) + +; CHECK: %[[G:[^ ]*]] = load i8, ptr %a, align 4 +; CHECK: ret i8 %[[G]] + +entry: + %b = load i8, ptr %a, align 4 + ret i8 %b +} + +define i16 @test_load16(ptr %a) sanitize_hwaddress { +; CHECK-LABEL: @test_load16( +; RECOVER: %[[A:[^ ]*]] = ptrtoint ptr %a to i64 +; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56 +; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8 +; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935 +; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4 +; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, ptr %.hwasan.shadow, i64 %4 +; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to ptr +; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, ptr %[[E]] +; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]] +; RECOVER: br i1 %[[F]], label %[[MISMATCH:[0-9]*]], label %[[CONT:[0-9]*]], !prof {{.*}} + +; RECOVER: [[MISMATCH]]: +; RECOVER: %[[NOTSHORT:[^ ]*]] = icmp ugt i8 %[[MEMTAG]], 15 +; RECOVER: br i1 %[[NOTSHORT]], label %[[FAIL:[0-9]*]], label %[[SHORT:[0-9]*]], !prof {{.*}} + +; RECOVER: [[FAIL]]: +; RECOVER: call void asm sideeffect "ebreak\0Aaddiw x0, x11, 97", "{x10}"(i64 %[[A]]) +; RECOVER: br label + +; RECOVER: [[SHORT]]: +; RECOVER: %[[LOWBITS:[^ ]*]] = and i64 %[[A]], 15 +; RECOVER: %[[LOWBITS_I8:[^ ]*]] = trunc i64 %[[LOWBITS]] to i8 +; RECOVER: %[[LAST:[^ ]*]] = add i8 %[[LOWBITS_I8]], 1 +; RECOVER: %[[OOB:[^ ]*]] = icmp uge i8 %[[LAST]], %[[MEMTAG]] +; RECOVER: br i1 %[[OOB]], label %[[FAIL]], label %[[INBOUNDS:[0-9]*]], !prof {{.*}} + +; RECOVER: [[INBOUNDS]]: +; RECOVER: %[[EOG_ADDR:[^ ]*]] = or i64 %[[C]], 15 +; RECOVER: %[[EOG_PTR:[^ ]*]] = inttoptr i64 %[[EOG_ADDR]] to ptr +; RECOVER: %[[EOGTAG:[^ ]*]] = load i8, ptr %[[EOG_PTR]] +; RECOVER: %[[EOG_MISMATCH:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[EOGTAG]] +; RECOVER: br i1 %[[EOG_MISMATCH]], label %[[FAIL]], label %[[CONT1:[0-9]*]], !prof {{.*}} + +; RECOVER: [[CONT1]]: +; RECOVER: br label %[[CONT]] + +; RECOVER: [[CONT]]: + +; ABORT: call void @llvm.hwasan.check.memaccess.shortgranules(ptr %.hwasan.shadow, ptr %a, i32 1) + +; CHECK: %[[G:[^ ]*]] = load i16, ptr %a, align 4 +; CHECK: ret i16 %[[G]] + +entry: + %b = load i16, ptr %a, align 4 + ret i16 %b +} + +define i32 @test_load32(ptr %a) sanitize_hwaddress { +; CHECK-LABEL: @test_load32( +; RECOVER: %[[A:[^ ]*]] = ptrtoint ptr %a to i64 +; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56 +; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8 +; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935 +; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4 +; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, ptr %.hwasan.shadow, i64 %4 +; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to ptr +; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, ptr %[[E]] +; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]] +; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}} + +; RECOVER: call void asm sideeffect "ebreak\0Aaddiw x0, x11, 98", "{x10}"(i64 %[[A]]) +; RECOVER: br label + +; ABORT: call void @llvm.hwasan.check.memaccess.shortgranules(ptr %.hwasan.shadow, ptr %a, i32 2) + +; CHECK: %[[G:[^ ]*]] = load i32, ptr %a, align 4 +; CHECK: ret i32 %[[G]] + +entry: + %b = load i32, ptr %a, align 4 + ret i32 %b +} + +define i64 @test_load64(ptr %a) sanitize_hwaddress { +; CHECK-LABEL: @test_load64( +; RECOVER: %[[A:[^ ]*]] = ptrtoint ptr %a to i64 +; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56 +; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8 +; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935 +; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4 +; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, ptr %.hwasan.shadow, i64 %4 +; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to ptr +; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, ptr %[[E]] +; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]] +; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}} + +; RECOVER: call void asm sideeffect "ebreak\0Aaddiw x0, x11, 99", "{x10}"(i64 %[[A]]) +; RECOVER: br label + +; ABORT: call void @llvm.hwasan.check.memaccess.shortgranules(ptr %.hwasan.shadow, ptr %a, i32 3) + +; CHECK: %[[G:[^ ]*]] = load i64, ptr %a, align 8 +; CHECK: ret i64 %[[G]] + +entry: + %b = load i64, ptr %a, align 8 + ret i64 %b +} + +define i128 @test_load128(ptr %a) sanitize_hwaddress { +; CHECK-LABEL: @test_load128( +; RECOVER: %[[A:[^ ]*]] = ptrtoint ptr %a to i64 +; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56 +; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8 +; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935 +; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4 +; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, ptr %.hwasan.shadow, i64 %4 +; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to ptr +; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, ptr %[[E]] +; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]] +; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}} + +; RECOVER: call void asm sideeffect "ebreak\0Aaddiw x0, x11, 100", "{x10}"(i64 %[[A]]) +; RECOVER: br label + +; ABORT: call void @llvm.hwasan.check.memaccess.shortgranules(ptr %.hwasan.shadow, ptr %a, i32 4) + +; CHECK: %[[G:[^ ]*]] = load i128, ptr %a, align 16 +; CHECK: ret i128 %[[G]] + +entry: + %b = load i128, ptr %a, align 16 + ret i128 %b +} + +define i40 @test_load40(ptr %a) sanitize_hwaddress { +; CHECK-LABEL: @test_load40( +; CHECK: %[[A:[^ ]*]] = ptrtoint ptr %a to i64 +; ABORT: call void @__hwasan_loadN(i64 %[[A]], i64 5) +; RECOVER: call void @__hwasan_loadN_noabort(i64 %[[A]], i64 5) +; CHECK: %[[B:[^ ]*]] = load i40, ptr %a +; CHECK: ret i40 %[[B]] + +entry: + %b = load i40, ptr %a, align 4 + ret i40 %b +} + +define void @test_store8(ptr %a, i8 %b) sanitize_hwaddress { +; CHECK-LABEL: @test_store8( +; RECOVER: %[[A:[^ ]*]] = ptrtoint ptr %a to i64 +; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56 +; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8 +; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935 +; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4 +; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, ptr %.hwasan.shadow, i64 %4 +; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to ptr +; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, ptr %[[E]] +; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]] +; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}} + +; RECOVER: call void asm sideeffect "ebreak\0Aaddiw x0, x11, 112", "{x10}"(i64 %[[A]]) +; RECOVER: br label + +; ABORT: call void @llvm.hwasan.check.memaccess.shortgranules(ptr %.hwasan.shadow, ptr %a, i32 16) + +; CHECK: store i8 %b, ptr %a, align 4 +; CHECK: ret void + +entry: + store i8 %b, ptr %a, align 4 + ret void +} + +define void @test_store16(ptr %a, i16 %b) sanitize_hwaddress { +; CHECK-LABEL: @test_store16( +; RECOVER: %[[A:[^ ]*]] = ptrtoint ptr %a to i64 +; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56 +; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8 +; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935 +; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4 +; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, ptr %.hwasan.shadow, i64 %4 +; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to ptr +; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, ptr %[[E]] +; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]] +; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}} + +; RECOVER: call void asm sideeffect "ebreak\0Aaddiw x0, x11, 113", "{x10}"(i64 %[[A]]) +; RECOVER: br label + +; ABORT: call void @llvm.hwasan.check.memaccess.shortgranules(ptr %.hwasan.shadow, ptr %a, i32 17) + +; CHECK: store i16 %b, ptr %a, align 4 +; CHECK: ret void + +entry: + store i16 %b, ptr %a, align 4 + ret void +} + +define void @test_store32(ptr %a, i32 %b) sanitize_hwaddress { +; CHECK-LABEL: @test_store32( +; RECOVER: %[[A:[^ ]*]] = ptrtoint ptr %a to i64 +; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56 +; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8 +; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935 +; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4 +; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, ptr %.hwasan.shadow, i64 %4 +; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to ptr +; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, ptr %[[E]] +; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]] +; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}} + +; RECOVER: call void asm sideeffect "ebreak\0Aaddiw x0, x11, 114", "{x10}"(i64 %[[A]]) +; RECOVER: br label + +; ABORT: call void @llvm.hwasan.check.memaccess.shortgranules(ptr %.hwasan.shadow, ptr %a, i32 18) + +; CHECK: store i32 %b, ptr %a, align 4 +; CHECK: ret void + +entry: + store i32 %b, ptr %a, align 4 + ret void +} + +define void @test_store64(ptr %a, i64 %b) sanitize_hwaddress { +; CHECK-LABEL: @test_store64( +; RECOVER: %[[A:[^ ]*]] = ptrtoint ptr %a to i64 +; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56 +; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8 +; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935 +; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4 +; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, ptr %.hwasan.shadow, i64 %4 +; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to ptr +; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, ptr %[[E]] +; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]] +; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}} + +; RECOVER: call void asm sideeffect "ebreak\0Aaddiw x0, x11, 115", "{x10}"(i64 %[[A]]) +; RECOVER: br label + +; ABORT: call void @llvm.hwasan.check.memaccess.shortgranules(ptr %.hwasan.shadow, ptr %a, i32 19) + +; CHECK: store i64 %b, ptr %a, align 8 +; CHECK: ret void + +entry: + store i64 %b, ptr %a, align 8 + ret void +} + +define void @test_store128(ptr %a, i128 %b) sanitize_hwaddress { +; CHECK-LABEL: @test_store128( +; RECOVER: %[[A:[^ ]*]] = ptrtoint ptr %a to i64 +; RECOVER: %[[B:[^ ]*]] = lshr i64 %[[A]], 56 +; RECOVER: %[[PTRTAG:[^ ]*]] = trunc i64 %[[B]] to i8 +; RECOVER: %[[C:[^ ]*]] = and i64 %[[A]], 72057594037927935 +; RECOVER: %[[D:[^ ]*]] = lshr i64 %[[C]], 4 +; RECOVER-DYNAMIC-SHADOW: %[[E:[^ ]*]] = getelementptr i8, ptr %.hwasan.shadow, i64 %4 +; RECOVER-ZERO-BASED-SHADOW: %[[E:[^ ]*]] = inttoptr i64 %[[D]] to ptr +; RECOVER: %[[MEMTAG:[^ ]*]] = load i8, ptr %[[E]] +; RECOVER: %[[F:[^ ]*]] = icmp ne i8 %[[PTRTAG]], %[[MEMTAG]] +; RECOVER: br i1 %[[F]], label {{.*}}, label {{.*}}, !prof {{.*}} + +; RECOVER: call void asm sideeffect "ebreak\0Aaddiw x0, x11, 116", "{x10}"(i64 %[[A]]) +; RECOVER: br label + +; ABORT: call void @llvm.hwasan.check.memaccess.shortgranules(ptr %.hwasan.shadow, ptr %a, i32 20) + +; CHECK: store i128 %b, ptr %a, align 16 +; CHECK: ret void + +entry: + store i128 %b, ptr %a, align 16 + ret void +} + +define void @test_store40(ptr %a, i40 %b) sanitize_hwaddress { +; CHECK-LABEL: @test_store40( +; CHECK: %[[A:[^ ]*]] = ptrtoint ptr %a to i64 +; ABORT: call void @__hwasan_storeN(i64 %[[A]], i64 5) +; RECOVER: call void @__hwasan_storeN_noabort(i64 %[[A]], i64 5) +; CHECK: store i40 %b, ptr %a +; CHECK: ret void + +entry: + store i40 %b, ptr %a, align 4 + ret void +} + +define void @test_store_unaligned(ptr %a, i64 %b) sanitize_hwaddress { +; CHECK-LABEL: @test_store_unaligned( +; CHECK: %[[A:[^ ]*]] = ptrtoint ptr %a to i64 +; ABORT: call void @__hwasan_storeN(i64 %[[A]], i64 8) +; RECOVER: call void @__hwasan_storeN_noabort(i64 %[[A]], i64 8) +; CHECK: store i64 %b, ptr %a, align 4 +; CHECK: ret void + +entry: + store i64 %b, ptr %a, align 4 + ret void +} + +define i8 @test_load_noattr(ptr %a) { +; CHECK-LABEL: @test_load_noattr( +; CHECK-NEXT: entry: +; CHECK-NEXT: %[[B:[^ ]*]] = load i8, ptr %a +; CHECK-NEXT: ret i8 %[[B]] + +entry: + %b = load i8, ptr %a, align 4 + ret i8 %b +} + +define i8 @test_load_notmyattr(ptr %a) sanitize_address { +; CHECK-LABEL: @test_load_notmyattr( +; CHECK-NEXT: entry: +; CHECK-NEXT: %[[B:[^ ]*]] = load i8, ptr %a +; CHECK-NEXT: ret i8 %[[B]] + +entry: + %b = load i8, ptr %a, align 4 + ret i8 %b +} + +define i8 @test_load_addrspace(ptr addrspace(256) %a) sanitize_hwaddress { +; CHECK-LABEL: @test_load_addrspace( +; CHECK-NEXT: entry: +; CHECK-NEXT: %[[B:[^ ]*]] = load i8, ptr addrspace(256) %a +; CHECK-NEXT: ret i8 %[[B]] + +entry: + %b = load i8, ptr addrspace(256) %a, align 4 + ret i8 %b +} + +; CHECK: declare void @__hwasan_init() + +; CHECK: define internal void @hwasan.module_ctor() #[[#ATTR:]] comdat { +; CHECK-NEXT: call void @__hwasan_init() +; CHECK-NEXT: ret void +; CHECK-NEXT: } + +; CHECK: attributes #[[#ATTR]] = { nounwind } diff --git a/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/exception-lifetime.ll b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/exception-lifetime.ll new file mode 100644 index 0000000..7b51acd --- /dev/null +++ b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/exception-lifetime.ll @@ -0,0 +1,55 @@ +; Test allocas with multiple lifetime ends, as frequently seen for exception +; handling. +; +; RUN: opt -passes=hwasan -hwasan-use-after-scope -S -o - %s | FileCheck %s --check-prefix=CHECK + +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" +target triple = "riscv64-unknown-linux" + +declare void @mayFail(ptr %x) sanitize_hwaddress +declare void @onExcept(ptr %x) sanitize_hwaddress + +declare void @llvm.lifetime.start.p0(i64, ptr nocapture) nounwind +declare void @llvm.lifetime.end.p0(i64, ptr nocapture) nounwind +declare i32 @__gxx_personality_v0(...) + +define void @test() sanitize_hwaddress personality ptr @__gxx_personality_v0 { +entry: + %x = alloca i32, align 8 + %exn.slot = alloca ptr, align 8 + %ehselector.slot = alloca i32, align 4 + call void @llvm.lifetime.start.p0(i64 8, ptr %x) + invoke void @mayFail(ptr %x) to label %invoke.cont unwind label %lpad + +invoke.cont: ; preds = %entry +; CHECK: invoke.cont: +; CHECK: call void @llvm.memset.p0.i64(ptr align 1 %{{.*}}, i8 0, i64 1, i1 false) +; CHECK: call void @llvm.lifetime.end.p0(i64 16, ptr {{.*}}{{.*}}%x) +; CHECK: ret void + + call void @llvm.lifetime.end.p0(i64 8, ptr %x) + ret void + +lpad: ; preds = %entry +; CHECK: lpad +; CHECK: call void @llvm.memset.p0.i64(ptr align 1 %{{.*}}, i8 0, i64 1, i1 false) +; CHECK: call void @llvm.lifetime.end.p0(i64 16, ptr {{.*}}{{.*}}%x) +; CHECK: br label %eh.resume + + %0 = landingpad { ptr, i32 } + cleanup + %1 = extractvalue { ptr, i32 } %0, 0 + store ptr %1, ptr %exn.slot, align 8 + %2 = extractvalue { ptr, i32 } %0, 1 + store i32 %2, ptr %ehselector.slot, align 4 + call void @onExcept(ptr %x) #18 + call void @llvm.lifetime.end.p0(i64 8, ptr %x) + br label %eh.resume + +eh.resume: ; preds = %lpad + %exn = load ptr, ptr %exn.slot, align 8 + %sel = load i32, ptr %ehselector.slot, align 4 + %lpad.val = insertvalue { ptr, i32 } undef, ptr %exn, 0 + %lpad.val1 = insertvalue { ptr, i32 } %lpad.val, i32 %sel, 1 + resume { ptr, i32 } %lpad.val1 +} diff --git a/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/stack-safety-analysis.ll b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/stack-safety-analysis.ll new file mode 100644 index 0000000..eb71ba2 --- /dev/null +++ b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/stack-safety-analysis.ll @@ -0,0 +1,303 @@ +; RUN: opt -passes=hwasan -hwasan-instrument-with-calls -hwasan-use-stack-safety=1 -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=SAFETY,CHECK +; RUN: opt -passes=hwasan -hwasan-instrument-with-calls -hwasan-use-stack-safety=0 -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=NOSAFETY,CHECK +; RUN: opt -passes=hwasan -hwasan-instrument-with-calls -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=SAFETY,CHECK +; RUN: opt -passes=hwasan -hwasan-instrument-stack=0 -hwasan-instrument-with-calls -hwasan-generate-tags-with-calls -S < %s | FileCheck %s --check-prefixes=NOSTACK,CHECK + +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" +target triple = "riscv64-unknown-linux" + +; Check a safe alloca to ensure it does not get a tag. +define i32 @test_simple(ptr %a) sanitize_hwaddress { +entry: + ; CHECK-LABEL: @test_simple + ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_store + ; SAFETY-NOT: call {{.*}}__hwasan_generate_tag + ; SAFETY-NOT: call {{.*}}__hwasan_store + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK-NOT: call {{.*}}__hwasan_store + %buf.sroa.0 = alloca i8, align 4 + call void @llvm.lifetime.start.p0(i64 1, ptr nonnull %buf.sroa.0) + store volatile i8 0, ptr %buf.sroa.0, align 4, !tbaa !8 + call void @llvm.lifetime.end.p0(i64 1, ptr nonnull %buf.sroa.0) + ret i32 0 +} + +; Check a non-safe alloca to ensure it gets a tag. +define i32 @test_use(ptr %a) sanitize_hwaddress { +entry: + ; CHECK-LABEL: @test_use + ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_store + ; SAFETY: call {{.*}}__hwasan_generate_tag + ; SAFETY-NOT: call {{.*}}__hwasan_store + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK-NOT: call {{.*}}__hwasan_store + %buf.sroa.0 = alloca i8, align 4 + call void @use(ptr nonnull %buf.sroa.0) + call void @llvm.lifetime.start.p0(i64 1, ptr nonnull %buf.sroa.0) + store volatile i8 0, ptr %buf.sroa.0, align 4, !tbaa !8 + call void @llvm.lifetime.end.p0(i64 1, ptr nonnull %buf.sroa.0) + ret i32 0 +} + +; Check an alloca with in range GEP to ensure it does not get a tag or check. +define i32 @test_in_range(ptr %a) sanitize_hwaddress { +entry: + ; CHECK-LABEL: @test_in_range + ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_store + ; SAFETY-NOT: call {{.*}}__hwasan_generate_tag + ; SAFETY-NOT: call {{.*}}__hwasan_store + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK-NOT: call {{.*}}__hwasan_store + %buf.sroa.0 = alloca [10 x i8], align 4 + call void @llvm.lifetime.start.p0(i64 10, ptr nonnull %buf.sroa.0) + store volatile i8 0, ptr %buf.sroa.0, align 4, !tbaa !8 + call void @llvm.lifetime.end.p0(i64 10, ptr nonnull %buf.sroa.0) + ret i32 0 +} + +; Check an alloca with in range GEP to ensure it does not get a tag or check. +define i32 @test_in_range2(ptr %a) sanitize_hwaddress { +entry: + ; CHECK-LABEL: @test_in_range2 + ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_store + ; SAFETY-NOT: call {{.*}}__hwasan_generate_tag + ; SAFETY-NOT: call {{.*}}__hwasan_store + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK-NOT: call {{.*}}__hwasan_store + %buf.sroa.0 = alloca [10 x i8], align 4 + %ptr = getelementptr [10 x i8], ptr %buf.sroa.0, i32 0, i32 9 + call void @llvm.lifetime.start.p0(i64 10, ptr nonnull %buf.sroa.0) + store volatile i8 0, ptr %ptr, align 4, !tbaa !8 + call void @llvm.lifetime.end.p0(i64 10, ptr nonnull %buf.sroa.0) + ret i32 0 +} + +define i32 @test_in_range3(ptr %a) sanitize_hwaddress { +entry: + ; CHECK-LABEL: @test_in_range3 + ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_memset + ; SAFETY-NOT: call {{.*}}__hwasan_generate_tag + ; SAFETY-NOT: call {{.*}}__hwasan_memset + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK-NOT: call {{.*}}__hwasan_memset + %buf.sroa.0 = alloca [10 x i8], align 4 + %ptr = getelementptr [10 x i8], ptr %buf.sroa.0, i32 0, i32 9 + call void @llvm.memset.p0.i32(ptr %ptr, i8 0, i32 1, i1 true) + ret i32 0 +} + +define i32 @test_in_range4(ptr %a) sanitize_hwaddress { +entry: + ; CHECK-LABEL: @test_in_range4 + ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_memmove + ; SAFETY-NOT: call {{.*}}__hwasan_generate_tag + ; SAFETY-NOT: call {{.*}}__hwasan_memmove + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK-NOT: call {{.*}}__hwasan_memmove + %buf.sroa.0 = alloca [10 x i8], align 4 + %ptr = getelementptr [10 x i8], ptr %buf.sroa.0, i32 0, i32 9 + call void @llvm.memmove.p0.p0.i32(ptr %ptr, ptr %ptr, i32 1, i1 true) + ret i32 0 +} + +define i32 @test_in_range5(ptr %a) sanitize_hwaddress { +entry: + ; CHECK-LABEL: @test_in_range5 + ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_memmove + ; SAFETY-NOT: call {{.*}}__hwasan_generate_tag + ; SAFETY-NOT: call {{.*}}__hwasan_memmove + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK-NOT: call {{.*}}__hwasan_memmove + %buf.sroa.0 = alloca [10 x i8], align 4 + %ptr = getelementptr [10 x i8], ptr %buf.sroa.0, i32 0, i32 9 + %buf.sroa.1 = alloca [10 x i8], align 4 + %ptr1 = getelementptr [10 x i8], ptr %buf.sroa.0, i32 0, i32 9 + call void @llvm.memmove.p0.p0.i32(ptr %ptr, ptr %ptr1, i32 1, i1 true) + ret i32 0 +} + +; Check an alloca with out of range GEP to ensure it gets a tag and check. +define i32 @test_out_of_range(ptr %a) sanitize_hwaddress { +entry: + ; CHECK-LABEL: @test_out_of_range + ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_store + ; SAFETY: call {{.*}}__hwasan_generate_tag + ; SAFETY: call {{.*}}__hwasan_store + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK-NOT: call {{.*}}__hwasan_store + %buf.sroa.0 = alloca [10 x i8], align 4 + %ptr = getelementptr [10 x i8], ptr %buf.sroa.0, i32 0, i32 10 + call void @llvm.lifetime.start.p0(i64 10, ptr nonnull %buf.sroa.0) + store volatile i8 0, ptr %ptr, align 4, !tbaa !8 + call void @llvm.lifetime.end.p0(i64 10, ptr nonnull %buf.sroa.0) + ret i32 0 +} + +define i32 @test_out_of_range3(ptr %a) sanitize_hwaddress { +entry: + ; CHECK-LABEL: @test_out_of_range3 + ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_memset + ; SAFETY: call {{.*}}__hwasan_generate_tag + ; SAFETY: call {{.*}}__hwasan_memset + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK-NOT: call {{.*}}__hwasan_memset + %buf.sroa.0 = alloca [10 x i8], align 4 + %ptr = getelementptr [10 x i8], ptr %buf.sroa.0, i32 0, i32 9 + call void @llvm.memset.p0.i32(ptr %ptr, i8 0, i32 2, i1 true) + ret i32 0 +} + +define i32 @test_out_of_range4(ptr %a) sanitize_hwaddress { +entry: + ; CHECK-LABEL: @test_out_of_range4 + ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_memmove + ; SAFETY: call {{.*}}__hwasan_generate_tag + ; SAFETY: call {{.*}}__hwasan_memmove + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK-NOT: call {{.*}}__hwasan_memmove + %buf.sroa.0 = alloca [10 x i8], align 4 + %ptr = getelementptr [10 x i8], ptr %buf.sroa.0, i32 0, i32 9 + call void @llvm.memmove.p0.p0.i32(ptr %ptr, ptr %ptr, i32 2, i1 true) + ret i32 0 +} + +define i32 @test_out_of_range5(ptr %a) sanitize_hwaddress { +entry: + ; CHECK-LABEL: @test_out_of_range5 + ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_memmove + ; SAFETY: call {{.*}}__hwasan_generate_tag + ; SAFETY: call {{.*}}__hwasan_memmove + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK-NOT: call {{.*}}__hwasan_memmove + %buf.sroa.0 = alloca [10 x i8], align 4 + %ptr = getelementptr [10 x i8], ptr %buf.sroa.0, i32 0, i32 9 + %buf.sroa.1 = alloca [10 x i8], align 4 + %ptr1 = getelementptr [10 x i8], ptr %buf.sroa.0, i32 0, i32 9 + call void @llvm.lifetime.start.p0(i64 10, ptr nonnull %buf.sroa.0) + call void @llvm.lifetime.end.p0(i64 10, ptr nonnull %buf.sroa.0) + call void @llvm.lifetime.start.p0(i64 10, ptr nonnull %buf.sroa.1) + call void @llvm.memmove.p0.p0.i32(ptr %ptr, ptr %ptr1, i32 1, i1 true) + call void @llvm.lifetime.end.p0(i64 10, ptr nonnull %buf.sroa.1) + ret i32 0 +} + +; Check an alloca with potentially out of range GEP to ensure it gets a tag and +; check. +define i32 @test_potentially_out_of_range(ptr %a) sanitize_hwaddress { +entry: + ; CHECK-LABEL: @test_potentially_out_of_range + ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_store + ; SAFETY: call {{.*}}__hwasan_generate_tag + ; SAFETY: call {{.*}}__hwasan_store + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK-NOT: call {{.*}}__hwasan_store + %buf.sroa.0 = alloca [10 x i8], align 4 + %off = call i32 @getoffset() + %ptr = getelementptr [10 x i8], ptr %buf.sroa.0, i32 0, i32 %off + call void @llvm.lifetime.start.p0(i64 10, ptr nonnull %ptr) + store volatile i8 0, ptr %ptr, align 4, !tbaa !8 + call void @llvm.lifetime.end.p0(i64 10, ptr nonnull %ptr) + ret i32 0 +} + +define i32 @test_potentially_out_of_range2(ptr %a) sanitize_hwaddress { +entry: + ; CHECK-LABEL: @test_potentially_out_of_range2 + ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_memmove + ; SAFETY-NOT: call {{.*}}__hwasan_generate_tag + ; SAFETY: call {{.*}}__hwasan_memmove + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK: call {{.*}}__hwasan_memmove + %buf.sroa.0 = alloca [10 x i8], align 4 + %ptr = getelementptr [10 x i8], ptr %buf.sroa.0, i32 0, i32 9 + call void @llvm.memmove.p0.p0.i32(ptr %ptr, ptr %a, i32 1, i1 true) + ret i32 0 +} +; Check an alloca with potentially out of range GEP to ensure it gets a tag and +; check. +define i32 @test_unclear(ptr %a) sanitize_hwaddress { +entry: + ; CHECK-LABEL: @test_unclear + ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_store + ; SAFETY: call {{.*}}__hwasan_generate_tag + ; SAFETY: call {{.*}}__hwasan_store + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK: call {{.*}}__hwasan_store + %buf.sroa.0 = alloca i8, align 4 + %ptr = call ptr @getptr(ptr %buf.sroa.0) + call void @llvm.lifetime.start.p0(i64 10, ptr nonnull %ptr) + store volatile i8 0, ptr %ptr, align 4, !tbaa !8 + call void @llvm.lifetime.end.p0(i64 10, ptr nonnull %ptr) + ret i32 0 +} + +define i32 @test_select(ptr %a) sanitize_hwaddress { +entry: + ; CHECK-LABEL: @test_select + ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_store + ; SAFETY: call {{.*}}__hwasan_generate_tag + ; SAFETY: call {{.*}}__hwasan_store + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK: call {{.*}}__hwasan_store + %x = call ptr @getptr(ptr %a) + %buf.sroa.0 = alloca i8, align 4 + call void @llvm.lifetime.start.p0(i64 1, ptr nonnull %buf.sroa.0) + %c = call i1 @cond() + %ptr = select i1 %c, ptr %x, ptr %buf.sroa.0 + store volatile i8 0, ptr %ptr, align 4, !tbaa !8 + call void @llvm.lifetime.end.p0(i64 1, ptr nonnull %buf.sroa.0) + ret i32 0 +} + +; Check whether we see through the returns attribute of functions. +define i32 @test_retptr(ptr %a) sanitize_hwaddress { +entry: + ; CHECK-LABEL: @test_retptr + ; NOSAFETY: call {{.*}}__hwasan_generate_tag + ; NOSAFETY: call {{.*}}__hwasan_store + ; SAFETY: call {{.*}}__hwasan_generate_tag + ; SAFETY-NOT: call {{.*}}__hwasan_store + ; NOSTACK-NOT: call {{.*}}__hwasan_generate_tag + ; NOSTACK-NOT: call {{.*}}__hwasan_store + %buf.sroa.0 = alloca i8, align 4 + call void @llvm.lifetime.start.p0(i64 1, ptr nonnull %buf.sroa.0) + %ptr = call ptr @retptr(ptr %buf.sroa.0) + store volatile i8 0, ptr %ptr, align 4, !tbaa !8 + call void @llvm.lifetime.end.p0(i64 1, ptr nonnull %buf.sroa.0) + ret i32 0 +} + +; Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn +declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) + +; Function Attrs: argmemonly mustprogress nofree nosync nounwind willreturn +declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) + +declare void @llvm.memset.p0.i32(ptr, i8, i32, i1) +declare void @llvm.memcpy.p0.p0.i32(ptr, ptr, i32, i1) +declare void @llvm.memmove.p0.p0.i32(ptr, ptr, i32, i1) + +declare i1 @cond() +declare void @use(ptr nocapture) +declare i32 @getoffset() +declare ptr @getptr(ptr nocapture) +declare ptr @retptr(ptr returned) + +!8 = !{!9, !9, i64 0} +!9 = !{!"omnipotent char", !10, i64 0} +!10 = !{!"Simple C/C++ TBAA"} diff --git a/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/use-after-scope-setjmp.ll b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/use-after-scope-setjmp.ll new file mode 100644 index 0000000..0f50ee7 --- /dev/null +++ b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/use-after-scope-setjmp.ll @@ -0,0 +1,42 @@ +; RUN: opt -passes=hwasan -hwasan-use-stack-safety=0 -hwasan-use-after-scope -S < %s | FileCheck %s +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" +target triple = "riscv64-unknown-linux" + +@stackbuf = dso_local local_unnamed_addr global ptr null, align 8 +@jbuf = dso_local global [32 x i64] zeroinitializer, align 8 + +declare void @may_jump() + +define dso_local noundef i1 @_Z6targetv() sanitize_hwaddress { +entry: + %buf = alloca [4096 x i8], align 1 + %call = call i32 @setjmp(ptr noundef @jbuf) + switch i32 %call, label %while.body [ + i32 1, label %return + i32 2, label %sw.bb1 + ] + +sw.bb1: ; preds = %entry + br label %return + +while.body: ; preds = %entry + call void @llvm.lifetime.start.p0(i64 4096, ptr nonnull %buf) #10 + store ptr %buf, ptr @stackbuf, align 8 + ; may_jump may call longjmp, going back to the switch (and then the return), + ; bypassing the lifetime.end. This is why we need to untag on the return, + ; rather than the lifetime.end. + call void @may_jump() + call void @llvm.lifetime.end.p0(i64 4096, ptr nonnull %buf) #10 + br label %return + +; CHECK-LABEL: return: +; CHECK: void @llvm.memset.p0.i64({{.*}}, i8 0, i64 256, i1 false) +return: ; preds = %entry, %while.body, %sw.bb1 + %retval.0 = phi i1 [ true, %while.body ], [ true, %sw.bb1 ], [ false, %entry ] + ret i1 %retval.0 +} + +declare i32 @setjmp(ptr noundef) returns_twice + +declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) +declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) diff --git a/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/with-calls.ll b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/with-calls.ll new file mode 100644 index 0000000..8cf3626 --- /dev/null +++ b/llvm/test/Instrumentation/HWAddressSanitizer/RISCV/with-calls.ll @@ -0,0 +1,203 @@ +; Test basic address sanitizer instrumentation. +; +; RUN: opt < %s -passes=hwasan -hwasan-instrument-with-calls -S | FileCheck %s --check-prefixes=CHECK,ABORT +; RUN: opt < %s -passes=hwasan -hwasan-instrument-with-calls -hwasan-recover=1 -S | FileCheck %s --check-prefixes=CHECK,RECOVER + +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" +target triple = "riscv64-unknown-linux" + +define i8 @test_load8(ptr %a) sanitize_hwaddress { +; CHECK-LABEL: @test_load8( +; CHECK: %[[A:[^ ]*]] = ptrtoint ptr %a to i64 +; ABORT: call void @__hwasan_load1(i64 %[[A]]) +; RECOVER: call void @__hwasan_load1_noabort(i64 %[[A]]) +; CHECK: %[[B:[^ ]*]] = load i8, ptr %a +; CHECK: ret i8 %[[B]] + +entry: + %b = load i8, ptr %a, align 4 + ret i8 %b +} + +define i16 @test_load16(ptr %a) sanitize_hwaddress { +; CHECK-LABEL: @test_load16( +; CHECK: %[[A:[^ ]*]] = ptrtoint ptr %a to i64 +; ABORT: call void @__hwasan_load2(i64 %[[A]]) +; RECOVER: call void @__hwasan_load2_noabort(i64 %[[A]]) +; CHECK: %[[B:[^ ]*]] = load i16, ptr %a +; CHECK: ret i16 %[[B]] + +entry: + %b = load i16, ptr %a, align 4 + ret i16 %b +} + +define i32 @test_load32(ptr %a) sanitize_hwaddress { +; CHECK-LABEL: @test_load32( +; CHECK: %[[A:[^ ]*]] = ptrtoint ptr %a to i64 +; ABORT: call void @__hwasan_load4(i64 %[[A]]) +; RECOVER: call void @__hwasan_load4_noabort(i64 %[[A]]) +; CHECK: %[[B:[^ ]*]] = load i32, ptr %a +; CHECK: ret i32 %[[B]] + +entry: + %b = load i32, ptr %a, align 4 + ret i32 %b +} + +define i64 @test_load64(ptr %a) sanitize_hwaddress { +; CHECK-LABEL: @test_load64( +; CHECK: %[[A:[^ ]*]] = ptrtoint ptr %a to i64 +; ABORT: call void @__hwasan_load8(i64 %[[A]]) +; RECOVER: call void @__hwasan_load8_noabort(i64 %[[A]]) +; CHECK: %[[B:[^ ]*]] = load i64, ptr %a +; CHECK: ret i64 %[[B]] + +entry: + %b = load i64, ptr %a, align 8 + ret i64 %b +} + +define i128 @test_load128(ptr %a) sanitize_hwaddress { +; CHECK-LABEL: @test_load128( +; CHECK: %[[A:[^ ]*]] = ptrtoint ptr %a to i64 +; ABORT: call void @__hwasan_load16(i64 %[[A]]) +; RECOVER: call void @__hwasan_load16_noabort(i64 %[[A]]) +; CHECK: %[[B:[^ ]*]] = load i128, ptr %a +; CHECK: ret i128 %[[B]] + +entry: + %b = load i128, ptr %a, align 16 + ret i128 %b +} + +define i40 @test_load40(ptr %a) sanitize_hwaddress { +; CHECK-LABEL: @test_load40( +; CHECK: %[[A:[^ ]*]] = ptrtoint ptr %a to i64 +; ABORT: call void @__hwasan_loadN(i64 %[[A]], i64 5) +; RECOVER: call void @__hwasan_loadN_noabort(i64 %[[A]], i64 5) +; CHECK: %[[B:[^ ]*]] = load i40, ptr %a +; CHECK: ret i40 %[[B]] + +entry: + %b = load i40, ptr %a, align 4 + ret i40 %b +} + +define void @test_store8(ptr %a, i8 %b) sanitize_hwaddress { +; CHECK-LABEL: @test_store8( +; CHECK: %[[A:[^ ]*]] = ptrtoint ptr %a to i64 +; ABORT: call void @__hwasan_store1(i64 %[[A]]) +; RECOVER: call void @__hwasan_store1_noabort(i64 %[[A]]) +; CHECK: store i8 %b, ptr %a +; CHECK: ret void + +entry: + store i8 %b, ptr %a, align 4 + ret void +} + +define void @test_store16(ptr %a, i16 %b) sanitize_hwaddress { +; CHECK-LABEL: @test_store16( +; CHECK: %[[A:[^ ]*]] = ptrtoint ptr %a to i64 +; ABORT: call void @__hwasan_store2(i64 %[[A]]) +; RECOVER: call void @__hwasan_store2_noabort(i64 %[[A]]) +; CHECK: store i16 %b, ptr %a +; CHECK: ret void + +entry: + store i16 %b, ptr %a, align 4 + ret void +} + +define void @test_store32(ptr %a, i32 %b) sanitize_hwaddress { +; CHECK-LABEL: @test_store32( +; CHECK: %[[A:[^ ]*]] = ptrtoint ptr %a to i64 +; ABORT: call void @__hwasan_store4(i64 %[[A]]) +; RECOVER: call void @__hwasan_store4_noabort(i64 %[[A]]) +; CHECK: store i32 %b, ptr %a +; CHECK: ret void + +entry: + store i32 %b, ptr %a, align 4 + ret void +} + +define void @test_store64(ptr %a, i64 %b) sanitize_hwaddress { +; CHECK-LABEL: @test_store64( +; CHECK: %[[A:[^ ]*]] = ptrtoint ptr %a to i64 +; ABORT: call void @__hwasan_store8(i64 %[[A]]) +; RECOVER: call void @__hwasan_store8_noabort(i64 %[[A]]) +; CHECK: store i64 %b, ptr %a +; CHECK: ret void + +entry: + store i64 %b, ptr %a, align 8 + ret void +} + +define void @test_store128(ptr %a, i128 %b) sanitize_hwaddress { +; CHECK-LABEL: @test_store128( +; CHECK: %[[A:[^ ]*]] = ptrtoint ptr %a to i64 +; ABORT: call void @__hwasan_store16(i64 %[[A]]) +; RECOVER: call void @__hwasan_store16_noabort(i64 %[[A]]) +; CHECK: store i128 %b, ptr %a +; CHECK: ret void + +entry: + store i128 %b, ptr %a, align 16 + ret void +} + +define void @test_store40(ptr %a, i40 %b) sanitize_hwaddress { +; CHECK-LABEL: @test_store40( +; CHECK: %[[A:[^ ]*]] = ptrtoint ptr %a to i64 +; ABORT: call void @__hwasan_storeN(i64 %[[A]], i64 5) +; RECOVER: call void @__hwasan_storeN_noabort(i64 %[[A]], i64 5) +; CHECK: store i40 %b, ptr %a +; CHECK: ret void + +entry: + store i40 %b, ptr %a, align 4 + ret void +} + +define i8 @test_load_noattr(ptr %a) { +; CHECK-LABEL: @test_load_noattr( +; CHECK-NEXT: entry: +; CHECK-NEXT: %[[B:[^ ]*]] = load i8, ptr %a +; CHECK-NEXT: ret i8 %[[B]] + +entry: + %b = load i8, ptr %a, align 4 + ret i8 %b +} + +define i8 @test_load_notmyattr(ptr %a) sanitize_address { +; CHECK-LABEL: @test_load_notmyattr( +; CHECK-NEXT: entry: +; CHECK-NEXT: %[[B:[^ ]*]] = load i8, ptr %a +; CHECK-NEXT: ret i8 %[[B]] + +entry: + %b = load i8, ptr %a, align 4 + ret i8 %b +} + +define i8 @test_load_addrspace(ptr addrspace(256) %a) sanitize_hwaddress { +; CHECK-LABEL: @test_load_addrspace( +; CHECK-NEXT: entry: +; CHECK-NEXT: %[[B:[^ ]*]] = load i8, ptr addrspace(256) %a +; CHECK-NEXT: ret i8 %[[B]] + +entry: + %b = load i8, ptr addrspace(256) %a, align 4 + ret i8 %b +} + +; CHECK: declare void @__hwasan_init() + +; CHECK: define internal void @hwasan.module_ctor() #[[#]] comdat { +; CHECK-NEXT: call void @__hwasan_init() +; CHECK-NEXT: ret void +; CHECK-NEXT: }