Short: On unloading Qt5Quick, the destructor of Q_GLOBAL_STATIC(QQmlValueTypeFactoryImpl, factoryImpl) hits an access violation trying to release a QString that points to invalid memory.
The address it points to was inside the space taken by the module in which the qml.cpp files were compiled, but that module gets unloaded before Qt5Quick, so now it's invalid memory.
This repros when the code using Qt lives in its own .DLL, call it MyQtCode.dll.
Using qmlcache gen to generate qml..cpp files and then compiling that code into MyQtCode.dll
On application exit, MyQtCode.dll gets unloaded first and the Qt5*.dlls after.
When unloading Qt5Quick, the destructor of Q_GLOBAL_STATIC(QQmlValueTypeFactoryImpl, factoryImpl) crashes with access violation trying to release a QString whose buffer lives in the address space where MyQtCode.dll was previously loaded.
The specific QQmlValueType being destroyed is idx = 0x40, which corresponds to QFont. The destructor of QFont calls QFontDef::~QFontDef which ends up trying to release its QString QFontDef::family.
Upon closer debugging, it turns out the family QString was pointing at const string data that lives in the qmlData compiled into the binary. The specific string was the font family name that I specified for my UI in the .qml file.
This leads to QV4CompileData_p.h, which for certain strings marked as "static" returns QStrings that directly reference qmldata instead of returning copies (see qtdeclarative\src\qml\compiler\qv4compileddata_p.h line 911: stringAtInternal for Q_LITTLE_ENDIAN, the if (flags & StaticData) case).
This looks like it's changed from Qt 5.11 which was always returning copies of the string data.
Crash stack below - please let me know if I need to provide a minimal sample app that reproduces this.
Qt5Cored.dll!std::_Load_relaxed_4(volatile unsigned long * _Tgt) Line 1341 C++>
Qt5Cored.dll!std::_Load_relaxed_4(volatile unsigned long * _Tgt) Line 1341 C+ +
Qt5Cored.dll!std::_Atomic_load_4(volatile unsigned long * _Tgt, std::memory_order _Order) Line 1360 C+ +
Qt5Cored.dll!std::atomic_load_explicit(const std::_Atomic_int * _Atom, std::memory_order _Order) Line 495 C+ +
Qt5Cored.dll!QAtomicOps<int>::load<int>(const std::atomic<int> & _q_value) Line 228 C+ +
Qt5Cored.dll!QBasicAtomicInteger<int>::load() Line 103 C+ +
Qt5Cored.dll!QtPrivate::RefCount::deref() Line 66 C+ +
Qt5Cored.dll!QString::~QString() Line 1135 C+ +
Qt5Guid.dll!QFontDef::~QFontDef() C+ +
Qt5Guid.dll!QFontPrivate::~QFontPrivate() Line 199 C+ +
Qt5Guid.dll!QFontPrivate::`scalar deleting destructor'(unsigned int) C+ +
Qt5Guid.dll!QFont::~QFont() Line 671 C+ +
Qt5Guid.dll!QFont::`scalar deleting destructor'(unsigned int) C+ +
Qt5Guid.dll!QtMetaTypePrivate::QMetaTypeFunctionHelper<QFont,1>::Destruct(void * t) Line 799 C+ +
Qt5Cored.dll!QMetaType::destroyExtended(void * data) Line 2574 C+
Qt5Qmld.dll!QQmlValueType::`vector deleting destructor'(unsigned int) C+ +
Qt5Qmld.dll!qDeleteAll<QQmlValueType * *>(QQmlValueType * * begin, QQmlValueType * * end) Line 320 C+ +
Qt5Qmld.dll!`anonymous namespace'::QQmlValueTypeFactoryImpl::~QQmlValueTypeFactoryImpl() Line 78 C++