// 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 <cstdint>
#include <cstdio>
#if __has_feature(ptrauth_calls)
#include <ptrauth.h>
#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!