From 42948ecb32a711a420d2b15d4ad396f73f69e48b Mon Sep 17 00:00:00 2001 From: Nikolai Kholiavin Date: Mon, 20 Nov 2023 16:40:59 +0000 Subject: [PATCH] [OHOS][CFI] Print potentially demangled vtable symbol in CFI non-trapping mode Issue: https://gitee.com/openharmony/third_party_llvm-project/issues/I8BEJ6 Signed-off-by: Nikolai Kholiavin --- compiler-rt/lib/ubsan/ubsan_diag.cpp | 10 ++++ compiler-rt/lib/ubsan/ubsan_diag.h | 2 + compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp | 46 +++++++++++++++++-- .../test/cfi/no-cfi-vtable-diagnostic.cpp | 31 +++++++++++++ compiler-rt/test/cfi/no-rtti-diagnostic.cpp | 30 ++++++++++++ 5 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 compiler-rt/test/cfi/no-cfi-vtable-diagnostic.cpp create mode 100644 compiler-rt/test/cfi/no-rtti-diagnostic.cpp diff --git a/compiler-rt/lib/ubsan/ubsan_diag.cpp b/compiler-rt/lib/ubsan/ubsan_diag.cpp index 3673e66539d0..51bb3dca0a0f 100644 --- a/compiler-rt/lib/ubsan/ubsan_diag.cpp +++ b/compiler-rt/lib/ubsan/ubsan_diag.cpp @@ -115,6 +115,16 @@ SymbolizedStack *__ubsan::getSymbolizedLocation(uptr PC) { return Symbolizer::GetOrInit()->SymbolizePC(PC); } +bool __ubsan::getSymbolizedData(uptr Addr, DataInfo *Info) { + InitAsStandaloneIfNecessary(); + return Symbolizer::GetOrInit()->SymbolizeData(Addr, Info); +} + +const char *__ubsan::demangle(const char *Name) { + InitAsStandaloneIfNecessary(); + return Symbolizer::GetOrInit()->Demangle(Name); +} + Diag &Diag::operator<<(const TypeDescriptor &V) { return AddArg(V.getTypeName()); } diff --git a/compiler-rt/lib/ubsan/ubsan_diag.h b/compiler-rt/lib/ubsan/ubsan_diag.h index b444e971b228..6b964643df1f 100644 --- a/compiler-rt/lib/ubsan/ubsan_diag.h +++ b/compiler-rt/lib/ubsan/ubsan_diag.h @@ -39,6 +39,8 @@ public: }; SymbolizedStack *getSymbolizedLocation(uptr PC); +bool getSymbolizedData(uptr Addr, DataInfo *Info); +const char *demangle(const char *Name); inline SymbolizedStack *getCallerLocation(uptr CallerPC) { CHECK(CallerPC); diff --git a/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp b/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp index 2a6d558de034..8f52952c36d3 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp +++ b/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp @@ -94,6 +94,31 @@ void __ubsan::__ubsan_handle_dynamic_type_cache_miss_abort( Die(); } +static bool StartsWith(const char *Str, const char *Pattern, uptr PatternLen) { + return internal_strncmp(Str, Pattern, PatternLen) == 0; +} +static bool EndsWith(const char *Str, uptr StrLen, const char *Pattern, uptr PatternLen) { + return (StrLen >= PatternLen) && + (internal_strcmp(Str + StrLen - PatternLen, Pattern) == 0); +} + +static const char *UndecorateCfiTypeIdSymbol(char *Str) { + const char StartPattern[] = "__typeid_"; + const char EndPattern[] = "_global_addr"; + auto StartPatternLen = sizeof(StartPattern) - 1; + auto EndPatternLen = sizeof(EndPattern) - 1; + + uptr Len = internal_strlen(Str); + if (Len > StartPatternLen + EndPatternLen && + StartsWith(Str, StartPattern, StartPatternLen) && + EndsWith(Str, Len, EndPattern, EndPatternLen)) { + Str[Len - EndPatternLen] = 0; + Str += StartPatternLen; + return common_flags()->demangle ? demangle(Str) : Str; + } + return nullptr; +} + namespace __ubsan { void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable, bool ValidVtable, ReportOptions Opts) { @@ -136,11 +161,26 @@ void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable, << Data->Type << CheckKindStr << (void *)Vtable; // If possible, say what type it actually points to. - if (!DTI.isValid()) - Diag(Vtable, DL_Note, ET, "invalid vtable"); - else + DataInfo VtableDataInfo; + if (DTI.isValid()) { Diag(Vtable, DL_Note, ET, "vtable is of type %0") << TypeName(DTI.getMostDerivedTypeName()); + } else if (getSymbolizedData(Vtable, &VtableDataInfo) && + VtableDataInfo.name) { + if (ValidVtable) { + const char *PrintedName = VtableDataInfo.name; + if (auto *Undecorated = UndecorateCfiTypeIdSymbol(VtableDataInfo.name)) + PrintedName = Undecorated; + Diag(Vtable, DL_Note, ET, "vtable CFI typeid is (or aliases) %0`%1") + << VtableDataInfo.module << PrintedName; + } else { + Diag(Vtable, DL_Note, ET, "invalid vtable (address points to %0`%1)") + << VtableDataInfo.module << VtableDataInfo.name; + } + } else { + Diag(Vtable, DL_Note, ET, "invalid vtable"); + } + VtableDataInfo.Clear(); // If the failure involved different DSOs for the check location and vtable, // report the DSO names. diff --git a/compiler-rt/test/cfi/no-cfi-vtable-diagnostic.cpp b/compiler-rt/test/cfi/no-cfi-vtable-diagnostic.cpp new file mode 100644 index 000000000000..b2b8b35c206b --- /dev/null +++ b/compiler-rt/test/cfi/no-cfi-vtable-diagnostic.cpp @@ -0,0 +1,31 @@ +// Check that diagnostics print the vtable symbol name, when it doesn't have CFI typeid + +// RUN: %clangxx -fno-sanitize=cfi -fno-lto -g -DSTATIC_LIB -c -o %t_static.o %s +// RUN: %clangxx_cfi_diag -g -o %t_exe_suffix %s %t_static.o +// RUN: %t_exe_suffix 2>&1 | FileCheck %s + +// REQUIRES: cxxabi + +struct S1 { + S1(); + virtual void f1(); +}; + +#ifdef STATIC_LIB + +S1::S1() = default; + +void S1::f1() {} + +#else + +int main() { + S1 *S = new S1(); + // CHECK: runtime error: control flow integrity check for type 'S1' failed during virtual call + // CHECK: note: invalid vtable (address points to {{.*}}vtable for S1) + S->f1(); // trigger cfi-vcall failure + + return 0; +} + +#endif // SHARED_LIB diff --git a/compiler-rt/test/cfi/no-rtti-diagnostic.cpp b/compiler-rt/test/cfi/no-rtti-diagnostic.cpp new file mode 100644 index 000000000000..5e04fc9c5149 --- /dev/null +++ b/compiler-rt/test/cfi/no-rtti-diagnostic.cpp @@ -0,0 +1,30 @@ +// Check that diagnostics print CFI typeid names when RTTI is disabled + +// RUN: %clangxx_cfi_diag -g -fno-rtti -o %t1 %s +// RUN: %t1 2>&1 | FileCheck %s + +// REQUIRES: cxxabi + +struct S1 { + virtual void f1() {} +}; + +struct S2 { + virtual void f2() {} +}; + +// One of the CFI typeids aliases all-vtables symbol, so trigger two checks +void f(S1 *S1p, S2 *S2p) { + // CHECK-DAG: runtime error: control flow integrity check for type 'S1' failed during cast to unrelated type + // CHECK-DAG: runtime error: control flow integrity check for type 'S2' failed during cast to unrelated type + // CHECK-DAG: vtable CFI typeid is (or aliases) {{.*}}typeinfo name for S + S2 *S2cast = reinterpret_cast(S1p); // trigger cfi-unrelated-cast failure + S1 *S1cast = reinterpret_cast(S2p); // trigger cfi-unrelated-cast failure +} + +int main() { + S1 S1v; + S2 S2v; + f(&S1v, &S2v); + return 0; +} -- Gitee