[libc] avoid type-punning with inactive union member (#116685)

This commit is contained in:
Schrodinger ZHU Yifan 2024-11-18 16:04:41 -05:00 committed by GitHub
parent 6a863f7e26
commit e59582b6f8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 30 additions and 34 deletions

View file

@ -10,6 +10,7 @@
///
//===----------------------------------------------------------------------===//
#include "include/llvm-libc-types/ENTRY.h"
#include "src/__support/CPP/bit.h"
#include "src/__support/CPP/string_view.h"
#include "src/__support/HashTable/table.h"
#include "src/__support/macros/config.h"
@ -81,15 +82,14 @@ static struct {
template <typename T> T next() {
static_assert(cpp::is_integral<T>::value, "T must be an integral type");
union {
T result;
char data[sizeof(T)];
};
for (size_t i = 0; i < sizeof(result); i++)
char data[sizeof(T)];
for (size_t i = 0; i < sizeof(T); i++)
data[i] = buffer[i];
buffer += sizeof(result);
remaining -= sizeof(result);
return result;
buffer += sizeof(T);
remaining -= sizeof(T);
return cpp::bit_cast<T>(data);
}
cpp::string_view next_string() {

View file

@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//
#include "src/__support/CPP/bit.h"
#include "src/__support/common.h"
#include "src/__support/endian_internal.h"
#include "src/__support/macros/config.h"
@ -44,13 +45,11 @@ struct Group {
// Load a group of control words from an arbitary address.
LIBC_INLINE static Group load(const void *addr) {
union {
bitmask_t value;
char bytes[sizeof(bitmask_t)];
} data;
char bytes[sizeof(bitmask_t)];
for (size_t i = 0; i < sizeof(bitmask_t); ++i)
data.bytes[i] = static_cast<const char *>(addr)[i];
return {data.value};
bytes[i] = static_cast<const char *>(addr)[i];
return Group{cpp::bit_cast<bitmask_t>(bytes)};
}
// Load a group of control words from an aligned address.

View file

@ -13,8 +13,8 @@
#include "src/__support/CPP/limits.h" // numeric_limits
#include "src/__support/macros/attributes.h" // LIBC_INLINE
#include "src/__support/macros/config.h"
#include "src/__support/uint128.h" // UInt128
#include <stdint.h> // For uint64_t
#include "src/__support/uint128.h" // UInt128
#include <stdint.h> // For uint64_t
namespace LIBC_NAMESPACE_DECL {
namespace internal {
@ -34,25 +34,23 @@ LIBC_INLINE uint64_t folded_multiply(uint64_t x, uint64_t y) {
// Therefore, we use a union to read the value.
template <typename T> LIBC_INLINE T read_little_endian(const void *ptr) {
const uint8_t *bytes = static_cast<const uint8_t *>(ptr);
union {
T value;
uint8_t buffer[sizeof(T)];
} data;
uint8_t buffer[sizeof(T)];
#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__
// Compiler should able to optimize this as a load followed by a byte swap.
// On aarch64 (-mbig-endian), this compiles to the following for int:
// Compiler should able to optimize this as a load followed by a byte
// swap. On aarch64 (-mbig-endian), this compiles to the following for
// int:
// ldr w0, [x0]
// rev w0, w0
// ret
for (size_t i = 0; i < sizeof(T); ++i) {
data.buffer[i] = bytes[sizeof(T) - i - 1];
buffer[i] = bytes[sizeof(T) - i - 1];
}
#else
for (size_t i = 0; i < sizeof(T); ++i) {
data.buffer[i] = bytes[i];
buffer[i] = bytes[i];
}
#endif
return data.value;
return cpp::bit_cast<T>(buffer);
}
// Specialized read functions for small values. size must be <= 8.

View file

@ -8,6 +8,7 @@
#include "src/__support/HashTable/bitmask.h"
#include "src/__support/CPP/bit.h"
#include "src/__support/macros/config.h"
#include "src/stdlib/rand.h"
#include "test/UnitTest/Test.h"
@ -28,14 +29,13 @@ TEST(LlvmLibcHashTableBitMaskTest, Match) {
size_t appearance[4][sizeof(Group)];
ByteArray array{};
union {
uintptr_t random;
int data[sizeof(uintptr_t) / sizeof(int)];
};
int data[sizeof(uintptr_t) / sizeof(int)];
for (int &i : data)
i = rand();
uintptr_t random = cpp::bit_cast<uintptr_t>(data);
for (size_t i = 0; i < sizeof(Group); ++i) {
size_t choice = random % 4;
random /= 4;
@ -62,14 +62,13 @@ TEST(LlvmLibcHashTableBitMaskTest, MaskAvailable) {
for (size_t i = 0; i < sizeof(Group); ++i) {
ByteArray array{};
union {
uintptr_t random;
int data[sizeof(uintptr_t) / sizeof(int)];
};
int data[sizeof(uintptr_t) / sizeof(int)];
for (int &j : data)
j = rand();
uintptr_t random = cpp::bit_cast<uintptr_t>(data);
ASSERT_FALSE(Group::load(array.data).mask_available().any_bit_set());
array.data[i] = 0x80;

View file

@ -82,7 +82,7 @@ TEST(LlvmLibcTableTest, GrowthSequence) {
}
TEST(LlvmLibcTableTest, Insertion) {
union key {
struct key {
char bytes[2];
} keys[256];
for (size_t k = 0; k < 256; ++k) {