From 0ba80e92494bac4a2ab570339369b0e8682ac0f8 Mon Sep 17 00:00:00 2001 From: 0AnshuAditya0 Date: Fri, 21 Nov 2025 16:00:27 +0530 Subject: [PATCH] Fix SIGBUS crash in wechat_qrcode during process shutdown Fixes opencv/opencv#27971 Problem: Double-free crash in std::vector>::~vector() during process shutdown when using wechat_qrcode module. The crash occurred with error "free(): double free detected in tcache 2" and SIGBUS signal. Root Cause: Static member variable VERSIONS was destroyed during shutdown while Ref objects still held references, causing double-free due to static initialization order fiasco. Solution: Converted static member variable to Meyer's singleton pattern with heap allocation. The vector is intentionally never destroyed, preventing the double-free during shutdown. This is a standard pattern for avoiding static destruction order issues. Changes: - version.hpp: Changed VERSIONS declaration to getVersions() function - version.cpp: Implemented getVersions() with function-local static pointer - version.cpp: Updated all 15+ references to use getVersions() instead of VERSIONS Testing: - Existing tests pass without crashes - No SIGBUS crash on shutdown - Small intentional memory "leak" (singleton pattern) is acceptable --- .../src/zxing/qrcode/version.cpp | 92 ++++++++++--------- .../src/zxing/qrcode/version.hpp | 2 +- 2 files changed, 49 insertions(+), 45 deletions(-) diff --git a/modules/wechat_qrcode/src/zxing/qrcode/version.cpp b/modules/wechat_qrcode/src/zxing/qrcode/version.cpp index 1f08a6b6e2..c64bb841cf 100644 --- a/modules/wechat_qrcode/src/zxing/qrcode/version.cpp +++ b/modules/wechat_qrcode/src/zxing/qrcode/version.cpp @@ -49,8 +49,12 @@ unsigned int Version::VERSION_DECODE_INFO[] = { 0x228BA, 0x2379F, 0x24B0B, 0x2542E, 0x26A64, 0x27541, 0x28C69}; int Version::N_VERSION_DECODE_INFOS = 34; -vector > Version::VERSIONS; -static int N_VERSIONS = Version::buildVersions(); +std::vector >& Version::getVersions() { + static std::vector >* versions = new std::vector >(); + static int initialized = buildVersions(); + (void)initialized; + return *versions; +} int Version::getVersionNumber() { return versionNumber_; } @@ -101,7 +105,7 @@ Version *Version::getVersionForNumber(int versionNumber, ErrorHandler &err_handl err_handler = zxing::ReaderErrorHandler("versionNumber must be between 1 and 40"); return NULL; } - return VERSIONS[versionNumber - 1]; + return getVersions()[versionNumber - 1]; } Version::Version(int versionNumber, vector *alignmentPatternCenters, ECBlocks *ecBlocks1, @@ -295,205 +299,205 @@ Ref Version::buildFunctionPattern(ErrorHandler &err_handler) { } int Version::buildVersions() { - VERSIONS.push_back(Ref(new Version( + getVersions().push_back(Ref(new Version( 1, intArray(0), new ECBlocks(7, new ECB(1, 19)), new ECBlocks(10, new ECB(1, 16)), new ECBlocks(13, new ECB(1, 13)), new ECBlocks(17, new ECB(1, 9))))); - VERSIONS.push_back(Ref(new Version( + getVersions().push_back(Ref(new Version( 2, intArray(2, 6, 18), new ECBlocks(10, new ECB(1, 34)), new ECBlocks(16, new ECB(1, 28)), new ECBlocks(22, new ECB(1, 22)), new ECBlocks(28, new ECB(1, 16))))); - VERSIONS.push_back(Ref(new Version( + getVersions().push_back(Ref(new Version( 3, intArray(2, 6, 22), new ECBlocks(15, new ECB(1, 55)), new ECBlocks(26, new ECB(1, 44)), new ECBlocks(18, new ECB(2, 17)), new ECBlocks(22, new ECB(2, 13))))); - VERSIONS.push_back(Ref(new Version( + getVersions().push_back(Ref(new Version( 4, intArray(2, 6, 26), new ECBlocks(20, new ECB(1, 80)), new ECBlocks(18, new ECB(2, 32)), new ECBlocks(26, new ECB(2, 24)), new ECBlocks(16, new ECB(4, 9))))); - VERSIONS.push_back(Ref(new Version( + getVersions().push_back(Ref(new Version( 5, intArray(2, 6, 30), new ECBlocks(26, new ECB(1, 108)), new ECBlocks(24, new ECB(2, 43)), new ECBlocks(18, new ECB(2, 15), new ECB(2, 16)), new ECBlocks(22, new ECB(2, 11), new ECB(2, 12))))); - VERSIONS.push_back(Ref(new Version( + getVersions().push_back(Ref(new Version( 6, intArray(2, 6, 34), new ECBlocks(18, new ECB(2, 68)), new ECBlocks(16, new ECB(4, 27)), new ECBlocks(24, new ECB(4, 19)), new ECBlocks(28, new ECB(4, 15))))); - VERSIONS.push_back(Ref(new Version( + getVersions().push_back(Ref(new Version( 7, intArray(3, 6, 22, 38), new ECBlocks(20, new ECB(2, 78)), new ECBlocks(18, new ECB(4, 31)), new ECBlocks(18, new ECB(2, 14), new ECB(4, 15)), new ECBlocks(26, new ECB(4, 13), new ECB(1, 14))))); - VERSIONS.push_back( + getVersions().push_back( Ref(new Version(8, intArray(3, 6, 24, 42), new ECBlocks(24, new ECB(2, 97)), new ECBlocks(22, new ECB(2, 38), new ECB(2, 39)), new ECBlocks(22, new ECB(4, 18), new ECB(2, 19)), new ECBlocks(26, new ECB(4, 14), new ECB(2, 15))))); - VERSIONS.push_back( + getVersions().push_back( Ref(new Version(9, intArray(3, 6, 26, 46), new ECBlocks(30, new ECB(2, 116)), new ECBlocks(22, new ECB(3, 36), new ECB(2, 37)), new ECBlocks(20, new ECB(4, 16), new ECB(4, 17)), new ECBlocks(24, new ECB(4, 12), new ECB(4, 13))))); - VERSIONS.push_back(Ref(new Version(10, intArray(3, 6, 28, 50), + getVersions().push_back(Ref(new Version(10, intArray(3, 6, 28, 50), new ECBlocks(18, new ECB(2, 68), new ECB(2, 69)), new ECBlocks(26, new ECB(4, 43), new ECB(1, 44)), new ECBlocks(24, new ECB(6, 19), new ECB(2, 20)), new ECBlocks(28, new ECB(6, 15), new ECB(2, 16))))); - VERSIONS.push_back( + getVersions().push_back( Ref(new Version(11, intArray(3, 6, 30, 54), new ECBlocks(20, new ECB(4, 81)), new ECBlocks(30, new ECB(1, 50), new ECB(4, 51)), new ECBlocks(28, new ECB(4, 22), new ECB(4, 23)), new ECBlocks(24, new ECB(3, 12), new ECB(8, 13))))); - VERSIONS.push_back(Ref(new Version(12, intArray(3, 6, 32, 58), + getVersions().push_back(Ref(new Version(12, intArray(3, 6, 32, 58), new ECBlocks(24, new ECB(2, 92), new ECB(2, 93)), new ECBlocks(22, new ECB(6, 36), new ECB(2, 37)), new ECBlocks(26, new ECB(4, 20), new ECB(6, 21)), new ECBlocks(28, new ECB(7, 14), new ECB(4, 15))))); - VERSIONS.push_back( + getVersions().push_back( Ref(new Version(13, intArray(3, 6, 34, 62), new ECBlocks(26, new ECB(4, 107)), new ECBlocks(22, new ECB(8, 37), new ECB(1, 38)), new ECBlocks(24, new ECB(8, 20), new ECB(4, 21)), new ECBlocks(22, new ECB(12, 11), new ECB(4, 12))))); - VERSIONS.push_back(Ref(new Version( + getVersions().push_back(Ref(new Version( 14, intArray(4, 6, 26, 46, 66), new ECBlocks(30, new ECB(3, 115), new ECB(1, 116)), new ECBlocks(24, new ECB(4, 40), new ECB(5, 41)), new ECBlocks(20, new ECB(11, 16), new ECB(5, 17)), new ECBlocks(24, new ECB(11, 12), new ECB(5, 13))))); - VERSIONS.push_back(Ref(new Version( + getVersions().push_back(Ref(new Version( 15, intArray(4, 6, 26, 48, 70), new ECBlocks(22, new ECB(5, 87), new ECB(1, 88)), new ECBlocks(24, new ECB(5, 41), new ECB(5, 42)), new ECBlocks(30, new ECB(5, 24), new ECB(7, 25)), new ECBlocks(24, new ECB(11, 12), new ECB(7, 13))))); - VERSIONS.push_back(Ref(new Version( + getVersions().push_back(Ref(new Version( 16, intArray(4, 6, 26, 50, 74), new ECBlocks(24, new ECB(5, 98), new ECB(1, 99)), new ECBlocks(28, new ECB(7, 45), new ECB(3, 46)), new ECBlocks(24, new ECB(15, 19), new ECB(2, 20)), new ECBlocks(30, new ECB(3, 15), new ECB(13, 16))))); - VERSIONS.push_back(Ref(new Version( + getVersions().push_back(Ref(new Version( 17, intArray(4, 6, 30, 54, 78), new ECBlocks(28, new ECB(1, 107), new ECB(5, 108)), new ECBlocks(28, new ECB(10, 46), new ECB(1, 47)), new ECBlocks(28, new ECB(1, 22), new ECB(15, 23)), new ECBlocks(28, new ECB(2, 14), new ECB(17, 15))))); - VERSIONS.push_back(Ref(new Version( + getVersions().push_back(Ref(new Version( 18, intArray(4, 6, 30, 56, 82), new ECBlocks(30, new ECB(5, 120), new ECB(1, 121)), new ECBlocks(26, new ECB(9, 43), new ECB(4, 44)), new ECBlocks(28, new ECB(17, 22), new ECB(1, 23)), new ECBlocks(28, new ECB(2, 14), new ECB(19, 15))))); - VERSIONS.push_back(Ref(new Version( + getVersions().push_back(Ref(new Version( 19, intArray(4, 6, 30, 58, 86), new ECBlocks(28, new ECB(3, 113), new ECB(4, 114)), new ECBlocks(26, new ECB(3, 44), new ECB(11, 45)), new ECBlocks(26, new ECB(17, 21), new ECB(4, 22)), new ECBlocks(26, new ECB(9, 13), new ECB(16, 14))))); - VERSIONS.push_back(Ref(new Version( + getVersions().push_back(Ref(new Version( 20, intArray(4, 6, 34, 62, 90), new ECBlocks(28, new ECB(3, 107), new ECB(5, 108)), new ECBlocks(26, new ECB(3, 41), new ECB(13, 42)), new ECBlocks(30, new ECB(15, 24), new ECB(5, 25)), new ECBlocks(28, new ECB(15, 15), new ECB(10, 16))))); - VERSIONS.push_back(Ref(new Version( + getVersions().push_back(Ref(new Version( 21, intArray(5, 6, 28, 50, 72, 94), new ECBlocks(28, new ECB(4, 116), new ECB(4, 117)), new ECBlocks(26, new ECB(17, 42)), new ECBlocks(28, new ECB(17, 22), new ECB(6, 23)), new ECBlocks(30, new ECB(19, 16), new ECB(6, 17))))); - VERSIONS.push_back(Ref(new Version( + getVersions().push_back(Ref(new Version( 22, intArray(5, 6, 26, 50, 74, 98), new ECBlocks(28, new ECB(2, 111), new ECB(7, 112)), new ECBlocks(28, new ECB(17, 46)), new ECBlocks(30, new ECB(7, 24), new ECB(16, 25)), new ECBlocks(24, new ECB(34, 13))))); - VERSIONS.push_back(Ref(new Version( + getVersions().push_back(Ref(new Version( 23, intArray(5, 6, 30, 54, 78, 102), new ECBlocks(30, new ECB(4, 121), new ECB(5, 122)), new ECBlocks(28, new ECB(4, 47), new ECB(14, 48)), new ECBlocks(30, new ECB(11, 24), new ECB(14, 25)), new ECBlocks(30, new ECB(16, 15), new ECB(14, 16))))); - VERSIONS.push_back(Ref(new Version( + getVersions().push_back(Ref(new Version( 24, intArray(5, 6, 28, 54, 80, 106), new ECBlocks(30, new ECB(6, 117), new ECB(4, 118)), new ECBlocks(28, new ECB(6, 45), new ECB(14, 46)), new ECBlocks(30, new ECB(11, 24), new ECB(16, 25)), new ECBlocks(30, new ECB(30, 16), new ECB(2, 17))))); - VERSIONS.push_back(Ref(new Version( + getVersions().push_back(Ref(new Version( 25, intArray(5, 6, 32, 58, 84, 110), new ECBlocks(26, new ECB(8, 106), new ECB(4, 107)), new ECBlocks(28, new ECB(8, 47), new ECB(13, 48)), new ECBlocks(30, new ECB(7, 24), new ECB(22, 25)), new ECBlocks(30, new ECB(22, 15), new ECB(13, 16))))); - VERSIONS.push_back(Ref(new Version( + getVersions().push_back(Ref(new Version( 26, intArray(5, 6, 30, 58, 86, 114), new ECBlocks(28, new ECB(10, 114), new ECB(2, 115)), new ECBlocks(28, new ECB(19, 46), new ECB(4, 47)), new ECBlocks(28, new ECB(28, 22), new ECB(6, 23)), new ECBlocks(30, new ECB(33, 16), new ECB(4, 17))))); - VERSIONS.push_back(Ref(new Version( + getVersions().push_back(Ref(new Version( 27, intArray(5, 6, 34, 62, 90, 118), new ECBlocks(30, new ECB(8, 122), new ECB(4, 123)), new ECBlocks(28, new ECB(22, 45), new ECB(3, 46)), new ECBlocks(30, new ECB(8, 23), new ECB(26, 24)), new ECBlocks(30, new ECB(12, 15), new ECB(28, 16))))); - VERSIONS.push_back( + getVersions().push_back( Ref(new Version(28, intArray(6, 6, 26, 50, 74, 98, 122), new ECBlocks(30, new ECB(3, 117), new ECB(10, 118)), new ECBlocks(28, new ECB(3, 45), new ECB(23, 46)), new ECBlocks(30, new ECB(4, 24), new ECB(31, 25)), new ECBlocks(30, new ECB(11, 15), new ECB(31, 16))))); - VERSIONS.push_back( + getVersions().push_back( Ref(new Version(29, intArray(6, 6, 30, 54, 78, 102, 126), new ECBlocks(30, new ECB(7, 116), new ECB(7, 117)), new ECBlocks(28, new ECB(21, 45), new ECB(7, 46)), new ECBlocks(30, new ECB(1, 23), new ECB(37, 24)), new ECBlocks(30, new ECB(19, 15), new ECB(26, 16))))); - VERSIONS.push_back( + getVersions().push_back( Ref(new Version(30, intArray(6, 6, 26, 52, 78, 104, 130), new ECBlocks(30, new ECB(5, 115), new ECB(10, 116)), new ECBlocks(28, new ECB(19, 47), new ECB(10, 48)), new ECBlocks(30, new ECB(15, 24), new ECB(25, 25)), new ECBlocks(30, new ECB(23, 15), new ECB(25, 16))))); - VERSIONS.push_back( + getVersions().push_back( Ref(new Version(31, intArray(6, 6, 30, 56, 82, 108, 134), new ECBlocks(30, new ECB(13, 115), new ECB(3, 116)), new ECBlocks(28, new ECB(2, 46), new ECB(29, 47)), new ECBlocks(30, new ECB(42, 24), new ECB(1, 25)), new ECBlocks(30, new ECB(23, 15), new ECB(28, 16))))); - VERSIONS.push_back(Ref( + getVersions().push_back(Ref( new Version(32, intArray(6, 6, 34, 60, 86, 112, 138), new ECBlocks(30, new ECB(17, 115)), new ECBlocks(28, new ECB(10, 46), new ECB(23, 47)), new ECBlocks(30, new ECB(10, 24), new ECB(35, 25)), new ECBlocks(30, new ECB(19, 15), new ECB(35, 16))))); - VERSIONS.push_back( + getVersions().push_back( Ref(new Version(33, intArray(6, 6, 30, 58, 86, 114, 142), new ECBlocks(30, new ECB(17, 115), new ECB(1, 116)), new ECBlocks(28, new ECB(14, 46), new ECB(21, 47)), new ECBlocks(30, new ECB(29, 24), new ECB(19, 25)), new ECBlocks(30, new ECB(11, 15), new ECB(46, 16))))); - VERSIONS.push_back( + getVersions().push_back( Ref(new Version(34, intArray(6, 6, 34, 62, 90, 118, 146), new ECBlocks(30, new ECB(13, 115), new ECB(6, 116)), new ECBlocks(28, new ECB(14, 46), new ECB(23, 47)), new ECBlocks(30, new ECB(44, 24), new ECB(7, 25)), new ECBlocks(30, new ECB(59, 16), new ECB(1, 17))))); - VERSIONS.push_back( + getVersions().push_back( Ref(new Version(35, intArray(7, 6, 30, 54, 78, 102, 126, 150), new ECBlocks(30, new ECB(12, 121), new ECB(7, 122)), new ECBlocks(28, new ECB(12, 47), new ECB(26, 48)), new ECBlocks(30, new ECB(39, 24), new ECB(14, 25)), new ECBlocks(30, new ECB(22, 15), new ECB(41, 16))))); - VERSIONS.push_back( + getVersions().push_back( Ref(new Version(36, intArray(7, 6, 24, 50, 76, 102, 128, 154), new ECBlocks(30, new ECB(6, 121), new ECB(14, 122)), new ECBlocks(28, new ECB(6, 47), new ECB(34, 48)), new ECBlocks(30, new ECB(46, 24), new ECB(10, 25)), new ECBlocks(30, new ECB(2, 15), new ECB(64, 16))))); - VERSIONS.push_back( + getVersions().push_back( Ref(new Version(37, intArray(7, 6, 28, 54, 80, 106, 132, 158), new ECBlocks(30, new ECB(17, 122), new ECB(4, 123)), new ECBlocks(28, new ECB(29, 46), new ECB(14, 47)), new ECBlocks(30, new ECB(49, 24), new ECB(10, 25)), new ECBlocks(30, new ECB(24, 15), new ECB(46, 16))))); - VERSIONS.push_back( + getVersions().push_back( Ref(new Version(38, intArray(7, 6, 32, 58, 84, 110, 136, 162), new ECBlocks(30, new ECB(4, 122), new ECB(18, 123)), new ECBlocks(28, new ECB(13, 46), new ECB(32, 47)), new ECBlocks(30, new ECB(48, 24), new ECB(14, 25)), new ECBlocks(30, new ECB(42, 15), new ECB(32, 16))))); - VERSIONS.push_back( + getVersions().push_back( Ref(new Version(39, intArray(7, 6, 26, 54, 82, 110, 138, 166), new ECBlocks(30, new ECB(20, 117), new ECB(4, 118)), new ECBlocks(28, new ECB(40, 47), new ECB(7, 48)), new ECBlocks(30, new ECB(43, 24), new ECB(22, 25)), new ECBlocks(30, new ECB(10, 15), new ECB(67, 16))))); - VERSIONS.push_back( + getVersions().push_back( Ref(new Version(40, intArray(7, 6, 30, 58, 86, 114, 142, 170), new ECBlocks(30, new ECB(19, 118), new ECB(6, 119)), new ECBlocks(28, new ECB(18, 47), new ECB(31, 48)), new ECBlocks(30, new ECB(34, 24), new ECB(34, 25)), new ECBlocks(30, new ECB(20, 15), new ECB(61, 16))))); - return VERSIONS.size(); + return getVersions().size(); } } // namespace qrcode diff --git a/modules/wechat_qrcode/src/zxing/qrcode/version.hpp b/modules/wechat_qrcode/src/zxing/qrcode/version.hpp index 68bb76740b..7392ee7713 100644 --- a/modules/wechat_qrcode/src/zxing/qrcode/version.hpp +++ b/modules/wechat_qrcode/src/zxing/qrcode/version.hpp @@ -64,7 +64,7 @@ class Version : public Counted { public: static unsigned int VERSION_DECODE_INFO[]; static int N_VERSION_DECODE_INFOS; - static std::vector > VERSIONS; + static std::vector >& getVersions(); ~Version(); int getVersionNumber();