Hi all,
I’m having a problem with Identifier
.
I get the following address sanitiser report when the application exits:
==21024==ERROR: AddressSanitizer: heap-use-after-free on address 0x604000070c10 at pc 0x000100890c19 bp 0x0003149e7ed0 sp 0x0003149e7ec8
READ of size 4 at 0x604000070c10 thread T0
#0 0x100890c18 in int std::__1::__cxx_atomic_load<int>(std::__1::__cxx_atomic_base_impl<int> const*, std::__1::memory_order) atomic:1010
#1 0x100890ab3 in std::__1::__atomic_base<int, false>::load(std::__1::memory_order) const atomic:1643
#2 0x1008998a3 in juce::Atomic<int>::get() const juce_Atomic.h:64
#3 0x1040a80d8 in juce::StringHolder::isEmptyString(juce::StringHolder*) juce_String.cpp:219
#4 0x1040a7d94 in juce::StringHolder::release(juce::StringHolder*) juce_String.cpp:162
#5 0x103f1d4b6 in juce::StringHolder::release(juce::CharPointer_UTF8) juce_String.cpp:169
#6 0x103f1d2f1 in juce::String::~String() juce_String.cpp:247
#7 0x103e6c798 in juce::String::~String() juce_String.cpp:246
#8 0x10099bac4 in juce::ArrayBase<juce::String, juce::DummyCriticalSection>::clear() juce_ArrayBase.h:242
#9 0x10099b958 in juce::ArrayBase<juce::String, juce::DummyCriticalSection>::~ArrayBase() juce_ArrayBase.h:55
#10 0x10099b908 in juce::ArrayBase<juce::String, juce::DummyCriticalSection>::~ArrayBase() juce_ArrayBase.h:54
#11 0x10099b8b8 in juce::Array<juce::String, juce::DummyCriticalSection, 0>::~Array() juce_Array.h:132
#12 0x10099a778 in juce::Array<juce::String, juce::DummyCriticalSection, 0>::~Array() juce_Array.h:132
#13 0x1040bad55 in juce::StringPool::~StringPool() juce_StringPool.h:39
#14 0x103f54ad8 in juce::StringPool::~StringPool() juce_StringPool.h:39
#15 0x7ff81f259dd3 in __cxa_finalize_ranges+0x198 (libsystem_c.dylib:x86_64+0x2edd3)
#16 0x7ff81f259bed in exit+0x22 (libsystem_c.dylib:x86_64+0x2ebed)
#17 0x7ff81f36d374 in dyld4::LibSystemHelpers::exit(int) const+0xa (libdyld.dylib:x86_64+0x6374)
#18 0x2100ae547 in start+0x1f7 (dyld:x86_64+0x5547)
0x604000070c10 is located 0 bytes inside of 35-byte region [0x604000070c10,0x604000070c33)
freed by thread T0 here:
#0 0x126bba78d in wrap__ZdaPv+0x7d (libclang_rt.asan_osx_dynamic.dylib:x86_64+0x5478d)
#1 0x1040a7e3d in juce::StringHolder::release(juce::StringHolder*) juce_String.cpp:164
#2 0x103f1d4b6 in juce::StringHolder::release(juce::CharPointer_UTF8) juce_String.cpp:169
#3 0x103f1d2f1 in juce::String::~String() juce_String.cpp:247
#4 0x103e6c798 in juce::String::~String() juce_String.cpp:246
#5 0x103f15de8 in juce::Identifier::~Identifier() juce_Identifier.cpp:27
#6 0x103e64b18 in juce::Identifier::~Identifier() juce_Identifier.cpp:27
#7 0x7ff81f259dd3 in __cxa_finalize_ranges+0x198 (libsystem_c.dylib:x86_64+0x2edd3)
#8 0x7ff81f259bed in exit+0x22 (libsystem_c.dylib:x86_64+0x2ebed)
#9 0x7ff81f36d374 in dyld4::LibSystemHelpers::exit(int) const+0xa (libdyld.dylib:x86_64+0x6374)
#10 0x2100ae547 in start+0x1f7 (dyld:x86_64+0x5547)
previously allocated by thread T0 here:
#0 0x126bba37d in wrap__Znam+0x7d (libclang_rt.asan_osx_dynamic.dylib:x86_64+0x5437d)
#1 0x103f1e696 in juce::StringHolder::createUninitialisedBytes(unsigned long) juce_String.cpp:71
#2 0x103f20e42 in juce::CharPointer_UTF8 juce::StringHolder::createFromCharPointer<juce::CharPointer_UTF8>(juce::CharPointer_UTF8) juce_String.cpp:84
#3 0x103f20b75 in juce::String::String(juce::CharPointer_UTF8) juce_String.cpp:349
#4 0x103e8be0f in juce::String::String(juce::CharPointer_UTF8) juce_String.cpp:349
#5 0x103f52ed0 in juce::String juce::addPooledString<juce::CharPointer_UTF8>(juce::Array<juce::String, juce::DummyCriticalSection, 0>&, juce::CharPointer_UTF8 const&) juce_StringPool.cpp:96
#6 0x103f169c3 in juce::StringPool::getPooledString(char const*) juce_StringPool.cpp:107
#7 0x103f1662c in juce::Identifier::Identifier(char const*) juce_Identifier.cpp:53
#8 0x103e76b80 in juce::Identifier::Identifier(char const*) juce_Identifier.cpp:54
#9 0x1008a21a6 in __cxx_global_var_init.182 Sound.h:31
#10 0x1008a2ce8 in _GLOBAL__sub_I_MultiSoundEditor.cpp MultiSoundEditor.cpp
#11 0x2100bddda in invocation function for block in dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const+0xb5 (dyld:x86_64+0x14dda)
#12 0x2100e40ba in invocation function for block in dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const+0x80 (dyld:x86_64+0x3b0ba)
#13 0x2100db859 in invocation function for block in dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const+0x22c (dyld:x86_64+0x32859)
#14 0x2100aadb2 in dyld3::MachOFile::forEachLoadCommand(Diagnostics&, void (load_command const*, bool&) block_pointer) const+0x80 (dyld:x86_64+0x1db2)
#15 0x2100db5ea in dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const+0xb2 (dyld:x86_64+0x325ea)
#16 0x2100e3aeb in dyld3::MachOAnalyzer::forEachInitializerPointerSection(Diagnostics&, void (unsigned int, unsigned int, unsigned char const*, bool&) block_pointer) const+0x75 (dyld:x86_64+0x3aaeb)
#17 0x2100e3d5d in dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const+0x181 (dyld:x86_64+0x3ad5d)
#18 0x2100bdd0d in dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const+0x8f (dyld:x86_64+0x14d0d)
#19 0x2100bde99 in dyld4::Loader::runInitializersBottomUp(dyld4::RuntimeState&, dyld3::Array<dyld4::Loader const*>&) const+0xb1 (dyld:x86_64+0x14e99)
#20 0x2100bdf3d in dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const+0x6b (dyld:x86_64+0x14f3d)
#21 0x2100d154d in dyld4::APIs::runAllInitializersForMain()+0xdd (dyld:x86_64+0x2854d)
#22 0x2100af37c in dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*)+0xd72 (dyld:x86_64+0x637c)
#23 0x2100ae4d3 in start+0x183 (dyld:x86_64+0x54d3)
SUMMARY: AddressSanitizer: heap-use-after-free atomic:1010 in int std::__1::__cxx_atomic_load<int>(std::__1::__cxx_atomic_base_impl<int> const*, std::__1::memory_order)
Shadow bytes around the buggy address:
0x1c080000e130: fa fa fd fd fd fd fd fa fa fa 00 00 00 00 00 03
0x1c080000e140: fa fa 00 00 00 00 03 fa fa fa 00 00 00 00 07 fa
0x1c080000e150: fa fa 00 00 00 00 07 fa fa fa 00 00 00 00 00 03
0x1c080000e160: fa fa 00 00 00 00 07 fa fa fa 00 00 00 00 00 03
0x1c080000e170: fa fa 00 00 00 00 07 fa fa fa 00 00 00 00 00 03
=>0x1c080000e180: fa fa[fd]fd fd fd fd fa fa fa 00 00 00 00 00 07
0x1c080000e190: fa fa 00 00 00 00 00 03 fa fa 00 00 00 00 07 fa
0x1c080000e1a0: fa fa fd fd fd fd fd fd fa fa 00 00 00 00 03 fa
0x1c080000e1b0: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fd
0x1c080000e1c0: fa fa fd fd fd fd fd fa fa fa 00 00 00 00 07 fa
0x1c080000e1d0: fa fa 00 00 00 00 03 fa fa fa fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==21024==ABORTING
AddressSanitizer report breakpoint hit. Use 'thread info -s' to get extended information about the report.
As one can see, this is related to the allocation and destruction of global variables. I know, this is kind of my first mistake using global variables. It’s a left over from the original SamplerPluginDemo. The one line related to this issue is (in header file)
namespace IDs
{
#define DECLARE_ID(name) const juce::Identifier name(#name)
DECLARE_ID(adsrEnabled); // Here is Sound.h line 31
#undef DECLARE_ID
}
But this alone does not trigger the error. The error is somehow triggered by my meta programming:
// In header
struct adsrEnabled {};
template <typename property> const Identifier identifier;
// In (of course only one) cpp
template <> const Identifier identifier<adsrEnabled> = IDs::adsrEnabled;
These two bits are enough to reproduce the error in a new JUCE project. Looking at the stack trace the global string pool seems to be freed first and then some kind of left over Identifier
. While reproducing the bug, it is also possible to go vice versa. After half a day of searching I still cannot come up with an idea how/why this happens. A work around is of course very straight forward (just don’t use a global template variable but a template function) but I’d like to understand the problem first before going down this road.
Thanks in advance!