Details
- Reviewers
kcc vitalybuka MaskRay - Commits
- rG3e52c0926c22: Add -fsanitizer-coverage=control-flow
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
Cool!
please add the documentation and the run-time test to the same CL.
A'll let Vitaly do the next pass of the code, but will review the documentation.
| llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp | ||
|---|---|---|
| 1062 | remove if not needed any more | |
| 1064 | declare at the first point of use | |
| 1068 | "can not" ? | |
| 1075 | hmmm... is it even possible? | |
| 1084–1085 | typical LLVM code uses this: if (CallBase *CB = ...)) { ...} | |
| llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp | ||
|---|---|---|
| 1068 | Actually I started with "can not", but saw the error message from opt saying "may not". Changing anyways :) | |
| 1075 | I was being cautious here for the branches (like goto) to the beginning of the function. something like the following code breaks the entry basic block: int foo (int x) {
top:
x += 5;
if (x > 5)
bar(x);
else
goto top;
return x;
}define dso_local i32 @foo(i32 noundef %x) #0 {
entry:
%x.addr = alloca i32, align 4
store i32 %x, ptr %x.addr, align 4
br label %top
top: ; preds = %if.else, %entry
%0 = load i32, ptr %x.addr, align 4
%add = add nsw i32 %0, 5
store i32 %add, ptr %x.addr, align 4
%1 = load i32, ptr %x.addr, align 4
%cmp = icmp sgt i32 %1, 5
br i1 %cmp, label %if.then, label %if.else
if.then: ; preds = %top
%2 = load i32, ptr %x.addr, align 4
call void @bar(i32 noundef %2)
br label %if.end
if.else: ; preds = %top
br label %top
if.end: ; preds = %if.then
%3 = load i32, ptr %x.addr, align 4
ret i32 %3
}If you think it is impossible, I am fine with simplifying the code here. | |
| llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp | ||
|---|---|---|
| 1075 | yea, please simplify. ok to leave an assert | |
| llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp | ||
|---|---|---|
| 1075 | Happy to! | |
| llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp | ||
|---|---|---|
| 1062 | something more specific, or just remove it? | |
| 1068 | what does happen? | |
| 1069 | Here, I guess, "C ? A : B" operator is nicer | |
| 1070 | static_cast or dyn_cast | |
| 1099–1100 | ||
| llvm/test/Instrumentation/SanitizerCoverage/control-flow.ll | ||
| 3 | you don't have to, but may try to generate test with It could be reasonable, or not | |
| 12 | the test does not cover CallBase | |
Sorry, first time user of arcanist here! The test file is missed from this upgrade somehow :/
| llvm/test/Instrumentation/SanitizerCoverage/control-flow.ll | ||
|---|---|---|
| 3 | Thanks! I tried it and it added many more checks, which does not seem very useful? Please let me know if you see some value in having these: +; CHECK-LABEL: @foo( +; CHECK-NEXT: entry: +; CHECK-NEXT: call void @__sanitizer_cov_trace_pc_guard(i32* getelementptr inbounds ([3 x i32], [3 x i32]* @__sancov_gen_.1, i32 0, i32 0)) #[[ATTR2:[0-9]+]] +; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32* [[A:%.*]], null +; CHECK-NEXT: br i1 [[TOBOOL]], label [[ENTRY_IF_END_CRIT_EDGE:%.*]], label [[IF_THEN:%.*]] +; CHECK: entry.if.end_crit_edge: +; CHECK-NEXT: call void @__sanitizer_cov_trace_pc_guard(i32* inttoptr (i64 add (i64 ptrtoint ([3 x i32]* @__sancov_gen_.1 to i64), i64 4) to i32*)) #[[ATTR2]] +; CHECK-NEXT: br label [[IF_END:%.*]] +; CHECK: if.then: +; CHECK-NEXT: call void @__sanitizer_cov_trace_pc_guard(i32* inttoptr (i64 add (i64 ptrtoint ([3 x i32]* @__sancov_gen_.1 to i64), i64 8) to i32*)) #[[ATTR2]] +; CHECK-NEXT: store i32 0, i32* [[A]], align 4 +; CHECK-NEXT: call void @foo(i32* [[A]]) +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: +; CHECK-NEXT: ret void +; | |
| compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_control_flow.cpp | ||
|---|---|---|
| 5 | this code does not use assertions, so this this flag is not needed | |
| 5 | similar tests set REQUIRES: has_sancovcc,stable-runtime | |
| 12 | Could you please move this test into a separate patch, I suspect this one likely than the rest will be reverted of platforms with limited runtime | |
| 76 | you can use | |
| llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp | ||
| 1070 | Then keep as-is in this patch | |
| 1076 | wouldn't be better to prefix with count instead of separator? | |
| 1077 | ||
| 1090 | getNullValue | |
| clang/docs/SanitizerCoverage.rst | ||
|---|---|---|
| 338 | This paragraph doesn't describe how the table is encoded. The description about null-separated is incorrect as it is actually null-ended. | |
| llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp | ||
| 1061 | Use collectFunctionControlFlow for new functions. CamelCaseFunction is legacy. I'd prefer createXXX since collectXXX implies returning the object while the function actually creates the needed metadata. | |
| 1093 | -Wunused-variable | |
| 1094 | I'd avoid the variable in favor of FunctionCFsArray | |
| llvm/test/Instrumentation/SanitizerCoverage/control-flow.ll | ||
| 2 | End complete sentences in comments with . | |
| 7 | Avoid i32*. Use opaque pointers ptr for new tests. | |
| clang/lib/Driver/SanitizerArgs.cpp | ||
|---|---|---|
| 818–819 | shouldn't this be: probably even: | |
| clang/lib/Driver/SanitizerArgs.cpp | ||
|---|---|---|
| 818–819 |
| |
| clang/docs/SanitizerCoverage.rst | ||
|---|---|---|
| 382 | we can also generate normal structs, per function, and pass them into __sanitizer_cov_cfs_init(const MyStruct* begin, const MyStruct* end); | |
| clang/lib/Driver/SanitizerArgs.cpp | ||
| 826 | why do you need CoverageEdge if enabled CoverageControlFlow? | |
we need to update
llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_coverage_interface.inc
llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_interface_internal.h
you can search by __sanitizer_cov_8bit_counters_init if anything missing
Something like SingletonCounterCoverage could be useful.
Bring back the runtime test.
| clang/lib/Driver/SanitizerArgs.cpp | ||
|---|---|---|
| 818–819 |
This makes sense, thanks! | |
| 826 | No essential need, but here I am implicitly enabling edge when instrumentation type is not specified. This was the way that I could get -fsanitizer-coverage=control-flow working without passing -fsanitizer-coverage=bb,control-flow. | |
| clang/docs/SanitizerCoverage.rst | ||
|---|---|---|
| 382 | The struct will still have some variable length arrays, right? MyStruct will have to be defined there, and there is no header file for sancov for users to include, and I don't think I want one. | |
| compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_control_flow.cpp | ||
|---|---|---|
| 2 | I suggest to make this test smaller:
| |
LGTM as-is
| compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_control_flow.cpp | ||
|---|---|---|
| 16 | actually printing can be don't in follow up patch, but it may simplify the test, you will not need iterate it in the test. | |
| compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_control_flow.cpp | ||
|---|---|---|
| 16 |
I'm not sure I follow what you are suggesting. | |
| compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_control_flow.cpp | ||
|---|---|---|
| 25 | syntax nit: auto main_ptr = &main | |
| 34 | I suggest you move this to a separate function, called from main() | |
| 68 | I don't think you are guaranteed to have main and foo in this order, and similarly dir vs indir call in this order. | |
| llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp | ||
|---|---|---|
| 156 | false can be removed | |
| llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp | ||
|---|---|---|
| 156 | I'll keep it for consistency with the rest of file | |
This paragraph doesn't describe how the table is encoded.
The description about null-separated is incorrect as it is actually null-ended.