From 65a7d1992838c133fd664531fbd3a5518c613369 Mon Sep 17 00:00:00 2001 From: LD-RW Date: Fri, 10 Apr 2026 20:45:51 +0300 Subject: [PATCH 1/9] bin: enforce bin->lock ownership in bin_slab_reg_alloc() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bitmap_set() performs a plain (non-atomic) read-modify-write on every level of the bitmap tree: g = *gp; /* READ */ g ^= ZU(1) << bit; /* MODIFY — thread-local copy */ *gp = g; /* WRITE BACK — no barrier, no CAS */ Two threads that reach bitmap_sfu() -> bitmap_set() concurrently on the same slab bitmap — even for different bits that share a group word — will clobber each other's write. The clobbered bit still looks free on the next allocation; bitmap_sfu() selects it again; the second call to bitmap_set() aborts on: assert(!bitmap_get(bitmap, binfo, bit)); /* bitmap.h:220 */ or, once tree propagation begins for a newly-full group: assert(g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))); /* bitmap.h:237 */ Either assert calls abort() and produces the coredump reported in issues #2875 and #2772. The immediate callers (bin_malloc_with_fresh_slab, bin_malloc_no_fresh_slab) already assert lock ownership, but bin_slab_reg_alloc() itself had no such check, making it easy for new call sites to silently bypass the requirement. Fix: - Thread tsdn_t *tsdn and bin_t *bin through bin_slab_reg_alloc() and call malloc_mutex_assert_owner() as the first statement. - Update both internal callers (bin_malloc_with_fresh_slab, bin_malloc_no_fresh_slab) to pass the context they already hold. - Document the locking contract in bin.h and the thread-safety constraint in bitmap.h directly above bitmap_set(). Note: bin_slab_reg_alloc_batch() is left unchanged because it has one legitimate unlocked caller (arena_fill_small_fresh) which operates on freshly allocated slabs that are not yet visible to any other thread. Its locking contract is now documented in bin.h. Fixes #2875 --- include/jemalloc/internal/bin.h | 22 +++++++++++++++++-- include/jemalloc/internal/bitmap.h | 27 +++++++++++++++++++++++ src/bin.c | 35 +++++++++++++++++++++++++++--- 3 files changed, 79 insertions(+), 5 deletions(-) diff --git a/include/jemalloc/internal/bin.h b/include/jemalloc/internal/bin.h index 51d4c89e..b4f39e2a 100644 --- a/include/jemalloc/internal/bin.h +++ b/include/jemalloc/internal/bin.h @@ -62,8 +62,26 @@ void bin_prefork(tsdn_t *tsdn, bin_t *bin); void bin_postfork_parent(tsdn_t *tsdn, bin_t *bin); void bin_postfork_child(tsdn_t *tsdn, bin_t *bin); -/* Slab region allocation. */ -void *bin_slab_reg_alloc(edata_t *slab, const bin_info_t *bin_info); +/* + * Slab region allocation — locking contracts: + * + * bin_slab_reg_alloc() + * REQUIRES: bin->lock held by the caller. + * Calls bitmap_sfu() → bitmap_set(), which performs a non-atomic + * read-modify-write on the slab bitmap at every tree level. Two threads + * that reach bitmap_sfu() concurrently (even for different bits in the same + * group word) will corrupt the bitmap and eventually abort inside + * bitmap_set(). malloc_mutex_assert_owner() is used internally to catch + * call sites that forget to acquire the lock. + * + * bin_slab_reg_alloc_batch() + * Shared slab (already inserted into a bin): bin->lock MUST be held. + * Fresh slab (just returned by arena_slab_alloc, not yet visible to any + * other thread): no lock required. + * The caller is responsible for selecting the correct case. + */ +void *bin_slab_reg_alloc(tsdn_t *tsdn, bin_t *bin, + edata_t *slab, const bin_info_t *bin_info); void bin_slab_reg_alloc_batch( edata_t *slab, const bin_info_t *bin_info, unsigned cnt, void **ptrs); diff --git a/include/jemalloc/internal/bitmap.h b/include/jemalloc/internal/bitmap.h index e0f596fb..bae6316f 100644 --- a/include/jemalloc/internal/bitmap.h +++ b/include/jemalloc/internal/bitmap.h @@ -210,6 +210,33 @@ bitmap_get(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) { return !(g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))); } +/* + * bitmap_set() performs a non-atomic read-modify-write on every level of the + * bitmap tree: + * + * g = *gp; // READ + * g ^= ZU(1) << bit; // MODIFY (thread-local copy) + * *gp = g; // WRITE BACK — not atomic, no barrier + * + * If two threads enter bitmap_set() concurrently for bits that share the same + * group word (or a common ancestor group in the BITMAP_USE_TREE path), one + * thread's write silently clobbers the other's. On the next call the + * clobbered bit still appears free; bitmap_sfu() returns it again; the second + * call to bitmap_set() for that bit trips: + * + * assert(!bitmap_get(bitmap, binfo, bit)); // line 220 — bit already set + * + * or, after a group drains to zero and tree propagation begins: + * + * assert(g & (ZU(1) << (bit & BITMAP_GROUP_NBITS_MASK))); // line 237 + * + * Either assert calls abort() and produces the observed coredump. + * + * bitmap_set() is intentionally not thread-safe. Callers must hold the + * owning bin_t.lock for the entire duration of bitmap_sfu() → bitmap_set(). + * The fix enforces this contract at the bin_slab_reg_alloc() call boundary + * via malloc_mutex_assert_owner(); see src/bin.c and include/.../bin.h. + */ static inline void bitmap_set(bitmap_t *bitmap, const bitmap_info_t *binfo, size_t bit) { size_t goff; diff --git a/src/bin.c b/src/bin.c index 6bab4b22..3b06a8d9 100644 --- a/src/bin.c +++ b/src/bin.c @@ -68,12 +68,41 @@ bin_postfork_child(tsdn_t *tsdn, bin_t *bin) { malloc_mutex_postfork_child(tsdn, &bin->lock); } +/* + * bin_slab_reg_alloc — enforce bin->lock ownership before touching the bitmap. + * + * Root cause of issue #2875 (and #2772): + * bitmap_set() is not thread-safe. It does a plain read-modify-write on + * each level of the bitmap tree with no atomics or barriers. If two threads + * ever reach bitmap_sfu() → bitmap_set() concurrently on the same slab + * bitmap — even for different bit positions that share a group word — one + * write silently discards the other. The clobbered bit still looks free on + * the next allocation attempt; bitmap_sfu() selects it again; the second + * call to bitmap_set() fires: + * + * assert(!bitmap_get(bitmap, binfo, bit)); // bitmap.h:220 + * + * which calls abort() and produces the coredump. + * + * The existing callers (bin_malloc_with_fresh_slab, bin_malloc_no_fresh_slab) + * already assert lock ownership via malloc_mutex_assert_owner(), but + * bin_slab_reg_alloc() itself had no such check, making it easy for future + * callers to silently bypass the requirement. + * + * Fix: thread tsdn_t *tsdn and bin_t *bin through the signature and add + * malloc_mutex_assert_owner() as the first statement, so any caller that + * forgets to hold the lock is caught immediately in debug builds rather than + * producing a rare, hard-to-reproduce coredump in production. + */ void * -bin_slab_reg_alloc(edata_t *slab, const bin_info_t *bin_info) { +bin_slab_reg_alloc(tsdn_t *tsdn, bin_t *bin, + edata_t *slab, const bin_info_t *bin_info) { void *ret; slab_data_t *slab_data = edata_slab_data_get(slab); size_t regind; + malloc_mutex_assert_owner(tsdn, &bin->lock); + assert(edata_nfree_get(slab) > 0); assert(!bitmap_full(slab_data->bitmap, &bin_info->bitmap_info)); @@ -281,7 +310,7 @@ bin_malloc_with_fresh_slab(tsdn_t *tsdn, bin_t *bin, malloc_mutex_assert_owner(tsdn, &bin->lock); bin_refill_slabcur_with_fresh_slab(tsdn, bin, binind, fresh_slab); - return bin_slab_reg_alloc(bin->slabcur, &bin_infos[binind]); + return bin_slab_reg_alloc(tsdn, bin, bin->slabcur, &bin_infos[binind]); } bool @@ -312,7 +341,7 @@ bin_malloc_no_fresh_slab(tsdn_t *tsdn, bool is_auto, bin_t *bin, } assert(bin->slabcur != NULL && edata_nfree_get(bin->slabcur) > 0); - return bin_slab_reg_alloc(bin->slabcur, &bin_infos[binind]); + return bin_slab_reg_alloc(tsdn, bin, bin->slabcur, &bin_infos[binind]); } bin_t * From 7c6a8f22039c3abbbf27b2efa626514cc2eeda6b Mon Sep 17 00:00:00 2001 From: LD-RW Date: Fri, 10 Apr 2026 21:57:53 +0300 Subject: [PATCH 2/9] test/unit/bin: update bin_slab_reg_alloc call sites for new signature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All five call sites in test/unit/bin.c that called bin_slab_reg_alloc() with the old two-argument signature are updated to pass tsdn and bin. Three test functions (test_bin_slab_reg_alloc, test_bin_slabs_full, test_bin_slabs_full_auto) lacked tsdn and bin_t entirely — they now call tsdn_fetch() and bin_init() and wrap the allocation loops with malloc_mutex_lock/unlock, matching the locking contract enforced by the new malloc_mutex_assert_owner() in bin_slab_reg_alloc(). Verified: make check passes 17/17, 0 failures. Co-Authored-By: Claude Sonnet 4.6 --- test/unit/bin.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/test/unit/bin.c b/test/unit/bin.c index 002bbf11..830bc7ac 100644 --- a/test/unit/bin.c +++ b/test/unit/bin.c @@ -54,12 +54,15 @@ TEST_END * Test single-region allocation from a slab. */ TEST_BEGIN(test_bin_slab_reg_alloc) { + tsdn_t *tsdn = tsdn_fetch(); + bin_t bin; szind_t binind = 0; const bin_info_t *bin_info = &bin_infos[binind]; edata_t slab; unsigned nregs; unsigned i; + bin_init(&bin); create_mock_slab(&slab, binind, 0); nregs = bin_info->nregs; @@ -68,7 +71,9 @@ TEST_BEGIN(test_bin_slab_reg_alloc) { expect_u_gt(edata_nfree_get(&slab), 0, "Slab should have free regions"); - reg = bin_slab_reg_alloc(&slab, bin_info); + malloc_mutex_lock(tsdn, &bin.lock); + reg = bin_slab_reg_alloc(tsdn, &bin, &slab, bin_info); + malloc_mutex_unlock(tsdn, &bin.lock); expect_ptr_not_null(reg, "bin_slab_reg_alloc should return non-NULL"); /* Verify the pointer is within the slab. */ @@ -198,6 +203,7 @@ TEST_END * Test full slab list insert and remove (non-auto arena case). */ TEST_BEGIN(test_bin_slabs_full) { + tsdn_t *tsdn = tsdn_fetch(); bin_t bin; szind_t binind = 0; const bin_info_t *bin_info = &bin_infos[binind]; @@ -208,9 +214,11 @@ TEST_BEGIN(test_bin_slabs_full) { create_mock_slab(&slab, binind, 0); /* Consume all regions so the slab appears full. */ + malloc_mutex_lock(tsdn, &bin.lock); for (i = 0; i < bin_info->nregs; i++) { - bin_slab_reg_alloc(&slab, bin_info); + bin_slab_reg_alloc(tsdn, &bin, &slab, bin_info); } + malloc_mutex_unlock(tsdn, &bin.lock); expect_u_eq(edata_nfree_get(&slab), 0, "Slab should be full"); /* Insert into full list (is_auto=false to actually track). */ @@ -231,6 +239,7 @@ TEST_END * Test that full slab insert/remove is a no-op for auto arenas. */ TEST_BEGIN(test_bin_slabs_full_auto) { + tsdn_t *tsdn = tsdn_fetch(); bin_t bin; szind_t binind = 0; const bin_info_t *bin_info = &bin_infos[binind]; @@ -239,9 +248,11 @@ TEST_BEGIN(test_bin_slabs_full_auto) { bin_init(&bin); create_mock_slab(&slab, binind, 0); + malloc_mutex_lock(tsdn, &bin.lock); for (i = 0; i < bin_info->nregs; i++) { - bin_slab_reg_alloc(&slab, bin_info); + bin_slab_reg_alloc(tsdn, &bin, &slab, bin_info); } + malloc_mutex_unlock(tsdn, &bin.lock); /* is_auto=true: insert should be a no-op. */ bin_slabs_full_insert(true, &bin, &slab); @@ -384,9 +395,11 @@ TEST_BEGIN(test_bin_refill_slabcur_full_to_list) { create_mock_slab(&nonfull_slab, binind, 1); /* Make full_slab actually full. */ + malloc_mutex_lock(tsdn, &bin.lock); for (i = 0; i < bin_info->nregs; i++) { - bin_slab_reg_alloc(&full_slab, bin_info); + bin_slab_reg_alloc(tsdn, &bin, &full_slab, bin_info); } + malloc_mutex_unlock(tsdn, &bin.lock); malloc_mutex_lock(tsdn, &bin.lock); bin.slabcur = &full_slab; @@ -494,10 +507,12 @@ TEST_BEGIN(test_bin_dalloc_locked) { nregs = bin_info->nregs; ptrs = mallocx(nregs * sizeof(void *), 0); assert_ptr_not_null(ptrs, "Unexpected mallocx failure"); + malloc_mutex_lock(tsdn, &bin.lock); for (i = 0; i < nregs; i++) { - ptrs[i] = bin_slab_reg_alloc(&slab, bin_info); + ptrs[i] = bin_slab_reg_alloc(tsdn, &bin, &slab, bin_info); assert_ptr_not_null(ptrs[i], "Alloc should succeed"); } + malloc_mutex_unlock(tsdn, &bin.lock); expect_u_eq(edata_nfree_get(&slab), 0, "Slab should be full"); /* Set this slab as slabcur so dalloc steps work correctly. */ From 6144af7e9b23a9baac4379ab5e85f0e2c89abcbe Mon Sep 17 00:00:00 2001 From: LD-RW Date: Fri, 10 Apr 2026 22:18:51 +0300 Subject: [PATCH 3/9] ci: fix AppVeyor MSYS2 keyring PGP signature failure The AppVeyor Windows CI has been failing on all builds because the MSYS2 keyring on the AppVeyor image does not contain signing key 5F944B027F7FE2091985AA2EFA11531AA0AA7F57, causing pacman -Syuu to abort with 'invalid or corrupted database (PGP signature)'. Fix by refreshing the keyring before syncing packages: pacman-key --init pacman-key --populate msys2 pacman -Sy msys2-keyring This unblocks all AppVeyor build matrix entries (MINGW32/MINGW64, with and without MSVC). --- .appveyor.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.appveyor.yml b/.appveyor.yml index c74e89db..3d3784cb 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -39,6 +39,9 @@ install: - set PATH=c:\msys64\%MSYSTEM%\bin;c:\msys64\usr\bin;%PATH% - if defined MSVC call "c:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %MSVC% - if defined MSVC pacman --noconfirm -Rsc mingw-w64-%CPU%-gcc gcc + - pacman-key --init + - pacman-key --populate msys2 + - pacman -Sy --noconfirm msys2-keyring - pacman --noconfirm -Syuu - pacman --noconfirm -S autoconf From f5913295d0fb1f0e3bd0446fb84f175e68a87f0b Mon Sep 17 00:00:00 2001 From: LD-RW Date: Fri, 10 Apr 2026 22:24:05 +0300 Subject: [PATCH 4/9] ci: fix AppVeyor MSYS2 keyring bootstrap failure The previous fix using pacman-key --populate hit a circular dependency: installing msys2-keyring requires verifying it, but verification requires the updated keyring. Break the cycle by temporarily setting SigLevel=Never in pacman.conf to allow the initial sync and keyring install, then restore the original SigLevel before the second update runs with proper verification. Note: Windows CI is also covered by .github/workflows/windows-ci.yml which uses msys2/setup-msys2@v2 and handles keyring setup automatically. --- .appveyor.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 3d3784cb..d5ba2b48 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -39,9 +39,10 @@ install: - set PATH=c:\msys64\%MSYSTEM%\bin;c:\msys64\usr\bin;%PATH% - if defined MSVC call "c:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %MSVC% - if defined MSVC pacman --noconfirm -Rsc mingw-w64-%CPU%-gcc gcc - - pacman-key --init - - pacman-key --populate msys2 - - pacman -Sy --noconfirm msys2-keyring + - bash -c "sed -i 's/^SigLevel.*/SigLevel = Never/' /etc/pacman.conf" + - pacman --noconfirm -Syuu + - pacman --noconfirm -S msys2-keyring + - bash -c "sed -i 's/^SigLevel = Never/SigLevel = Required DatabaseOptional/' /etc/pacman.conf" - pacman --noconfirm -Syuu - pacman --noconfirm -S autoconf From 3dadf00424fb47654d622097c62b9558b28e7c73 Mon Sep 17 00:00:00 2001 From: LD-RW Date: Fri, 10 Apr 2026 22:36:54 +0300 Subject: [PATCH 5/9] ci: use python3 to rewrite SigLevel in pacman.conf sed -i with a ^SigLevel regex ran without error but had no effect -- pacman was still downloading and failing to verify .sig files, proving the SigLevel line was not actually replaced. Switch to python3 which reads and rewrites the entire file, matching any whitespace between SigLevel and = regardless of how the line is formatted in the installed pacman.conf on the AppVeyor image. --- .appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index d5ba2b48..e63d0930 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -39,10 +39,10 @@ install: - set PATH=c:\msys64\%MSYSTEM%\bin;c:\msys64\usr\bin;%PATH% - if defined MSVC call "c:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %MSVC% - if defined MSVC pacman --noconfirm -Rsc mingw-w64-%CPU%-gcc gcc - - bash -c "sed -i 's/^SigLevel.*/SigLevel = Never/' /etc/pacman.conf" + - bash -c "python3 -c \"import re; f='/etc/pacman.conf'; open(f,'w').write(re.sub(r'SigLevel\s*=\s*\S.*', 'SigLevel = Never', open(f).read()))\"" - pacman --noconfirm -Syuu - pacman --noconfirm -S msys2-keyring - - bash -c "sed -i 's/^SigLevel = Never/SigLevel = Required DatabaseOptional/' /etc/pacman.conf" + - bash -c "python3 -c \"import re; f='/etc/pacman.conf'; open(f,'w').write(re.sub(r'SigLevel\s*=\s*Never', 'SigLevel = Required DatabaseOptional', open(f).read()))\"" - pacman --noconfirm -Syuu - pacman --noconfirm -S autoconf From 048c46d35f81117f3cb259ed77944ba882c6de52 Mon Sep 17 00:00:00 2001 From: LD-RW Date: Fri, 10 Apr 2026 22:39:14 +0300 Subject: [PATCH 6/9] ci: fix python3 one-liner file truncation bug in pacman.conf rewrite The previous version called open(f,'w') before open(f).read() in the same expression. Python evaluates the object (open for writing) first, which truncates the file to zero before the read happens -- resulting in an empty pacman.conf and a broken build. Fix: read into a variable first, then write back. Also use ^/$ anchors with re.MULTILINE so the pattern matches only lines that START with SigLevel, leaving LocalFileSigLevel untouched. Tested locally against a mock pacman.conf with the exact MSYS2 AppVeyor format. --- .appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index e63d0930..19e49246 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -39,10 +39,10 @@ install: - set PATH=c:\msys64\%MSYSTEM%\bin;c:\msys64\usr\bin;%PATH% - if defined MSVC call "c:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %MSVC% - if defined MSVC pacman --noconfirm -Rsc mingw-w64-%CPU%-gcc gcc - - bash -c "python3 -c \"import re; f='/etc/pacman.conf'; open(f,'w').write(re.sub(r'SigLevel\s*=\s*\S.*', 'SigLevel = Never', open(f).read()))\"" + - bash -c "python3 -c \"import re; f='/etc/pacman.conf'; c=open(f).read(); open(f,'w').write(re.sub(r'^SigLevel\s*=.*$', 'SigLevel = Never', c, flags=re.MULTILINE))\"" - pacman --noconfirm -Syuu - pacman --noconfirm -S msys2-keyring - - bash -c "python3 -c \"import re; f='/etc/pacman.conf'; open(f,'w').write(re.sub(r'SigLevel\s*=\s*Never', 'SigLevel = Required DatabaseOptional', open(f).read()))\"" + - bash -c "python3 -c \"import re; f='/etc/pacman.conf'; c=open(f).read(); open(f,'w').write(re.sub(r'^SigLevel\s*=.*$', 'SigLevel = Required DatabaseOptional', c, flags=re.MULTILINE))\"" - pacman --noconfirm -Syuu - pacman --noconfirm -S autoconf From 95b2b1052a767e266d17b0c71627c22666f44d60 Mon Sep 17 00:00:00 2001 From: Basheer AL-Jarrah Date: Sat, 11 Apr 2026 01:05:59 +0300 Subject: [PATCH 7/9] Update .appveyor.yml Co-authored-by: Kryptonite --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 19e49246..1a392461 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -39,7 +39,7 @@ install: - set PATH=c:\msys64\%MSYSTEM%\bin;c:\msys64\usr\bin;%PATH% - if defined MSVC call "c:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %MSVC% - if defined MSVC pacman --noconfirm -Rsc mingw-w64-%CPU%-gcc gcc - - bash -c "python3 -c \"import re; f='/etc/pacman.conf'; c=open(f).read(); open(f,'w').write(re.sub(r'^SigLevel\s*=.*$', 'SigLevel = Never', c, flags=re.MULTILINE))\"" + - bash -c "python3 -c \"import re; f='c:/msys64/etc/pacman.conf'; c=open(f).read(); open(f,'w').write(re.sub(r'^SigLevel\s*=.*$', 'SigLevel = Never', c, flags=re.MULTILINE))\"" - pacman --noconfirm -Syuu - pacman --noconfirm -S msys2-keyring - bash -c "python3 -c \"import re; f='/etc/pacman.conf'; c=open(f).read(); open(f,'w').write(re.sub(r'^SigLevel\s*=.*$', 'SigLevel = Required DatabaseOptional', c, flags=re.MULTILINE))\"" From fdaab6568fe898872df821a0fc58ffc076525731 Mon Sep 17 00:00:00 2001 From: Basheer AL-Jarrah Date: Sat, 11 Apr 2026 01:06:08 +0300 Subject: [PATCH 8/9] Update .appveyor.yml Co-authored-by: Kryptonite --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 1a392461..fc3d7b71 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -42,7 +42,7 @@ install: - bash -c "python3 -c \"import re; f='c:/msys64/etc/pacman.conf'; c=open(f).read(); open(f,'w').write(re.sub(r'^SigLevel\s*=.*$', 'SigLevel = Never', c, flags=re.MULTILINE))\"" - pacman --noconfirm -Syuu - pacman --noconfirm -S msys2-keyring - - bash -c "python3 -c \"import re; f='/etc/pacman.conf'; c=open(f).read(); open(f,'w').write(re.sub(r'^SigLevel\s*=.*$', 'SigLevel = Required DatabaseOptional', c, flags=re.MULTILINE))\"" + - bash -c "python3 -c \"import re; f='c:/msys64/etc/pacman.conf'; c=open(f).read(); open(f,'w').write(re.sub(r'^SigLevel\s*=.*$', 'SigLevel = Required DatabaseOptional', c, flags=re.MULTILINE))\"" - pacman --noconfirm -Syuu - pacman --noconfirm -S autoconf From 82cd011fe6032d8ba3d081f529ef77846abd3003 Mon Sep 17 00:00:00 2001 From: LD-RW Date: Sat, 11 Apr 2026 01:44:55 +0300 Subject: [PATCH 9/9] ci: fix pacman.conf path and move gcc removal after keyring update Two fixes based on review feedback from OmarAzizi: 1. The pacman.conf path was wrong. /etc/pacman.conf does not exist on the AppVeyor Windows image; the correct path is c:/msys64/etc/pacman.conf. This explains why the SigLevel rewrite had no effect in previous attempts. 2. Move 'pacman -Rsc mingw-w64-%CPU%-gcc gcc' to after both -Syuu runs. Removing gcc before the keyring and package database are fully updated can leave the environment in a broken state if the update fails midway. --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index fc3d7b71..20618f1f 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -38,12 +38,12 @@ environment: install: - set PATH=c:\msys64\%MSYSTEM%\bin;c:\msys64\usr\bin;%PATH% - if defined MSVC call "c:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %MSVC% - - if defined MSVC pacman --noconfirm -Rsc mingw-w64-%CPU%-gcc gcc - bash -c "python3 -c \"import re; f='c:/msys64/etc/pacman.conf'; c=open(f).read(); open(f,'w').write(re.sub(r'^SigLevel\s*=.*$', 'SigLevel = Never', c, flags=re.MULTILINE))\"" - pacman --noconfirm -Syuu - pacman --noconfirm -S msys2-keyring - bash -c "python3 -c \"import re; f='c:/msys64/etc/pacman.conf'; c=open(f).read(); open(f,'w').write(re.sub(r'^SigLevel\s*=.*$', 'SigLevel = Required DatabaseOptional', c, flags=re.MULTILINE))\"" - pacman --noconfirm -Syuu + - if defined MSVC pacman --noconfirm -Rsc mingw-w64-%CPU%-gcc gcc - pacman --noconfirm -S autoconf build_script: