Fix ClassIDs for DLL usage

If ClassID::Of<T>() is used inside tint and used outside tint for the same type, and tint is built as a DLL, then the address of the Unique<T>::token can resolve to different addresses, entirely breaking Castable.

Replace address-of for a unique symbol with a single static counter that's incremented for each use of TINT_INSTANTIATE_CLASS_ID().

Change-Id: I40dc81b1273110291d90a1d5ec05428f7e703c6a
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/42460
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
Ben Clayton 2021-02-24 21:03:34 +00:00 committed by Commit Bot service account
parent 72260e44ae
commit 80cb20de7c
1 changed files with 27 additions and 19 deletions

View File

@ -22,28 +22,36 @@
namespace tint { namespace tint {
/// Helper macro to instantiate the ClassID for `CLASS`. class ClassID;
#define TINT_INSTANTIATE_CLASS_ID(CLASS) \
template <> \ /// Helper macro to instantiate the TypeInfo<T> template for `CLASS`.
const char ::tint::ClassID::Unique<CLASS>::token = 0 #define TINT_INSTANTIATE_CLASS_ID(CLASS) \
template <> \
const tint::ClassID tint::TypeInfo<CLASS>::class_id { \
tint::ClassID::New() \
}
/// TypeInfo holds type information for the type T.
/// TINT_INSTANTIATE_CLASS_ID() must be defined in a .cpp file for each type
/// `T`.
template <typename T>
struct TypeInfo {
static const ClassID class_id;
};
/// ClassID represents a unique, comparable identifier for a C++ type. /// ClassID represents a unique, comparable identifier for a C++ type.
class ClassID { class ClassID {
private:
/// Helper template that holds a single static field, which is used by Of()
/// to obtain a unique identifier by taking the field's address.
template <typename T>
struct Unique {
static const char token;
};
public: public:
/// @returns a new and unique ClassID
static inline ClassID New() {
static uintptr_t next(0);
return ClassID(next++);
}
/// @returns the unique ClassID for the type T. /// @returns the unique ClassID for the type T.
template <typename T> template <typename T>
static ClassID Of() { static inline ClassID Of() {
// Take the address of a static variable to produce a unique identifier for return TypeInfo<T>::class_id;
// the type T.
return ClassID{reinterpret_cast<uintptr_t>(&Unique<T>::token)};
} }
/// Equality operator /// Equality operator
@ -81,7 +89,7 @@ class CastableBase {
/// @returns true if this object is of, or derives from the class `TO` /// @returns true if this object is of, or derives from the class `TO`
template <typename TO> template <typename TO>
bool Is() const { inline bool Is() const {
using FROM = CastableBase; using FROM = CastableBase;
constexpr const bool downcast = std::is_base_of<FROM, TO>::value; constexpr const bool downcast = std::is_base_of<FROM, TO>::value;
constexpr const bool upcast = std::is_base_of<TO, FROM>::value; constexpr const bool upcast = std::is_base_of<TO, FROM>::value;
@ -146,13 +154,13 @@ class Castable : public BASE {
/// @returns true if this object is of, or derives from a class with the /// @returns true if this object is of, or derives from a class with the
/// ClassID `id`. /// ClassID `id`.
/// @param id the ClassID to test for /// @param id the ClassID to test for
bool Is(ClassID id) const override { inline bool Is(ClassID id) const override {
return ClassID::Of<CLASS>() == id || BASE::Is(id); return ClassID::Of<CLASS>() == id || BASE::Is(id);
} }
/// @returns true if this object is of, or derives from the class `TO` /// @returns true if this object is of, or derives from the class `TO`
template <typename TO> template <typename TO>
bool Is() const { inline bool Is() const {
using FROM = Castable; using FROM = Castable;
constexpr const bool downcast = std::is_base_of<FROM, TO>::value; constexpr const bool downcast = std::is_base_of<FROM, TO>::value;
constexpr const bool upcast = std::is_base_of<TO, FROM>::value; constexpr const bool upcast = std::is_base_of<TO, FROM>::value;