Skip to content

Commit c78d8ff

Browse files
l0rinchodlinatorryanofsky
committed
prevector: avoid GCC bogus warnings in insert method
When compiling with GCC 12.2, both `-Warray-bounds` and `-Wstringop-overflow` warnings were triggered in the `prevector::insert` method during CScript prevector operations. GCC incorrectly assumed that operator new could modify the state of class members, leading to false positives during the memmove operation. Following the approach in https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=cca06f0d6d76b0, we introduced local copies for the destination pointer in memmove operations. This prevents GCC from misinterpreting memory manipulation as unsafe. A minimal reproducer triggering this issue in GCC 12.2 and passing in GCC 12.3 can be found at https://godbolt.org/z/8r9TKKoxv. ------- Full error (with changes from the next commit as well): ``` In file included from /ci_container_base/src/script/script.h:11, from /ci_container_base/src/primitives/transaction.h:11, from /ci_container_base/src/primitives/block.h:9, from /ci_container_base/src/kernel/chainparams.h:11, from /ci_container_base/src/kernel/chainparams.cpp:6: In member function ‘void prevector<N, T, Size, Diff>::fill(T*, InputIterator, InputIterator) [with InputIterator = const unsigned char*; unsigned int N = 28; T = unsigned char; Size = unsigned int; Diff = int]’, inlined from ‘void prevector<N, T, Size, Diff>::insert(iterator, InputIterator, InputIterator) [with InputIterator = const unsigned char*; unsigned int N = 28; T = unsigned char; Size = unsigned int; Diff = int]’ at /ci_container_base/src/prevector.h:395:13, inlined from ‘void CScript::AppendData(const prevector<28, unsigned char>::value_type*, size_t)’ at /ci_container_base/src/script/script.h:439:15, inlined from ‘CScript& CScript::operator<<(std::span<const std::byte>)’ at /ci_container_base/src/script/script.h:496:17, inlined from ‘CBlock CreateGenesisBlock(uint32_t, uint32_t, uint32_t, int32_t, const CAmount&)’ at /ci_container_base/src/kernel/chainparams.cpp:76:54: /ci_container_base/src/prevector.h:216:13: error: writing 65 bytes into a region of size 32 [-Werror=stringop-overflow=] 216 | new(static_cast<void*>(dst)) T(*first); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /ci_container_base/src/kernel/chainparams.cpp: In function ‘CBlock CreateGenesisBlock(uint32_t, uint32_t, uint32_t, int32_t, const CAmount&)’: /ci_container_base/src/kernel/chainparams.cpp:76:49: note: destination object ‘<anonymous>’ of size 32 76 | const CScript genesisOutputScript = CScript() << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"_hex << OP_CHECKSIG; | ^ In file included from /usr/lib/gcc/x86_64-w64-mingw32/12-posix/include/c++/cstring:42, from /ci_container_base/src/crypto/common.h:11, from /ci_container_base/src/uint256.h:9, from /ci_container_base/src/consensus/params.h:9, from /ci_container_base/src/kernel/chainparams.h:9: In function ‘void* memmove(void*, const void*, size_t)’, inlined from ‘void prevector<N, T, Size, Diff>::insert(iterator, InputIterator, InputIterator) [with InputIterator = const unsigned char*; unsigned int N = 28; T = unsigned char; Size = unsigned int; Diff = int]’ at /ci_container_base/src/prevector.h:393:16, inlined from ‘void CScript::AppendData(const prevector<28, unsigned char>::value_type*, size_t)’ at /ci_container_base/src/script/script.h:439:15, inlined from ‘CScript& CScript::operator<<(std::span<const std::byte>)’ at /ci_container_base/src/script/script.h:496:17, inlined from ‘CBlock CreateGenesisBlock(uint32_t, uint32_t, uint32_t, int32_t, const CAmount&)’ at /ci_container_base/src/kernel/chainparams.cpp:76:54: /usr/share/mingw-w64/include/string.h:214:33: warning: ‘void* __builtin_memmove(void*, const void*, long long unsigned int)’ offset [65, 35] is out of the bounds [0, 32] of object ‘<anonymous>’ with type ‘CScript’ [-Warray-bounds] 214 | return __builtin___memmove_chk(__dst, __src, __n, __mingw_bos(__dst, 0)); | ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /ci_container_base/src/kernel/chainparams.cpp: In function ‘CBlock CreateGenesisBlock(uint32_t, uint32_t, uint32_t, int32_t, const CAmount&)’: /ci_container_base/src/kernel/chainparams.cpp:76:49: note: ‘<anonymous>’ declared here 76 | const CScript genesisOutputScript = CScript() << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"_hex << OP_CHECKSIG; | ^ ``` Co-authored-by: Hodlinator <172445034+hodlinator@users.noreply.github.com> Co-authored-by: Ryan Ofsky <ryan@ofsky.org>
1 parent a7a4e11 commit c78d8ff

File tree

1 file changed

+6
-3
lines changed

1 file changed

+6
-3
lines changed

src/prevector.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,8 @@ class prevector {
363363
change_capacity(new_size + (new_size >> 1));
364364
}
365365
T* ptr = item_ptr(p);
366-
memmove(ptr + 1, ptr, (size() - p) * sizeof(T));
366+
T* dst = ptr + 1;
367+
memmove(dst, ptr, (size() - p) * sizeof(T));
367368
_size++;
368369
new(static_cast<void*>(ptr)) T(value);
369370
return iterator(ptr);
@@ -376,7 +377,8 @@ class prevector {
376377
change_capacity(new_size + (new_size >> 1));
377378
}
378379
T* ptr = item_ptr(p);
379-
memmove(ptr + count, ptr, (size() - p) * sizeof(T));
380+
T* dst = ptr + count;
381+
memmove(dst, ptr, (size() - p) * sizeof(T));
380382
_size += count;
381383
fill(item_ptr(p), count, value);
382384
}
@@ -390,7 +392,8 @@ class prevector {
390392
change_capacity(new_size + (new_size >> 1));
391393
}
392394
T* ptr = item_ptr(p);
393-
memmove(ptr + count, ptr, (size() - p) * sizeof(T));
395+
T* dst = ptr + count;
396+
memmove(dst, ptr, (size() - p) * sizeof(T));
394397
_size += count;
395398
fill(ptr, first, last);
396399
}

0 commit comments

Comments
 (0)