Use natural alignment for prevector#17530
Conversation
`#pragma pack(1)` prevents aligning the struct and its members to their required alignment. This can result in code that performs non-aligned reads and writes to integers and pointers, which is problematic on some architectures. It also triggers UBsan — see bitcoin#17156 (comment) and bitcoin#17510.
This can be done now that prevector is properly aligned.
63c4d98 to
5432306
Compare
|
@jamesob Would be nice to see IBD performance on this? |
|
Concept ACK: thanks for tackling this! Would be nice to see IBD performance numbers. Very glad to see that We can get rid of the |
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
On it! |
|
@jamesob Any news on the IBD performance? It would be really nice to see if you have the time :) |
|
I think this is the correct thing to do no matter the performance result, but still it'd be nice to see. |
|
@laanwj Agree totally. I really look forward to seeing this merged: this alignment issue creates a lot of sanitiser noise (or signal depending how you see it...) for me when doing my continuous fuzzing of Bitcoin Core :) |
|
ACK 5432306 -- diff looks correct |
|
People interested in getting rid of the two UBSan suppressions needed after the merge of this PR might want to review PR #17208 ("Make all tests pass UBSan without using any UBSan suppressions") too :) |
|
TBH it seems that there's completely no interest in this. |
|
What is the |
|
before: 32 |
|
Couldn't fix that by reshuffling fields either, e.g. the usual suggestion of putting big fields first union direct_or_indirect {
char direct[sizeof(T) * N];
struct {
char* indirect;
size_type capacity;
};
} _union = {};
size_type _size = 0;… a |
|
See also #17060, which makes a bigger prevector layout change (avoiding the memory increase without pragma pack). |
|
That PR changes the layout, but it looks like it relies just as much on sizeof(Coin) before: 48 |
|
This seems like it does the right thing to me fwiw: --- a/src/prevector.h
+++ b/src/prevector.h
@@ -15,7 +15,6 @@
#include <type_traits>
#include <utility>
-#pragma pack(push, 1)
/** Implements a drop-in replacement for std::vector<T> which stores up to N
* elements directly (without heap allocation). The types Size and Diff are
* used to store element counts, and can be any unsigned + signed type.
@@ -45,6 +44,9 @@ public:
typedef value_type* pointer;
typedef const value_type* const_pointer;
+ static_assert(N % alignof(Size) == 0, "Must have preallocation as a multiple of size");
+ static_assert(alignof(char*) % alignof(Size) == 0, "Must have Size be aligned whenever char* would be aligned");
+
class iterator {
T* ptr;
public:
@@ -147,14 +149,23 @@ public:
};
private:
- size_type _size = 0;
+
+#pragma pack(push,1)
+ // we don't want padding added here, we will ensure indirect is
+ // correctly aligned manually, which will in turn ensure capacity
+ // is aligned.
union direct_or_indirect {
char direct[sizeof(T) * N];
struct {
- size_type capacity;
char* indirect;
+ size_type capacity;
};
- } _union = {};
+ };
+#pragma pack(pop)
+
+ alignas(alignof(char*)) direct_or_indirect _union = {};
+ size_type _size = 0;
+private:
T* direct_ptr(difference_type pos) { return reinterpret_cast<T*>(_union.direct) + pos; }
const T* direct_ptr(difference_type pos) const { return reinterpret_cast<const T*>(_union.direct) + pos; }
@@ -523,6 +534,5 @@ public:
return item_ptr(0);
}
};
-#pragma pack(pop) |
|
Will leave this to you @ajtowns |
|
@ajtowns Would you mind opening a PR with that suggested change? It would be nice to get this fixed :) |
|
The saga continues in #17708 |
5f26855 test: Remove ubsan alignment suppressions (Wladimir J. van der Laan) 9d933ef prevector: avoid misaligned member accesses (Anthony Towns) Pull request description: Ensure prevector data is appropriately aligned. Earlier discussion in #17530. **Edit laanwj**: In contrast to #17530, it does this without increase in size of any of the coin cache data structures (x86_64, clang) | Struct | (size,align) before | (size,align) after | | ------------- | ------------- | ------- | | Coin | 48, 8 | 48, 8 | | CCoinsCacheEntry | 56, 8 | 56, 8 | | CScript | 32, 1 | 32, 8 | ACKs for top commit: laanwj: ACK 5f26855 practicalswift: ACK 5f26855 jonatack: ACK 5f26855 Tree-SHA512: 98d112d6856f683d5b212410b73f3071d2994f1efb046a2418a35890aa1cf1aa7c96a960fc2e963fa15241e861093c1ea41951cf5b4b5431f88345eb1dd0a98a
5f26855 test: Remove ubsan alignment suppressions (Wladimir J. van der Laan) 9d933ef prevector: avoid misaligned member accesses (Anthony Towns) Pull request description: Ensure prevector data is appropriately aligned. Earlier discussion in bitcoin#17530. **Edit laanwj**: In contrast to bitcoin#17530, it does this without increase in size of any of the coin cache data structures (x86_64, clang) | Struct | (size,align) before | (size,align) after | | ------------- | ------------- | ------- | | Coin | 48, 8 | 48, 8 | | CCoinsCacheEntry | 56, 8 | 56, 8 | | CScript | 32, 1 | 32, 8 | ACKs for top commit: laanwj: ACK 5f26855 practicalswift: ACK 5f26855 jonatack: ACK 5f26855 Tree-SHA512: 98d112d6856f683d5b212410b73f3071d2994f1efb046a2418a35890aa1cf1aa7c96a960fc2e963fa15241e861093c1ea41951cf5b4b5431f88345eb1dd0a98a
5f26855 test: Remove ubsan alignment suppressions (Wladimir J. van der Laan) 9d933ef prevector: avoid misaligned member accesses (Anthony Towns) Pull request description: Ensure prevector data is appropriately aligned. Earlier discussion in bitcoin#17530. **Edit laanwj**: In contrast to bitcoin#17530, it does this without increase in size of any of the coin cache data structures (x86_64, clang) | Struct | (size,align) before | (size,align) after | | ------------- | ------------- | ------- | | Coin | 48, 8 | 48, 8 | | CCoinsCacheEntry | 56, 8 | 56, 8 | | CScript | 32, 1 | 32, 8 | ACKs for top commit: laanwj: ACK 5f26855 practicalswift: ACK 5f26855 jonatack: ACK 5f26855 Tree-SHA512: 98d112d6856f683d5b212410b73f3071d2994f1efb046a2418a35890aa1cf1aa7c96a960fc2e963fa15241e861093c1ea41951cf5b4b5431f88345eb1dd0a98a
5f26855 test: Remove ubsan alignment suppressions (Wladimir J. van der Laan) 9d933ef prevector: avoid misaligned member accesses (Anthony Towns) Pull request description: Ensure prevector data is appropriately aligned. Earlier discussion in bitcoin#17530. **Edit laanwj**: In contrast to bitcoin#17530, it does this without increase in size of any of the coin cache data structures (x86_64, clang) | Struct | (size,align) before | (size,align) after | | ------------- | ------------- | ------- | | Coin | 48, 8 | 48, 8 | | CCoinsCacheEntry | 56, 8 | 56, 8 | | CScript | 32, 1 | 32, 8 | ACKs for top commit: laanwj: ACK 5f26855 practicalswift: ACK 5f26855 jonatack: ACK 5f26855 Tree-SHA512: 98d112d6856f683d5b212410b73f3071d2994f1efb046a2418a35890aa1cf1aa7c96a960fc2e963fa15241e861093c1ea41951cf5b4b5431f88345eb1dd0a98a
5f26855 test: Remove ubsan alignment suppressions (Wladimir J. van der Laan) 9d933ef prevector: avoid misaligned member accesses (Anthony Towns) Pull request description: Ensure prevector data is appropriately aligned. Earlier discussion in bitcoin#17530. **Edit laanwj**: In contrast to bitcoin#17530, it does this without increase in size of any of the coin cache data structures (x86_64, clang) | Struct | (size,align) before | (size,align) after | | ------------- | ------------- | ------- | | Coin | 48, 8 | 48, 8 | | CCoinsCacheEntry | 56, 8 | 56, 8 | | CScript | 32, 1 | 32, 8 | ACKs for top commit: laanwj: ACK 5f26855 practicalswift: ACK 5f26855 jonatack: ACK 5f26855 Tree-SHA512: 98d112d6856f683d5b212410b73f3071d2994f1efb046a2418a35890aa1cf1aa7c96a960fc2e963fa15241e861093c1ea41951cf5b4b5431f88345eb1dd0a98a
#pragma pack(1)prevents aligning the struct and its members to their required alignment. This can result in code that performs non-aligned reads and writes to integers and pointers, which is problematic on some architectures.It also triggers UBsan — see #17156 (comment) and #17510.
So remove the pragmas.