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 | ||
|---|---|---|
| 1049 ↗ | (On Diff #457420) | remove if not needed any more |
| 1051 ↗ | (On Diff #457420) | declare at the first point of use |
| 1055 ↗ | (On Diff #457420) | "can not" ? |
| 1062 ↗ | (On Diff #457420) | hmmm... is it even possible? |
| 1071–1072 ↗ | (On Diff #457420) | typical LLVM code uses this: if (CallBase *CB = ...)) { ...} |
| llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp | ||
|---|---|---|
| 1055 ↗ | (On Diff #457420) | Actually I started with "can not", but saw the error message from opt saying "may not". Changing anyways :) |
| 1062 ↗ | (On Diff #457420) | 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 | ||
|---|---|---|
| 1062 ↗ | (On Diff #457420) | yea, please simplify. ok to leave an assert |
| llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp | ||
|---|---|---|
| 1062 ↗ | (On Diff #457420) | Happy to! |
| llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp | ||
|---|---|---|
| 1049 ↗ | (On Diff #457420) | something more specific, or just remove it? |
| 1055 ↗ | (On Diff #457420) | what does happen? |
| 1056 ↗ | (On Diff #457420) | Here, I guess, "C ? A : B" operator is nicer |
| 1057 ↗ | (On Diff #457420) | static_cast or dyn_cast |
| 1086–1087 ↗ | (On Diff #457420) | |
| 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 | ||
|---|---|---|
| 4 ↗ | (On Diff #457754) | this code does not use assertions, so this this flag is not needed |
| 4 ↗ | (On Diff #457754) | similar tests set REQUIRES: has_sancovcc,stable-runtime |
| 11 ↗ | (On Diff #457754) | 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 |
| 38 ↗ | (On Diff #457754) | you can use |
| llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp | ||
| 1063 ↗ | (On Diff #457754) | wouldn't be better to prefix with count instead of separator? |
| 1064 ↗ | (On Diff #457754) | |
| 1077 ↗ | (On Diff #457754) | getNullValue |
| 1057 ↗ | (On Diff #457420) | Then keep as-is in this patch |
| clang/docs/SanitizerCoverage.rst | ||
|---|---|---|
| 338 ↗ | (On Diff #457754) | 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 | ||
| 1048 ↗ | (On Diff #457754) | 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. |
| 1080 ↗ | (On Diff #457754) | -Wunused-variable |
| 1081 ↗ | (On Diff #457754) | 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 | ||
|---|---|---|
| 807 ↗ | (On Diff #458321) | shouldn't this be: probably even: |
| clang/lib/Driver/SanitizerArgs.cpp | ||
|---|---|---|
| 807 ↗ | (On Diff #458321) |
|
| clang/docs/SanitizerCoverage.rst | ||
|---|---|---|
| 382 ↗ | (On Diff #459157) | 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 | ||
| 814 ↗ | (On Diff #459157) | 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 | ||
|---|---|---|
| 814 ↗ | (On Diff #459157) | 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. |
| 807 ↗ | (On Diff #458321) |
This makes sense, thanks! |
| clang/docs/SanitizerCoverage.rst | ||
|---|---|---|
| 382 ↗ | (On Diff #459157) | 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 | ||
|---|---|---|
| 1 ↗ | (On Diff #459201) | I suggest to make this test smaller:
|
LGTM as-is
| compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_control_flow.cpp | ||
|---|---|---|
| 15 ↗ | (On Diff #460215) | 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 | ||
|---|---|---|
| 15 ↗ | (On Diff #460215) |
I'm not sure I follow what you are suggesting. |
| compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_control_flow.cpp | ||
|---|---|---|
| 24 ↗ | (On Diff #460232) | syntax nit: auto main_ptr = &main |
| 33 ↗ | (On Diff #460232) | I suggest you move this to a separate function, called from main() |
| 67 ↗ | (On Diff #460232) | I don't think you are guaranteed to have main and foo in this order, and similarly dir vs indir call in this order. |
| compiler-rt/test/sanitizer_common/TestCases/sanitizer_coverage_control_flow.cpp | ||
|---|---|---|
| 15 ↗ | (On Diff #460215) |
I see, thanks for the pointer. I think I leave it for later. |
| llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp | ||
|---|---|---|
| 155 ↗ | (On Diff #460518) | false can be removed |
| llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp | ||
|---|---|---|
| 155 ↗ | (On Diff #460518) | I'll keep it for consistency with the rest of file |
End complete sentences in comments with .