Index: compiler-rt/trunk/lib/ubsan/ubsan_handlers.h =================================================================== --- compiler-rt/trunk/lib/ubsan/ubsan_handlers.h +++ compiler-rt/trunk/lib/ubsan/ubsan_handlers.h @@ -148,6 +148,14 @@ /// \brief Handle passing null pointer to function with nonnull attribute. RECOVERABLE(nonnull_arg, NonNullArgData *Data) +struct CFIBadIcallData { + SourceLocation Loc; + const TypeDescriptor &Type; +}; + +/// \brief Handle control flow integrity failure for indirect function calls. +RECOVERABLE(cfi_bad_icall, CFIBadIcallData *Data, ValueHandle Function) + } #endif // UBSAN_HANDLERS_H Index: compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc =================================================================== --- compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc +++ compiler-rt/trunk/lib/ubsan/ubsan_handlers.cc @@ -473,4 +473,36 @@ Die(); } +static void handleCFIBadIcall(CFIBadIcallData *Data, ValueHandle Function, + ReportOptions Opts) { + SourceLocation Loc = Data->Loc.acquire(); + if (ignoreReport(Loc, Opts)) + return; + + ScopedReport R(Opts, Loc); + + Diag(Loc, DL_Error, "control flow integrity check for type %0 failed during " + "indirect function call") + << Data->Type; + + SymbolizedStackHolder FLoc(getSymbolizedLocation(Function)); + const char *FName = FLoc.get()->info.function; + if (!FName) + FName = "(unknown)"; + Diag(FLoc, DL_Note, "%0 defined here") << FName; +} + +void __ubsan::__ubsan_handle_cfi_bad_icall(CFIBadIcallData *Data, + ValueHandle Function) { + GET_REPORT_OPTIONS(false); + handleCFIBadIcall(Data, Function, Opts); +} + +void __ubsan::__ubsan_handle_cfi_bad_icall_abort(CFIBadIcallData *Data, + ValueHandle Function) { + GET_REPORT_OPTIONS(true); + handleCFIBadIcall(Data, Function, Opts); + Die(); +} + #endif // CAN_SANITIZE_UB Index: compiler-rt/trunk/test/cfi/bad-signature.c =================================================================== --- compiler-rt/trunk/test/cfi/bad-signature.c +++ compiler-rt/trunk/test/cfi/bad-signature.c @@ -0,0 +1,27 @@ +// RUN: %clangxx -o %t1 %s +// RUN: %t1 2>&1 | FileCheck --check-prefix=NCFI %s + +// RUN: %clangxx_cfi -o %t2 %s +// RUN: %expect_crash %t2 2>&1 | FileCheck --check-prefix=CFI %s + +// RUN: %clangxx_cfi_diag -g -o %t3 %s +// RUN: %t3 2>&1 | FileCheck --check-prefix=CFI-DIAG %s + +#include + +void f() { +} + +int main() { + // CFI: 1 + // NCFI: 1 + fprintf(stderr, "1\n"); + + // CFI-DIAG: runtime error: control flow integrity check for type 'void (int)' failed during indirect function call + // CFI-DIAG: f() defined here + ((void (*)(int))f)(42); // UB here + + // CFI-NOT: 2 + // NCFI: 2 + fprintf(stderr, "2\n"); +} Index: compiler-rt/trunk/test/cfi/external-call.c =================================================================== --- compiler-rt/trunk/test/cfi/external-call.c +++ compiler-rt/trunk/test/cfi/external-call.c @@ -0,0 +1,23 @@ +// RUN: %clangxx_cfi -o %t1 %s +// RUN: %t1 c 1 2>&1 | FileCheck --check-prefix=CFI %s +// RUN: %t1 s 2 2>&1 | FileCheck --check-prefix=CFI %s + +#include +#include +#include + +int main(int argc, char **argv) { + // CFI: 1 + fprintf(stderr, "1\n"); + + double (*fn)(double); + if (argv[1][0] == 's') + fn = sin; + else + fn = cos; + + fn(atof(argv[2])); + + // CFI: 2 + fprintf(stderr, "2\n"); +} Index: compiler-rt/trunk/test/cfi/lit.cfg =================================================================== --- compiler-rt/trunk/test/cfi/lit.cfg +++ compiler-rt/trunk/test/cfi/lit.cfg @@ -2,7 +2,7 @@ import os config.name = 'cfi' -config.suffixes = ['.cpp', '.test'] +config.suffixes = ['.c', '.cpp', '.test'] config.test_source_root = os.path.dirname(__file__) clangxx = ' '.join([config.clang] + config.cxx_mode_flags)