Skip to content

Commit

Permalink
prevector: avoid misaligned member accesses
Browse files Browse the repository at this point in the history
`#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.
  • Loading branch information
ajtowns committed Dec 10, 2019
1 parent 1189b6a commit 9d933ef
Showing 1 changed file with 9 additions and 5 deletions.
14 changes: 9 additions & 5 deletions src/prevector.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -147,14 +146,20 @@ class prevector {
};

private:
size_type _size = 0;
#pragma pack(push, 1)
union direct_or_indirect {
char direct[sizeof(T) * N];
struct {
size_type capacity;
char* indirect;
size_type capacity;
};
} _union = {};
};
#pragma pack(pop)
alignas(char*) direct_or_indirect _union = {};
size_type _size = 0;

static_assert(alignof(char*) % alignof(size_type) == 0 && sizeof(char*) % alignof(size_type) == 0, "size_type cannot have more restrictive alignment requirement than pointer");
static_assert(alignof(char*) % alignof(T) == 0, "value_type T cannot have more restrictive alignment requirement than pointer");

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; }
Expand Down Expand Up @@ -523,6 +528,5 @@ class prevector {
return item_ptr(0);
}
};
#pragma pack(pop)

#endif // BITCOIN_PREVECTOR_H

0 comments on commit 9d933ef

Please sign in to comment.