From 80cb20de7ca4f16ee21ee2e031913bd1c30a1d1e Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Wed, 24 Feb 2021 21:03:34 +0000 Subject: [PATCH] Fix ClassIDs for DLL usage If ClassID::Of() 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::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 Commit-Queue: Ben Clayton --- src/castable.h | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/src/castable.h b/src/castable.h index 3599c34cbb..9528d96102 100644 --- a/src/castable.h +++ b/src/castable.h @@ -22,28 +22,36 @@ namespace tint { -/// Helper macro to instantiate the ClassID for `CLASS`. -#define TINT_INSTANTIATE_CLASS_ID(CLASS) \ - template <> \ - const char ::tint::ClassID::Unique::token = 0 +class ClassID; + +/// Helper macro to instantiate the TypeInfo template for `CLASS`. +#define TINT_INSTANTIATE_CLASS_ID(CLASS) \ + template <> \ + const tint::ClassID tint::TypeInfo::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 +struct TypeInfo { + static const ClassID class_id; +}; /// ClassID represents a unique, comparable identifier for a C++ type. 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 - struct Unique { - static const char token; - }; - 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. template - static ClassID Of() { - // Take the address of a static variable to produce a unique identifier for - // the type T. - return ClassID{reinterpret_cast(&Unique::token)}; + static inline ClassID Of() { + return TypeInfo::class_id; } /// Equality operator @@ -81,7 +89,7 @@ class CastableBase { /// @returns true if this object is of, or derives from the class `TO` template - bool Is() const { + inline bool Is() const { using FROM = CastableBase; constexpr const bool downcast = std::is_base_of::value; constexpr const bool upcast = std::is_base_of::value; @@ -146,13 +154,13 @@ class Castable : public BASE { /// @returns true if this object is of, or derives from a class with the /// ClassID `id`. /// @param id the ClassID to test for - bool Is(ClassID id) const override { + inline bool Is(ClassID id) const override { return ClassID::Of() == id || BASE::Is(id); } /// @returns true if this object is of, or derives from the class `TO` template - bool Is() const { + inline bool Is() const { using FROM = Castable; constexpr const bool downcast = std::is_base_of::value; constexpr const bool upcast = std::is_base_of::value;