1 //===-- chunk.h -------------------------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 #define SCUDO_CHUNK_H_
14 #include "atomic_helpers.h"
21 extern Checksum HashAlgorithm
;
23 inline u16
computeChecksum(u32 Seed
, uptr Value
, uptr
*Array
, uptr ArraySize
) {
24 // If the hardware CRC32 feature is defined here, it was enabled everywhere,
25 // as opposed to only for crc32_hw.cpp. This means that other hardware
26 // specific instructions were likely emitted at other places, and as a result
27 // there is no reason to not use it here.
28 #if defined(__CRC32__) || defined(__SSE4_2__) || defined(__ARM_FEATURE_CRC32)
29 u32 Crc
= static_cast<u32
>(CRC32_INTRINSIC(Seed
, Value
));
30 for (uptr I
= 0; I
< ArraySize
; I
++)
31 Crc
= static_cast<u32
>(CRC32_INTRINSIC(Crc
, Array
[I
]));
32 return static_cast<u16
>(Crc
^ (Crc
>> 16));
34 if (HashAlgorithm
== Checksum::HardwareCRC32
) {
35 u32 Crc
= computeHardwareCRC32(Seed
, Value
);
36 for (uptr I
= 0; I
< ArraySize
; I
++)
37 Crc
= computeHardwareCRC32(Crc
, Array
[I
]);
38 return static_cast<u16
>(Crc
^ (Crc
>> 16));
40 u16 Checksum
= computeBSDChecksum(static_cast<u16
>(Seed
), Value
);
41 for (uptr I
= 0; I
< ArraySize
; I
++)
42 Checksum
= computeBSDChecksum(Checksum
, Array
[I
]);
45 #endif // defined(__CRC32__) || defined(__SSE4_2__) ||
46 // defined(__ARM_FEATURE_CRC32)
51 // Note that in an ideal world, `State` and `Origin` should be `enum class`, and
52 // the associated `UnpackedHeader` fields of their respective enum class type
53 // but https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414 prevents it from
54 // happening, as it will error, complaining the number of bits is not enough.
62 enum State
: u8
{ Available
= 0, Allocated
= 1, Quarantined
= 2 };
64 typedef u64 PackedHeader
;
65 // Update the 'Mask' constants to reflect changes in this structure.
66 struct UnpackedHeader
{
69 // Origin if State == Allocated, or WasZeroed otherwise.
70 u8 OriginOrWasZeroed
: 2;
71 uptr SizeOrUnusedBytes
: 20;
75 typedef atomic_u64 AtomicPackedHeader
;
76 static_assert(sizeof(UnpackedHeader
) == sizeof(PackedHeader
), "");
78 // Those constants are required to silence some -Werror=conversion errors when
79 // assigning values to the related bitfield variables.
80 constexpr uptr ClassIdMask
= (1UL << 8) - 1;
81 constexpr u8 StateMask
= (1U << 2) - 1;
82 constexpr u8 OriginMask
= (1U << 2) - 1;
83 constexpr uptr SizeOrUnusedBytesMask
= (1UL << 20) - 1;
84 constexpr uptr OffsetMask
= (1UL << 16) - 1;
85 constexpr uptr ChecksumMask
= (1UL << 16) - 1;
87 constexpr uptr
getHeaderSize() {
88 return roundUp(sizeof(PackedHeader
), 1U << SCUDO_MIN_ALIGNMENT_LOG
);
91 inline AtomicPackedHeader
*getAtomicHeader(void *Ptr
) {
92 return reinterpret_cast<AtomicPackedHeader
*>(reinterpret_cast<uptr
>(Ptr
) -
96 inline const AtomicPackedHeader
*getConstAtomicHeader(const void *Ptr
) {
97 return reinterpret_cast<const AtomicPackedHeader
*>(
98 reinterpret_cast<uptr
>(Ptr
) - getHeaderSize());
101 // We do not need a cryptographically strong hash for the checksum, but a CRC
102 // type function that can alert us in the event a header is invalid or
103 // corrupted. Ideally slightly better than a simple xor of all fields.
104 static inline u16
computeHeaderChecksum(u32 Cookie
, const void *Ptr
,
105 UnpackedHeader
*Header
) {
106 UnpackedHeader ZeroChecksumHeader
= *Header
;
107 ZeroChecksumHeader
.Checksum
= 0;
108 uptr HeaderHolder
[sizeof(UnpackedHeader
) / sizeof(uptr
)];
109 memcpy(&HeaderHolder
, &ZeroChecksumHeader
, sizeof(HeaderHolder
));
110 return computeChecksum(Cookie
, reinterpret_cast<uptr
>(Ptr
), HeaderHolder
,
111 ARRAY_SIZE(HeaderHolder
));
114 inline void storeHeader(u32 Cookie
, void *Ptr
,
115 UnpackedHeader
*NewUnpackedHeader
) {
116 NewUnpackedHeader
->Checksum
=
117 computeHeaderChecksum(Cookie
, Ptr
, NewUnpackedHeader
);
118 PackedHeader NewPackedHeader
= bit_cast
<PackedHeader
>(*NewUnpackedHeader
);
119 atomic_store_relaxed(getAtomicHeader(Ptr
), NewPackedHeader
);
122 inline void loadHeader(u32 Cookie
, const void *Ptr
,
123 UnpackedHeader
*NewUnpackedHeader
) {
124 PackedHeader NewPackedHeader
= atomic_load_relaxed(getConstAtomicHeader(Ptr
));
125 *NewUnpackedHeader
= bit_cast
<UnpackedHeader
>(NewPackedHeader
);
126 if (UNLIKELY(NewUnpackedHeader
->Checksum
!=
127 computeHeaderChecksum(Cookie
, Ptr
, NewUnpackedHeader
)))
128 reportHeaderCorruption(const_cast<void *>(Ptr
));
131 inline bool isValid(u32 Cookie
, const void *Ptr
,
132 UnpackedHeader
*NewUnpackedHeader
) {
133 PackedHeader NewPackedHeader
= atomic_load_relaxed(getConstAtomicHeader(Ptr
));
134 *NewUnpackedHeader
= bit_cast
<UnpackedHeader
>(NewPackedHeader
);
135 return NewUnpackedHeader
->Checksum
==
136 computeHeaderChecksum(Cookie
, Ptr
, NewUnpackedHeader
);
143 #endif // SCUDO_CHUNK_H_