Index: lib/ubsan/ubsan_handlers.cc =================================================================== --- lib/ubsan/ubsan_handlers.cc +++ lib/ubsan/ubsan_handlers.cc @@ -660,6 +660,21 @@ if (!FName) FName = "(unknown)"; Diag(FLoc, DL_Note, ET, "%0 defined here") << FName; + + // If the failure involved different DSOs for the check location and icall + // target, report the DSO names. + const char *DstModule = FLoc.get()->info.module; + if (!DstModule) + DstModule = "(unknown)"; + + const char *SrcModule = Symbolizer::GetOrInit()->GetModuleNameForPc(Opts.pc); + if (!SrcModule) + SrcModule = "(unknown)"; + + if (internal_strcmp(SrcModule, DstModule)) + Diag(Loc, DL_Note, ET, + "check failed in %0, destination function located in %1") + << SrcModule << DstModule; } namespace __ubsan { Index: lib/ubsan/ubsan_handlers_cxx.cc =================================================================== --- lib/ubsan/ubsan_handlers_cxx.cc +++ lib/ubsan/ubsan_handlers_cxx.cc @@ -137,16 +137,25 @@ << Data->Type << CheckKindStr << (void *)Vtable; // If possible, say what type it actually points to. - if (!DTI.isValid()) { - const char *module = Symbolizer::GetOrInit()->GetModuleNameForPc(Vtable); - if (module) - Diag(Vtable, DL_Note, ET, "invalid vtable in module %0") << module; - else - Diag(Vtable, DL_Note, ET, "invalid vtable"); - } else { + if (!DTI.isValid()) + Diag(Vtable, DL_Note, ET, "invalid vtable"); + else Diag(Vtable, DL_Note, ET, "vtable is of type %0") << TypeName(DTI.getMostDerivedTypeName()); - } + + // If the failure involved different DSOs for the check location and vtable, + // report the DSO names. + const char *DstModule = Symbolizer::GetOrInit()->GetModuleNameForPc(Vtable); + if (!DstModule) + DstModule = "(unknown)"; + + const char *SrcModule = Symbolizer::GetOrInit()->GetModuleNameForPc(Opts.pc); + if (!SrcModule) + SrcModule = "(unknown)"; + + if (internal_strcmp(SrcModule, DstModule)) + Diag(Loc, DL_Note, ET, "check failed in %0, vtable located in %1") + << SrcModule << DstModule; } } // namespace __ubsan Index: test/cfi/cross-dso-diagnostic.cpp =================================================================== --- test/cfi/cross-dso-diagnostic.cpp +++ test/cfi/cross-dso-diagnostic.cpp @@ -0,0 +1,42 @@ +// Check that cross-DSO diagnostics print the names of both modules + +// RUN: %clangxx_cfi_diag -g -DSHARED_LIB -fPIC -shared -o %t_dso_suffix %s +// RUN: %clangxx_cfi_diag -g -o %t_exe_suffix %s -ldl +// RUN: %t_exe_suffix %t_dso_suffix 2>&1 | FileCheck %s + +// UNSUPPORTED: win32 +// REQUIRES: cxxabi + +#include +#include + +struct S1 { + virtual void f1(); +}; + +#ifdef SHARED_LIB + +void S1::f1() {} + +__attribute__((visibility("default"))) extern "C" +void* dso_symbol() { return new S1(); } + +#else + +int main(int argc, char *argv[]) { + void *handle = dlopen(argv[1], RTLD_NOW); + + // CHECK: runtime error: control flow integrity check for type 'void *()' failed during indirect function call + // CHECK: dso_symbol defined here + // CHECK: check failed in {{.*}}_exe_suffix, destination function located in {{.*}}_dso_suffix + void* (*fp)(void) = + reinterpret_cast(dlsym(handle, "dso_symbol")); + void *S = fp(); // trigger cfi-icall failure + + // CHECK: runtime error: control flow integrity check for type 'S1' failed during cast to unrelated type + // CHECK: invalid vtable + // CHECK: check failed in {{.*}}_exe_suffix, vtable located in {{.*}}_dso_suffix + S1 *Scast = reinterpret_cast(S); // trigger cfi-unrelated-cast failure +} + +#endif // SHARED_LIB