From 30a8e79243084017d23f1c765d5f1cbb86564191 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 19 May 2023 10:15:32 -0700 Subject: [PATCH] QCallableObject: work around VS2022 compiler bug Address Sanitizer in Visual Studio reported: ==17744==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x11ffe2ba0760 at ... WRITE of size 1 at 0x11ffe2ba0760 thread T0 0x11ffe2ba0760 is located 0 bytes to the right of 16-byte region [0x11ffe2ba0750,0x11ffe2ba0760) allocated ... Disassembly of QCallableObject's constructor shows that the compiler did emit that 1-byte store of a null byte, 16 bytes after the object start, of an object whose size is 16 bytes. The location of this code implies it was the initialization of the StorageEmptyBaseClassOptimization sub-object. Without an explicit constructor, this was an aggregate initialization. This seems to be the same issue as [1]. The workaround is to give it an explicit constructor, the same workaround as [2]. I suppose other people using Empty Base Optimization haven't run into this issue because that empty base usually overlaps something inside the object. So an alternative workaround would be to invert the order of derivation such that StorageEmptyBaseClassOptimization was the first base. [1] https://developercommunity.visualstudio.com/t/address-of-empty-base-class-is-wrong-c-bad-code-ge/322444 [2] https://developercommunity.visualstudio.com/t/empty-class-derived-from-empty-base-class-causes-r/451088 Change-Id: I5f7f427ded124479baa6fffd17609adca0f8e235 Reviewed-by: Qt CI Bot Reviewed-by: Volker Hilsheimer --- src/corelib/tools/qfunctionaltools_impl.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/corelib/tools/qfunctionaltools_impl.h b/src/corelib/tools/qfunctionaltools_impl.h index 1f03b978e82..5878b90bd6a 100644 --- a/src/corelib/tools/qfunctionaltools_impl.h +++ b/src/corelib/tools/qfunctionaltools_impl.h @@ -12,6 +12,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -38,9 +39,16 @@ struct StorageByValue #undef MAKE_GETTER }; -template +template struct StorageEmptyBaseClassOptimization : Object { + StorageEmptyBaseClassOptimization(Object &&o) + : Object(std::move(o)) + {} + StorageEmptyBaseClassOptimization(const Object &o) + : Object(o) + {} + #define MAKE_GETTER(cvref) \ constexpr Object cvref object() cvref noexcept \ { return static_cast(*this); }