Files
RedBear-OS/local/recipes/dev/libclc/source/clang/test/CodeGenCXX/ubsan-devirtualized-calls.cpp
T
vasilito cb424d7448 build: static patch-sanity linter (shift-left the malformed-patch class)
verify-patch-sanity.py validates every active recipe .patch has internally-
consistent hunk line counts — catching the 'malformed patch at line N' failure
at commit/CI/preflight time instead of hours into a cook. This cycle hit that
class three times (qtwaylandscanner, sddm, xwayland), each only discovered when
cookbook tried to apply the patch.

Running it across the repo found 29 latent malformed patches (validated against
GNU patch: e.g. relibc/P3-sysv-ipc reproduces 'malformed patch at line 22').
They were harmless only because they sit in vendored recipes (baked, not re-
applied) — but would fail on any version-bump re-derivation. --fix recounts the
hunk headers (body untouched) and repaired all 29.

Wired into build-preflight.sh (Phase 1.0D) and redbear-ci.yml, with a unit test
(test-patch-sanity.sh). Skips archived/legacy trees and unvalidatable formats
(empty placeholders, bare-@@ git hunks).
2026-08-01 05:13:02 +03:00

89 lines
3.7 KiB
C++

// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -emit-llvm -fsanitize=null,vptr %s -o - | FileCheck %s
struct Base1 {
virtual void f1() {}
};
struct Base2 {
virtual void f1() {}
};
struct Derived1 final : Base1 {
void f1() override {}
};
struct Derived2 final : Base1, Base2 {
void f1() override {}
};
struct Derived3 : Base1 {
void f1() override /* nofinal */ {}
};
struct Derived4 final : Base1 {
void f1() override final {}
};
// CHECK: [[UBSAN_TI_DERIVED1_1:@[0-9]+]] = private unnamed_addr global {{.*}} ptr @_ZTI8Derived1
// CHECK: [[UBSAN_TI_DERIVED2_1:@[0-9]+]] = private unnamed_addr global {{.*}} ptr @_ZTI8Derived2
// CHECK: [[UBSAN_TI_DERIVED2_2:@[0-9]+]] = private unnamed_addr global {{.*}} ptr @_ZTI8Derived2
// CHECK: [[UBSAN_TI_DERIVED3:@[0-9]+]] = private unnamed_addr global {{.*}} ptr @_ZTI8Derived3
// CHECK: [[UBSAN_TI_BASE1:@[0-9]+]] = private unnamed_addr global {{.*}} ptr @_ZTI5Base1
// CHECK: [[UBSAN_TI_DERIVED4_1:@[0-9]+]] = private unnamed_addr global {{.*}} ptr @_ZTI8Derived4
// CHECK: [[UBSAN_TI_DERIVED4_2:@[0-9]+]] = private unnamed_addr global {{.*}} ptr @_ZTI8Derived4
// CHECK-LABEL: define {{(dso_local )?}}void @_Z2t1v
void t1() {
Derived1 d1;
static_cast<Base1 *>(&d1)->f1(); //< Devirt Base1::f1 to Derived1::f1.
// CHECK: %[[D1:[0-9]+]] = ptrtoint ptr %d1 to i{{[0-9]+}}, !nosanitize
// CHECK-NEXT: call void @__ubsan_handle_dynamic_type_cache{{[_a-z]*}}({{.*}} [[UBSAN_TI_DERIVED1_1]], i{{[0-9]+}} %[[D1]]
}
// CHECK-LABEL: define {{(dso_local )?}}void @_Z2t2v
void t2() {
Derived2 d2;
static_cast<Base1 *>(&d2)->f1(); //< Devirt Base1::f1 to Derived2::f1.
// CHECK: %[[D2_1:[0-9]+]] = ptrtoint ptr %d2 to i{{[0-9]+}}, !nosanitize
// CHECK-NEXT: call void @__ubsan_handle_dynamic_type_cache{{[_a-z]*}}({{.*}} [[UBSAN_TI_DERIVED2_1]], i{{[0-9]+}} %[[D2_1]]
}
// CHECK-LABEL: define {{(dso_local )?}}void @_Z2t3v
void t3() {
Derived2 d2;
static_cast<Base2 *>(&d2)->f1(); //< Devirt Base2::f1 to Derived2::f1.
// CHECK: %[[D2_2:[0-9]+]] = ptrtoint ptr %d2 to i{{[0-9]+}}, !nosanitize
// CHECK-NEXT: call void @__ubsan_handle_dynamic_type_cache{{[_a-z]*}}({{.*}} [[UBSAN_TI_DERIVED2_2]], i{{[0-9]+}} %[[D2_2]]
}
// CHECK-LABEL: define {{(dso_local )?}}void @_Z2t4v
void t4() {
Base1 p;
Derived3 *badp = static_cast<Derived3 *>(&p); //< Check that &p isa Derived3.
// CHECK: %[[P1:[0-9]+]] = ptrtoint ptr %p to i{{[0-9]+}}, !nosanitize
// CHECK-NEXT: call void @__ubsan_handle_dynamic_type_cache{{[_a-z]*}}({{.*}} [[UBSAN_TI_DERIVED3]], i{{[0-9]+}} %[[P1]]
static_cast<Base1 *>(badp)->f1(); //< No devirt, test 'badp isa Base1'.
// We were able to skip the null check on the first type check because 'p'
// is backed by an alloca. We can't skip the second null check because 'badp'
// is a (bitcast (load ...)).
// CHECK: call void @__ubsan_handle_type_mismatch
//
// CHECK: %[[BADP1:[0-9]+]] = ptrtoint ptr {{%[0-9]+}} to i{{[0-9]+}}, !nosanitize
// CHECK-NEXT: call void @__ubsan_handle_dynamic_type_cache{{[_a-z]*}}({{.*}} [[UBSAN_TI_BASE1]], i{{[0-9]+}} %[[BADP1]]
}
// CHECK-LABEL: define {{(dso_local )?}}void @_Z2t5v
void t5() {
Base1 p;
Derived4 *badp = static_cast<Derived4 *>(&p); //< Check that &p isa Derived4.
// CHECK: %[[P1:[0-9]+]] = ptrtoint ptr %p to i{{[0-9]+}}, !nosanitize
// CHECK-NEXT: call void @__ubsan_handle_dynamic_type_cache{{[_a-z]*}}({{.*}} [[UBSAN_TI_DERIVED4_1]], i{{[0-9]+}} %[[P1]]
static_cast<Base1 *>(badp)->f1(); //< Devirt Base1::f1 to Derived4::f1.
// CHECK: call void @__ubsan_handle_type_mismatch
//
// CHECK: %[[BADP1:[0-9]+]] = ptrtoint ptr {{%[0-9]+}} to i{{[0-9]+}}, !nosanitize
// CHECK-NEXT: call void @__ubsan_handle_dynamic_type_cache{{[_a-z]*}}({{.*}} [[UBSAN_TI_DERIVED4_2]], i{{[0-9]+}} %[[BADP1]]
}