-
Notifications
You must be signed in to change notification settings - Fork 38.7k
Use natural alignment for prevector #17530
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
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.