While trying to get a coverage for sanitizers for my library compiled with Clang 5.0.0 I have encountered a problem that some calls to __sanitizer_coverage_trace_pc_guards
are missing in several basic blocks. I made a reduced reprocase for this and built it with -gline-tables-only -O0 -fsanitize=address -fsanitize-coverage=trace-pc-guard
flags:
clang -gline-tables-only -O0 -fsanitize=address -fsanitize-coverage=trace-pc-guard -S reduced.c
extern void clobber1(int *state_ptr);
extern void clobber2(int *state_ptr);
extern void clobber3(int *state_ptr);
int foo(char c, int state, int threshold) {
while (state < threshold) {
switch (state) {
case 1:
clobber1(&state);
if (c == '*') {
state++;
} else if (c == '/') {
state--; <============== missing __sanitizer_cov_trace_pc_guard call
} else {
clobber1(&state);
goto out;
}
clobber2(&state);
break;
case 2:
clobber3(&state);
break;
}
}
out:
return state;
}
int main(int argc, char **argv) {
return foo(argv[1][2], argc + 4, 255) > 100;
}
After examination of dumped LLVM IR (-print-after-all) I have found that there are no calls of __sanitizer_coverage_trace_pc_guard
in if.then6
basic block that corresponds to else if (c == '/')
fall through case:
sw.bb: ; preds = %while.body
call void @clobber1(i32* %state.addr), !dbg !15
%3 = load i8, i8* %c.addr, align 1, !dbg !16
%conv = sext i8 %3 to i32, !dbg !16
%cmp1 = icmp eq i32 %conv, 42, !dbg !17
br i1 %cmp1, label %if.then, label %if.else, !dbg !16
if.then: ; preds = %sw.bb
call void @__sanitizer_cov_trace_pc_guard(i32* inttoptr (i64 add (i64 ptrtoint ([6 x i32]* @__sancov_gen_ to i64), i64 8) to i32*)), !dbg !18
call void asm sideeffect "", ""(), !dbg !18
%4 = load i32, i32* %state.addr, align 4, !dbg !18
%inc = add nsw i32 %4, 1, !dbg !18
store i32 %inc, i32* %state.addr, align 4, !dbg !18
br label %if.end8, !dbg !19
if.else: ; preds = %sw.bb
%5 = load i8, i8* %c.addr, align 1, !dbg !20
%conv3 = sext i8 %5 to i32, !dbg !20
%cmp4 = icmp eq i32 %conv3, 47, !dbg !21
br i1 %cmp4, label %if.then6, label %if.else7, !dbg !20
if.then6: ; preds = %if.else <======= no __sanitizer_cov_trace_pc_guard
%6 = load i32, i32* %state.addr, align 4, !dbg !22
%dec = add nsw i32 %6, -1, !dbg !22
store i32 %dec, i32* %state.addr, align 4, !dbg !22
br label %if.end, !dbg !23
if.else7: ; preds = %if.else
call void @__sanitizer_cov_trace_pc_guard(i32* inttoptr (i64 add (i64 ptrtoint ([6 x i32]* @__sancov_gen_ to i64), i64 12) to i32*)), !dbg !24
call void asm sideeffect "", ""(), !dbg !24
call void @clobber1(i32* %state.addr), !dbg !24
br label %out, !dbg !25
if.end: ; preds = %if.then6
br label %if.end8
if.end8: ; preds = %if.end, %if.then
call void @clobber2(i32* %state.addr), !dbg !26
br label %sw.epilog, !dbg !27
But, if I remove the goto out
instruction, then __sanitizer_cov_trace_pc_guard
call appears in all if
clauses as expected.
I also reported this issue to [email protected] but haven't got any reply yet:
http://lists.llvm.org/pipermail/llvm-dev/2017-March/111209.html