https://github.com/jakos-sec updated https://github.com/llvm/llvm-project/pull/203341
>From 5244b87126de980a68aa91e260770f195cf11794 Mon Sep 17 00:00:00 2001 From: Jakob Koschel <[email protected]> Date: Thu, 11 Jun 2026 16:52:59 +0000 Subject: [PATCH 1/4] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20in?= =?UTF-8?q?itial=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.7 --- compiler-rt/lib/ubsan/ubsan_checks.inc | 7 +- compiler-rt/lib/ubsan/ubsan_handlers.cpp | 12 +- compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp | 21 +++- compiler-rt/test/cfi/lit.cfg.py | 10 +- compiler-rt/test/cfi/summary.cpp | 111 +++++++++++++++++++ 5 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 compiler-rt/test/cfi/summary.cpp diff --git a/compiler-rt/lib/ubsan/ubsan_checks.inc b/compiler-rt/lib/ubsan/ubsan_checks.inc index b1d09a9024e7e..ebcd5df872d69 100644 --- a/compiler-rt/lib/ubsan/ubsan_checks.inc +++ b/compiler-rt/lib/ubsan/ubsan_checks.inc @@ -69,4 +69,9 @@ UBSAN_CHECK(InvalidNullArgument, "invalid-null-argument", "nonnull-attribute") UBSAN_CHECK(InvalidNullArgumentWithNullability, "invalid-null-argument", "nullability-arg") UBSAN_CHECK(DynamicTypeMismatch, "dynamic-type-mismatch", "vptr") -UBSAN_CHECK(CFIBadType, "cfi-bad-type", "cfi") +UBSAN_CHECK(CFIVCall, "cfi-vcall", "cfi") +UBSAN_CHECK(CFINVCall, "cfi-nvcall", "cfi") +UBSAN_CHECK(CFIDerivedCast, "cfi-derived-cast", "cfi") +UBSAN_CHECK(CFIUnrelatedCast, "cfi-unrelated-cast", "cfi") +UBSAN_CHECK(CFIICall, "cfi-icall", "cfi") +UBSAN_CHECK(CFIMFCall, "cfi-mfcall", "cfi") diff --git a/compiler-rt/lib/ubsan/ubsan_handlers.cpp b/compiler-rt/lib/ubsan/ubsan_handlers.cpp index 2614d49bf238b..0cd8a437adf4d 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers.cpp +++ b/compiler-rt/lib/ubsan/ubsan_handlers.cpp @@ -883,11 +883,19 @@ static SymbolizedStack *removeArtificialFiles(SymbolizedStack *FS) { static void handleCFIBadIcall(CFICheckFailData *Data, ValueHandle Function, ReportOptions Opts) { - if (Data->CheckKind != CFITCK_ICall && Data->CheckKind != CFITCK_NVMFCall) + ErrorType ET; + switch (Data->CheckKind) { + case CFITCK_ICall: + ET = ErrorType::CFIICall; + break; + case CFITCK_NVMFCall: + ET = ErrorType::CFIMFCall; + break; + default: Die(); + } SourceLocation Loc = Data->Loc.acquire(); - ErrorType ET = ErrorType::CFIBadType; if (ignoreReport(Loc, Opts, ET)) return; diff --git a/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp b/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp index 206a0bb485a9c..a1ae0347a6a57 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp +++ b/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp @@ -98,7 +98,26 @@ namespace __ubsan { void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable, bool ValidVtable, ReportOptions Opts) { SourceLocation Loc = Data->Loc.acquire(); - ErrorType ET = ErrorType::CFIBadType; + ErrorType ET; + switch (Data->CheckKind) { + case CFITCK_VCall: + ET = ErrorType::CFIVCall; + break; + case CFITCK_NVCall: + ET = ErrorType::CFINVCall; + break; + case CFITCK_DerivedCast: + ET = ErrorType::CFIDerivedCast; + break; + case CFITCK_UnrelatedCast: + ET = ErrorType::CFIUnrelatedCast; + break; + case CFITCK_VMFCall: + ET = ErrorType::CFIMFCall; + break; + default: + Die(); + } if (ignoreReport(Loc, Opts, ET)) return; diff --git a/compiler-rt/test/cfi/lit.cfg.py b/compiler-rt/test/cfi/lit.cfg.py index c879d7f46e6be..7c60d2a464364 100644 --- a/compiler-rt/test/cfi/lit.cfg.py +++ b/compiler-rt/test/cfi/lit.cfg.py @@ -63,8 +63,14 @@ def build_invocation(compile_flags): else: config.unsupported = True -if config.default_sanitizer_opts: - config.environment["UBSAN_OPTIONS"] = ":".join(config.default_sanitizer_opts) +default_ubsan_opts = list(config.default_sanitizer_opts) if config.default_sanitizer_opts else [] +default_ubsan_opts_str = ":".join(default_ubsan_opts) +if default_ubsan_opts_str: + config.environment["UBSAN_OPTIONS"] = default_ubsan_opts_str + default_ubsan_opts_str += ":" +config.substitutions.append( + ("%env_ubsan_opts=", "env UBSAN_OPTIONS=" + default_ubsan_opts_str) +) if lit_config.params.get("check_supported", None) and config.unsupported: raise BaseException("Tests unsupported") diff --git a/compiler-rt/test/cfi/summary.cpp b/compiler-rt/test/cfi/summary.cpp new file mode 100644 index 0000000000000..492d25fe7b58c --- /dev/null +++ b/compiler-rt/test/cfi/summary.cpp @@ -0,0 +1,111 @@ +// RUN: %clangxx_cfi_diag -g -o %t %s +// RUN: %env_ubsan_opts=print_summary=1:report_error_type=1 %run %t vcall 2>&1 | FileCheck --check-prefix=VCALL %s +// RUN: %env_ubsan_opts=print_summary=1:report_error_type=1 %run %t nvcall 2>&1 | FileCheck --check-prefix=NVCALL %s +// RUN: %env_ubsan_opts=print_summary=1:report_error_type=1 %run %t ucast 2>&1 | FileCheck --check-prefix=UCAST %s +// RUN: %env_ubsan_opts=print_summary=1:report_error_type=1 %run %t dcast 2>&1 | FileCheck --check-prefix=DCAST %s +// RUN: %env_ubsan_opts=print_summary=1:report_error_type=1 %run %t icall 2>&1 | FileCheck --check-prefix=ICALL %s +// RUN: %env_ubsan_opts=print_summary=1:report_error_type=1 %run %t nvmfcall 2>&1 | FileCheck --check-prefix=NVMFCALL %s +// RUN: %env_ubsan_opts=print_summary=1:report_error_type=1 %run %t vmfcall 2>&1 | FileCheck --check-prefix=VMFCALL %s + +// REQUIRES: cxxabi + +#include <stdio.h> +#include <string.h> +#include "utils.h" + +struct A { + virtual void f(); +}; +void A::f() {} + +struct B { + virtual void f(); +}; +void B::f() {} + +struct C : A { + virtual void f(); +}; +void C::f() {} + +struct D { + void f(); // non-virtual + virtual void g(); +}; +void D::f() {} +void D::g() {} + +struct S { + void f(); // non-virtual + virtual void g(); // virtual +}; +void S::f() {} +void S::g() {} + +struct T { + void f(); + virtual void g(); +}; +void T::f() {} +void T::g() {} + +typedef void (S::*S_void)(); +typedef int (S::*S_int)(); + +template <typename To, typename From> +To bitcast(From f) { + To t; + memcpy(&t, &f, sizeof(f)); + return t; +} + +void g() {} + +int main(int argc, char **argv) { + if (argc < 2) return 0; + + create_derivers<B>(); + create_derivers<D>(); + create_derivers<T>(); + + if (strcmp(argv[1], "vcall") == 0) { + A *a = new A; + break_optimization(a); + // VCALL: SUMMARY: UndefinedBehaviorSanitizer: cfi-vcall {{.*}}summary.cpp:[[@LINE+1]] + ((B *)a)->f(); + } else if (strcmp(argv[1], "nvcall") == 0) { + A *a = new A; + break_optimization(a); + // NVCALL: SUMMARY: UndefinedBehaviorSanitizer: cfi-nvcall {{.*}}summary.cpp:[[@LINE+1]] + ((D *)a)->f(); + } else if (strcmp(argv[1], "ucast") == 0) { + A *a = new A; + break_optimization(a); + // UCAST: SUMMARY: UndefinedBehaviorSanitizer: cfi-unrelated-cast {{.*}}summary.cpp:[[@LINE+1]] + B *b = (B *)a; + break_optimization(b); + } else if (strcmp(argv[1], "dcast") == 0) { + A *a = new A; + break_optimization(a); + // DCAST: SUMMARY: UndefinedBehaviorSanitizer: cfi-derived-cast {{.*}}summary.cpp:[[@LINE+1]] + C *c = (C *)a; + break_optimization(c); + } else if (strcmp(argv[1], "icall") == 0) { + void (*fp)() = g; + break_optimization(&fp); + // ICALL: SUMMARY: UndefinedBehaviorSanitizer: cfi-icall {{.*}}summary.cpp:[[@LINE+1]] + ((void (*)(int))fp)(42); + } else if (strcmp(argv[1], "nvmfcall") == 0) { + S s; + break_optimization(&s); + // NVMFCALL: SUMMARY: UndefinedBehaviorSanitizer: cfi-mfcall {{.*}}summary.cpp:[[@LINE+1]] + (s.*bitcast<S_void>(&T::f))(); + } else if (strcmp(argv[1], "vmfcall") == 0) { + S s; + break_optimization(&s); + // VMFCALL: SUMMARY: UndefinedBehaviorSanitizer: cfi-mfcall {{.*}}summary.cpp:[[@LINE+1]] + (s.*bitcast<S_int>(&S::g))(); + } + + return 0; +} >From 2e757b8f83c14666f4a681261b2e25aed064a546 Mon Sep 17 00:00:00 2001 From: Jakob Koschel <[email protected]> Date: Thu, 11 Jun 2026 17:06:48 +0000 Subject: [PATCH 2/4] fix formatting issues Created using spr 1.3.7 --- compiler-rt/test/cfi/lit.cfg.py | 4 +++- compiler-rt/test/cfi/summary.cpp | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/compiler-rt/test/cfi/lit.cfg.py b/compiler-rt/test/cfi/lit.cfg.py index 7c60d2a464364..532521bd9ec02 100644 --- a/compiler-rt/test/cfi/lit.cfg.py +++ b/compiler-rt/test/cfi/lit.cfg.py @@ -63,7 +63,9 @@ def build_invocation(compile_flags): else: config.unsupported = True -default_ubsan_opts = list(config.default_sanitizer_opts) if config.default_sanitizer_opts else [] +default_ubsan_opts = ( + list(config.default_sanitizer_opts) if config.default_sanitizer_opts else [] +) default_ubsan_opts_str = ":".join(default_ubsan_opts) if default_ubsan_opts_str: config.environment["UBSAN_OPTIONS"] = default_ubsan_opts_str diff --git a/compiler-rt/test/cfi/summary.cpp b/compiler-rt/test/cfi/summary.cpp index 492d25fe7b58c..211419d1eafd6 100644 --- a/compiler-rt/test/cfi/summary.cpp +++ b/compiler-rt/test/cfi/summary.cpp @@ -9,9 +9,9 @@ // REQUIRES: cxxabi +#include "utils.h" #include <stdio.h> #include <string.h> -#include "utils.h" struct A { virtual void f(); @@ -36,7 +36,7 @@ void D::f() {} void D::g() {} struct S { - void f(); // non-virtual + void f(); // non-virtual virtual void g(); // virtual }; void S::f() {} @@ -52,8 +52,7 @@ void T::g() {} typedef void (S::*S_void)(); typedef int (S::*S_int)(); -template <typename To, typename From> -To bitcast(From f) { +template <typename To, typename From> To bitcast(From f) { To t; memcpy(&t, &f, sizeof(f)); return t; @@ -62,7 +61,8 @@ To bitcast(From f) { void g() {} int main(int argc, char **argv) { - if (argc < 2) return 0; + if (argc < 2) + return 0; create_derivers<B>(); create_derivers<D>(); >From beb2021c4b136b044e87c5cb136e63f7491d8176 Mon Sep 17 00:00:00 2001 From: Jakob Koschel <[email protected]> Date: Thu, 11 Jun 2026 17:17:52 +0000 Subject: [PATCH 3/4] fix python formatting Created using spr 1.3.7 --- compiler-rt/test/cfi/lit.cfg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler-rt/test/cfi/lit.cfg.py b/compiler-rt/test/cfi/lit.cfg.py index 532521bd9ec02..ad80772e4b936 100644 --- a/compiler-rt/test/cfi/lit.cfg.py +++ b/compiler-rt/test/cfi/lit.cfg.py @@ -64,7 +64,7 @@ def build_invocation(compile_flags): config.unsupported = True default_ubsan_opts = ( - list(config.default_sanitizer_opts) if config.default_sanitizer_opts else [] + list(config.default_sanitizer_opts) if config.default_sanitizer_opts else [] ) default_ubsan_opts_str = ":".join(default_ubsan_opts) if default_ubsan_opts_str: >From 4f0187951d42ce839a5c62337379b17e441336a2 Mon Sep 17 00:00:00 2001 From: Jakob Koschel <[email protected]> Date: Fri, 12 Jun 2026 07:03:06 +0000 Subject: [PATCH 4/4] move mfcall to separate test to exclude windows Created using spr 1.3.7 --- compiler-rt/test/cfi/summary-mfcall.cpp | 54 +++++++++++++++++++++++++ compiler-rt/test/cfi/summary.cpp | 36 ----------------- 2 files changed, 54 insertions(+), 36 deletions(-) create mode 100644 compiler-rt/test/cfi/summary-mfcall.cpp diff --git a/compiler-rt/test/cfi/summary-mfcall.cpp b/compiler-rt/test/cfi/summary-mfcall.cpp new file mode 100644 index 0000000000000..ad5f706383624 --- /dev/null +++ b/compiler-rt/test/cfi/summary-mfcall.cpp @@ -0,0 +1,54 @@ +// RUN: %clangxx_cfi_diag -g -o %t %s +// RUN: %env_ubsan_opts=print_summary=1:report_error_type=1 %run %t nvmfcall 2>&1 | FileCheck --check-prefix=NVMFCALL %s +// RUN: %env_ubsan_opts=print_summary=1:report_error_type=1 %run %t vmfcall 2>&1 | FileCheck --check-prefix=VMFCALL %s + +// UNSUPPORTED: target={{.*windows-msvc.*}} +// REQUIRES: cxxabi + +#include "utils.h" +#include <stdio.h> +#include <string.h> + +struct S { + void f(); // non-virtual + virtual void g(); // virtual +}; +void S::f() {} +void S::g() {} + +struct T { + void f(); + virtual void g(); +}; +void T::f() {} +void T::g() {} + +typedef void (S::*S_void)(); +typedef int (S::*S_int)(); + +template <typename To, typename From> To bitcast(From f) { + To t; + memcpy(&t, &f, sizeof(f)); + return t; +} + +int main(int argc, char **argv) { + if (argc < 2) + return 0; + + create_derivers<T>(); + + if (strcmp(argv[1], "nvmfcall") == 0) { + S s; + break_optimization(&s); + // NVMFCALL: SUMMARY: UndefinedBehaviorSanitizer: cfi-mfcall {{.*}}summary-mfcall.cpp:[[@LINE+1]] + (s.*bitcast<S_void>(&T::f))(); + } else if (strcmp(argv[1], "vmfcall") == 0) { + S s; + break_optimization(&s); + // VMFCALL: SUMMARY: UndefinedBehaviorSanitizer: cfi-mfcall {{.*}}summary-mfcall.cpp:[[@LINE+1]] + (s.*bitcast<S_int>(&S::g))(); + } + + return 0; +} diff --git a/compiler-rt/test/cfi/summary.cpp b/compiler-rt/test/cfi/summary.cpp index 211419d1eafd6..e5d47f81ffa5b 100644 --- a/compiler-rt/test/cfi/summary.cpp +++ b/compiler-rt/test/cfi/summary.cpp @@ -4,8 +4,6 @@ // RUN: %env_ubsan_opts=print_summary=1:report_error_type=1 %run %t ucast 2>&1 | FileCheck --check-prefix=UCAST %s // RUN: %env_ubsan_opts=print_summary=1:report_error_type=1 %run %t dcast 2>&1 | FileCheck --check-prefix=DCAST %s // RUN: %env_ubsan_opts=print_summary=1:report_error_type=1 %run %t icall 2>&1 | FileCheck --check-prefix=ICALL %s -// RUN: %env_ubsan_opts=print_summary=1:report_error_type=1 %run %t nvmfcall 2>&1 | FileCheck --check-prefix=NVMFCALL %s -// RUN: %env_ubsan_opts=print_summary=1:report_error_type=1 %run %t vmfcall 2>&1 | FileCheck --check-prefix=VMFCALL %s // REQUIRES: cxxabi @@ -35,29 +33,6 @@ struct D { void D::f() {} void D::g() {} -struct S { - void f(); // non-virtual - virtual void g(); // virtual -}; -void S::f() {} -void S::g() {} - -struct T { - void f(); - virtual void g(); -}; -void T::f() {} -void T::g() {} - -typedef void (S::*S_void)(); -typedef int (S::*S_int)(); - -template <typename To, typename From> To bitcast(From f) { - To t; - memcpy(&t, &f, sizeof(f)); - return t; -} - void g() {} int main(int argc, char **argv) { @@ -66,7 +41,6 @@ int main(int argc, char **argv) { create_derivers<B>(); create_derivers<D>(); - create_derivers<T>(); if (strcmp(argv[1], "vcall") == 0) { A *a = new A; @@ -95,16 +69,6 @@ int main(int argc, char **argv) { break_optimization(&fp); // ICALL: SUMMARY: UndefinedBehaviorSanitizer: cfi-icall {{.*}}summary.cpp:[[@LINE+1]] ((void (*)(int))fp)(42); - } else if (strcmp(argv[1], "nvmfcall") == 0) { - S s; - break_optimization(&s); - // NVMFCALL: SUMMARY: UndefinedBehaviorSanitizer: cfi-mfcall {{.*}}summary.cpp:[[@LINE+1]] - (s.*bitcast<S_void>(&T::f))(); - } else if (strcmp(argv[1], "vmfcall") == 0) { - S s; - break_optimization(&s); - // VMFCALL: SUMMARY: UndefinedBehaviorSanitizer: cfi-mfcall {{.*}}summary.cpp:[[@LINE+1]] - (s.*bitcast<S_int>(&S::g))(); } return 0; _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
