Skip to content

Commit 23924ea

Browse files
[libc] avoid type-punning with inactive union field
1 parent de5e4eb commit 23924ea

File tree

5 files changed

+30
-34
lines changed

5 files changed

+30
-34
lines changed

libc/fuzzing/__support/hashtable_fuzz.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
///
1111
//===----------------------------------------------------------------------===//
1212
#include "include/llvm-libc-types/ENTRY.h"
13+
#include "src/__support/CPP/bit.h"
1314
#include "src/__support/CPP/string_view.h"
1415
#include "src/__support/HashTable/table.h"
1516
#include "src/__support/macros/config.h"
@@ -81,15 +82,14 @@ static struct {
8182

8283
template <typename T> T next() {
8384
static_assert(cpp::is_integral<T>::value, "T must be an integral type");
84-
union {
85-
T result;
86-
char data[sizeof(T)];
87-
};
88-
for (size_t i = 0; i < sizeof(result); i++)
85+
86+
char data[sizeof(T)];
87+
88+
for (size_t i = 0; i < sizeof(T); i++)
8989
data[i] = buffer[i];
90-
buffer += sizeof(result);
91-
remaining -= sizeof(result);
92-
return result;
90+
buffer += sizeof(T);
91+
remaining -= sizeof(T);
92+
return cpp::bit_cast<T>(data);
9393
}
9494

9595
cpp::string_view next_string() {

libc/src/__support/HashTable/generic/bitmask_impl.inc

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
#include "src/__support/CPP/bit.h"
910
#include "src/__support/common.h"
1011
#include "src/__support/endian_internal.h"
1112
#include "src/__support/macros/config.h"
@@ -44,13 +45,11 @@ struct Group {
4445

4546
// Load a group of control words from an arbitary address.
4647
LIBC_INLINE static Group load(const void *addr) {
47-
union {
48-
bitmask_t value;
49-
char bytes[sizeof(bitmask_t)];
50-
} data;
48+
char bytes[sizeof(bitmask_t)];
49+
5150
for (size_t i = 0; i < sizeof(bitmask_t); ++i)
52-
data.bytes[i] = static_cast<const char *>(addr)[i];
53-
return {data.value};
51+
bytes[i] = static_cast<const char *>(addr)[i];
52+
return Group{cpp::bit_cast<bitmask_t>(bytes)};
5453
}
5554

5655
// Load a group of control words from an aligned address.

libc/src/__support/hash.h

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
#include "src/__support/CPP/limits.h" // numeric_limits
1414
#include "src/__support/macros/attributes.h" // LIBC_INLINE
1515
#include "src/__support/macros/config.h"
16-
#include "src/__support/uint128.h" // UInt128
17-
#include <stdint.h> // For uint64_t
16+
#include "src/__support/uint128.h" // UInt128
17+
#include <stdint.h> // For uint64_t
1818

1919
namespace LIBC_NAMESPACE_DECL {
2020
namespace internal {
@@ -34,25 +34,23 @@ LIBC_INLINE uint64_t folded_multiply(uint64_t x, uint64_t y) {
3434
// Therefore, we use a union to read the value.
3535
template <typename T> LIBC_INLINE T read_little_endian(const void *ptr) {
3636
const uint8_t *bytes = static_cast<const uint8_t *>(ptr);
37-
union {
38-
T value;
39-
uint8_t buffer[sizeof(T)];
40-
} data;
37+
uint8_t buffer[sizeof(T)];
4138
#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
42-
// Compiler should able to optimize this as a load followed by a byte swap.
43-
// On aarch64 (-mbig-endian), this compiles to the following for int:
39+
// Compiler should able to optimize this as a load followed by a byte
40+
// swap. On aarch64 (-mbig-endian), this compiles to the following for
41+
// int:
4442
// ldr w0, [x0]
4543
// rev w0, w0
4644
// ret
4745
for (size_t i = 0; i < sizeof(T); ++i) {
48-
data.buffer[i] = bytes[sizeof(T) - i - 1];
46+
buffer[i] = bytes[sizeof(T) - i - 1];
4947
}
5048
#else
5149
for (size_t i = 0; i < sizeof(T); ++i) {
52-
data.buffer[i] = bytes[i];
50+
buffer[i] = bytes[i];
5351
}
5452
#endif
55-
return data.value;
53+
return cpp::bit_cast<T>(buffer);
5654
}
5755

5856
// Specialized read functions for small values. size must be <= 8.

libc/test/src/__support/HashTable/group_test.cpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "src/__support/HashTable/bitmask.h"
1010

11+
#include "src/__support/CPP/bit.h"
1112
#include "src/__support/macros/config.h"
1213
#include "src/stdlib/rand.h"
1314
#include "test/UnitTest/Test.h"
@@ -28,14 +29,13 @@ TEST(LlvmLibcHashTableBitMaskTest, Match) {
2829
size_t appearance[4][sizeof(Group)];
2930
ByteArray array{};
3031

31-
union {
32-
uintptr_t random;
33-
int data[sizeof(uintptr_t) / sizeof(int)];
34-
};
32+
int data[sizeof(uintptr_t) / sizeof(int)];
3533

3634
for (int &i : data)
3735
i = rand();
3836

37+
uintptr_t random = cpp::bit_cast<uintptr_t>(data);
38+
3939
for (size_t i = 0; i < sizeof(Group); ++i) {
4040
size_t choice = random % 4;
4141
random /= 4;
@@ -62,14 +62,13 @@ TEST(LlvmLibcHashTableBitMaskTest, MaskAvailable) {
6262
for (size_t i = 0; i < sizeof(Group); ++i) {
6363
ByteArray array{};
6464

65-
union {
66-
uintptr_t random;
67-
int data[sizeof(uintptr_t) / sizeof(int)];
68-
};
65+
int data[sizeof(uintptr_t) / sizeof(int)];
6966

7067
for (int &j : data)
7168
j = rand();
7269

70+
uintptr_t random = cpp::bit_cast<uintptr_t>(data);
71+
7372
ASSERT_FALSE(Group::load(array.data).mask_available().any_bit_set());
7473

7574
array.data[i] = 0x80;

libc/test/src/__support/HashTable/table_test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ TEST(LlvmLibcTableTest, GrowthSequence) {
8282
}
8383

8484
TEST(LlvmLibcTableTest, Insertion) {
85-
union key {
85+
struct key {
8686
char bytes[2];
8787
} keys[256];
8888
for (size_t k = 0; k < 256; ++k) {

0 commit comments

Comments
 (0)