Merge pull request #10605 from harisibrar1/fix/rtti-ambiguous-private-base

fix(libc): reject a catch or upcast to a base that a private path repeats
This commit is contained in:
Dean authored and GitHub committed 2026-10-26 05:59:40 +13:00
commit 4718dedcf8
3 files changed
+20 -2

No files matched your search

+5 -2
View File
@@ -202,12 +202,15 @@ void VisitBases(const std::type_info* type, BaseLocation location, bool publicPa
void Bases(const std::type_info* type, void* object, Search& search) {
std::uintptr_t identity = 0;
bool reachedPublicly = false;
auto visitor = [&](const std::type_info* candidate, BaseLocation location, bool publicPath) {
if (!publicPath || !Equal(candidate, search.wanted)) return;
if (!search.count) { search.found = location.object; identity = location.identity; search.count = 1; }
if (!Equal(candidate, search.wanted)) return;
if (!search.count) { search.found = location.object; identity = location.identity; search.count = 1; reachedPublicly = publicPath; }
else if (search.found != location.object || identity != location.identity) search.count = 2;
else if (publicPath) reachedPublicly = true;
};
VisitBases(type, {object, 0}, true, visitor);
if (search.count == 1 && !reachedPublicly) search.count = 0;
}
bool PointerMatch(const __cxxabiv1::__pbase_type_info* caught, const __cxxabiv1::__pbase_type_info* thrown,
+4
View File
@@ -40,6 +40,7 @@ struct Virtual : virtual Base {};
struct Left : Base {};
struct Right : Base {};
struct Repeated : Left, Right {};
struct MixedRepeated : Left, private Right {};
struct LeftVirtual : virtual Base {};
struct RightVirtual : virtual Base {};
struct Diamond : LeftVirtual, RightVirtual {};
@@ -59,6 +60,9 @@ void CheckRtti() {
try { throw static_cast<Repeated*>(nullptr); }
catch (Base*) { assert(false); }
catch (Repeated* p) { assert(p == nullptr); }
try { throw MixedRepeated(); }
catch (Base&) { assert(false); }
catch (MixedRepeated&) {}
try { throw static_cast<Diamond*>(nullptr); }
catch (Base* p) { assert(p == nullptr); }
try { throw nullptr; }
+11
View File
@@ -56,6 +56,17 @@ static void TestTypeInfoVtables() {
if (!upcastType(&multiple, &base, &object) || object != storage.data() + 16) throw std::runtime_error("multiple RTTI upcast failed");
object = storage.data();
if (catchType(&other, &single, &object, 0)) throw std::runtime_error("unrelated RTTI catch succeeded");
TypeRecord shared {classTable + 2 * sizeof(void*), "6Shared"};
SingleRecord publicPath {{singleTable + 2 * sizeof(void*), "10PublicPath"}, &shared};
SingleRecord privatePath {{singleTable + 2 * sizeof(void*), "11PrivatePath"}, &shared};
MultipleRecord mixed {{multipleTable + 2 * sizeof(void*), "5Mixed"}, 1, 2, {{&publicPath.type, 2}, {&privatePath.type, 16 << 8}}};
MultipleRecord hidden {{multipleTable + 2 * sizeof(void*), "6Hidden"}, 0, 1, {{&privatePath.type, 0}, {}}};
object = storage.data();
if (catchType(&shared, &mixed, &object, 0) || object != storage.data()) throw std::runtime_error("RTTI catch of a base repeated through a private path succeeded");
if (upcastType(&mixed, &shared, &object) || object != storage.data()) throw std::runtime_error("RTTI upcast to a base repeated through a private path succeeded");
if (!catchType(&publicPath, &mixed, &object, 0) || object != storage.data()) throw std::runtime_error("RTTI catch of the public path failed");
object = storage.data();
if (catchType(&shared, &hidden, &object, 0)) throw std::runtime_error("RTTI catch of a privately inherited base succeeded");
}
extern "C" [[noreturn]] void NotImplemented_nid_no_patch(const char*);