//===-- ubsan_type_hash_itanium.cpp ---------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Implementation of type hashing/lookup for Itanium C++ ABI. // //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_platform.h" #include "ubsan_platform.h" #if CAN_SANITIZE_UB && !defined(_MSC_VER) #include "ubsan_type_hash.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_ptrauth.h" #include <stdint.h> // The following are intended to be binary compatible with the definitions // given in the Itanium ABI. We make no attempt to be ODR-compatible with // those definitions, since existing ABI implementations aren't. namespace std { class type_info { … }; } namespace __cxxabiv1 { /// Type info for classes with no bases, and base class for type info for /// classes with bases. class __class_type_info : public std::type_info { … }; /// Type info for classes with simple single public inheritance. class __si_class_type_info : public __class_type_info { … }; class __base_class_type_info { … }; /// Type info for classes with multiple, virtual, or non-public inheritance. class __vmi_class_type_info : public __class_type_info { … }; } abi; usingnamespace__sanitizer; // We implement a simple two-level cache for type-checking results. For each // (vptr,type) pair, a hash is computed. This hash is assumed to be globally // unique; if it collides, we will get false negatives, but: // * such a collision would have to occur on the *first* bad access, // * the probability of such a collision is low (and for a 64-bit target, is // negligible), and // * the vptr, and thus the hash, can be affected by ASLR, so multiple runs // give better coverage. // // The first caching layer is a small hash table with no chaining; buckets are // reused as needed. The second caching layer is a large hash table with open // chaining. We can freely evict from either layer since this is just a cache. // // FIXME: Make these hash table accesses thread-safe. The races here are benign: // assuming the unsequenced loads and stores don't misbehave too badly, // the worst case is false negatives or poor cache behavior, not false // positives or crashes. /// Find a bucket to store the given hash value in. static __ubsan::HashValue *getTypeCacheHashTableBucket(__ubsan::HashValue V) { … } /// \brief Determine whether \p Derived has a \p Base base class subobject at /// offset \p Offset. static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived, const abi::__class_type_info *Base, sptr Offset) { … } /// \brief Find the derived-most dynamic base class of \p Derived at offset /// \p Offset. static const abi::__class_type_info *findBaseAtOffset( const abi::__class_type_info *Derived, sptr Offset) { … } namespace { struct VtablePrefix { … }; VtablePrefix *getVtablePrefix(void *Vtable) { … } } bool __ubsan::checkDynamicType(void *Object, void *Type, HashValue Hash) { … } __ubsan::DynamicTypeInfo __ubsan::getDynamicTypeInfoFromVtable(void *VtablePtr) { … } bool __ubsan::checkTypeInfoEquality(const void *TypeInfo1, const void *TypeInfo2) { … } #endif // CAN_SANITIZE_UB && !SANITIZER_WINDOWS