// Tests -fsanitize-coverage=control-flow. // REQUIRES: has_sancovcc,stable-runtime // UNSUPPORTED: i386-darwin, x86_64-darwin // RUN: %clangxx -O0 -std=c++11 -fsanitize-coverage=control-flow %s -o %t // RUN: %run %t 2>&1 | FileCheck %s #include #include #if __has_feature(ptrauth_calls) #include #else #define ptrauth_strip(__value, __key) (__value) #endif uintptr_t *CFS_BEG, *CFS_END; extern "C" void __sanitizer_cov_cfs_init(const uintptr_t *cfs_beg, const uintptr_t *cfs_end) { CFS_BEG = (uintptr_t *)cfs_beg; CFS_END = (uintptr_t *)cfs_end; } __attribute__((noinline)) void foo(int x) { /* empty body */ } void check_cfs_section(uintptr_t main_ptr, uintptr_t foo_ptr) { printf("Control Flow section boundaries: [%p %p)\n", CFS_BEG, CFS_END); uintptr_t *pt = CFS_BEG; uintptr_t currBB; while (pt < CFS_END) { currBB = *pt; pt++; if (currBB == main_ptr) printf("Saw the main().\n"); else if (currBB == foo_ptr) printf("Saw the foo().\n"); // Iterate over successors. while (*pt) { pt++; } pt++; // Iterate over callees. while (*pt) { if (*pt == foo_ptr && currBB != main_ptr) printf("Direct call matched.\n"); if (*pt == -1 && currBB != main_ptr) printf("Indirect call matched.\n"); pt++; } pt++; } } int main() { auto main_ptr = ptrauth_strip(&main, ptrauth_key_function_pointer); auto foo_ptr = ptrauth_strip(&foo, ptrauth_key_function_pointer); int x = 10; if (x > 0) foo(x); else (*foo_ptr)(x); check_cfs_section((uintptr_t)(*main_ptr), (uintptr_t)(*foo_ptr)); printf("Finished!\n"); return 0; } // CHECK: Control Flow section boundaries // CHECK-DAG: Saw the foo(). // CHECK-DAG: Saw the main(). // CHECK-DAG: Direct call matched. // CHECK-DAG: Indirect call matched. // CHECK: Finished!