Skip to content

Commit 574891b

Browse files
[NFCI][SYCL] Eliminate UB in ANSI alias violation accessing ByteArray's (#7023)
As part of it provide a nicer (IMO) interface to it. Also, asserts are now moved into the underlying utility functions making it easier to read the core logic up the call stack.
1 parent 54777c0 commit 574891b

File tree

4 files changed

+58
-41
lines changed

4 files changed

+58
-41
lines changed

sycl/source/detail/device_binary_image.hpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <sycl/detail/os_util.hpp>
1111
#include <sycl/detail/pi.hpp>
1212

13+
#include <cstring>
1314
#include <memory>
1415

1516
namespace sycl {
@@ -27,9 +28,34 @@ class ByteArray {
2728
ConstIterator begin() const { return Ptr; }
2829
ConstIterator end() const { return Ptr + Size; }
2930

31+
template <typename... Ts> auto consume() {
32+
if constexpr (sizeof...(Ts) == 1)
33+
return consumeOneElem<Ts...>();
34+
else
35+
return std::tuple{consumeOneElem<Ts>()...};
36+
}
37+
38+
void dropBytes(std::size_t Bytes) {
39+
assert(Bytes <= Size && "Not enough bytes left!");
40+
Ptr += Bytes;
41+
Size -= Bytes;
42+
}
43+
44+
template <typename T> void drop() { return dropBytes(sizeof(T)); }
45+
46+
bool empty() const { return Size == 0; }
47+
3048
private:
49+
template <typename T> T consumeOneElem() {
50+
assert(sizeof(T) <= Size && "Out of bounds!");
51+
T Val;
52+
std::memcpy(&Val, Ptr, sizeof(T));
53+
drop<T>();
54+
return Val;
55+
}
56+
3157
const std::uint8_t *Ptr;
32-
const std::size_t Size;
58+
std::size_t Size;
3359
};
3460

3561
// C++ wrapper over the _pi_device_binary_property_struct structure.

sycl/source/detail/device_image_impl.hpp

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -260,39 +260,33 @@ class device_image_impl {
260260
const char *SCName = (*SCIt)->Name;
261261

262262
ByteArray Descriptors = DeviceBinaryProperty(*SCIt).asByteArray();
263-
assert(Descriptors.size() > 8 && "Unexpected property size");
263+
// First 8 bytes are consumed by the size of the property.
264+
Descriptors.dropBytes(8);
264265

265266
// Expected layout is vector of 3-component tuples (flattened into a
266267
// vector of scalars), where each tuple consists of: ID of a scalar spec
267268
// constant, (which might be a member of the composite); offset, which
268269
// is used to calculate location of scalar member within the composite
269-
// or zero for scalar spec constants; size of a spec constant
270-
constexpr size_t NumElements = 3;
271-
assert(((Descriptors.size() - 8) / sizeof(std::uint32_t)) %
272-
NumElements ==
273-
0 &&
274-
"unexpected layout of composite spec const descriptors");
275-
auto *It = reinterpret_cast<const std::uint32_t *>(&Descriptors[8]);
276-
auto *End = reinterpret_cast<const std::uint32_t *>(&Descriptors[0] +
277-
Descriptors.size());
270+
// or zero for scalar spec constants; size of a spec constant.
278271
unsigned LocalOffset = 0;
279-
while (It != End) {
280-
// Make sure that alignment is correct in blob.
281-
const unsigned OffsetFromLast = /*Offset*/ It[1] - LocalOffset;
272+
while (!Descriptors.empty()) {
273+
auto [Id, CompositeOffset, Size] =
274+
Descriptors.consume<uint32_t, uint32_t, uint32_t>();
275+
276+
// Make sure that alignment is correct in the blob.
277+
const unsigned OffsetFromLast = CompositeOffset - LocalOffset;
282278
BlobOffset += OffsetFromLast;
283279
// Composites may have a special padding element at the end which
284280
// should not have a descriptor. These padding elements all have max
285281
// ID value.
286-
if (It[0] != std::numeric_limits<std::uint32_t>::max()) {
282+
if (Id != std::numeric_limits<std::uint32_t>::max()) {
287283
// The map is not locked here because updateSpecConstSymMap() is
288284
// only supposed to be called from c'tor.
289285
MSpecConstSymMap[std::string{SCName}].push_back(
290-
SpecConstDescT{/*ID*/ It[0], /*CompositeOffset*/ It[1],
291-
/*Size*/ It[2], BlobOffset});
286+
SpecConstDescT{Id, CompositeOffset, Size, BlobOffset});
292287
}
293-
LocalOffset += OffsetFromLast + /*Size*/ It[2];
294-
BlobOffset += /*Size*/ It[2];
295-
It += NumElements;
288+
LocalOffset += OffsetFromLast + Size;
289+
BlobOffset += Size;
296290
}
297291
}
298292
MSpecConstsBlob.resize(BlobOffset);

sycl/source/detail/program_impl.cpp

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -541,23 +541,21 @@ void program_impl::flush_spec_constants(const RTDeviceBinaryImage &Img,
541541
const spec_constant_impl &SC = SCEntry->second;
542542
assert(SC.isSet() && "uninitialized spec constant");
543543
ByteArray Descriptors = DeviceBinaryProperty(*SCIt).asByteArray();
544-
// First 8 bytes are consumed by size of the property
545-
assert(Descriptors.size() > 8 && "Unexpected property size");
546-
// Expected layout is vector of 3-component tuples (flattened into a vector
547-
// of scalars), where each tuple consists of: ID of a scalar spec constant,
548-
// (which might be a member of the composite); offset, which is used to
549-
// calculate location of scalar member within the composite or zero for
550-
// scalar spec constants; size of a spec constant
551-
assert(((Descriptors.size() - 8) / sizeof(std::uint32_t)) % 3 == 0 &&
552-
"unexpected layout of composite spec const descriptors");
553-
auto *It = reinterpret_cast<const std::uint32_t *>(&Descriptors[8]);
554-
auto *End = reinterpret_cast<const std::uint32_t *>(&Descriptors[0] +
555-
Descriptors.size());
556-
while (It != End) {
544+
545+
// First 8 bytes are consumed by the size of the property.
546+
Descriptors.dropBytes(8);
547+
548+
// Expected layout is vector of 3-component tuples (flattened into a
549+
// vector of scalars), where each tuple consists of: ID of a scalar spec
550+
// constant, (which might be a member of the composite); offset, which
551+
// is used to calculate location of scalar member within the composite
552+
// or zero for scalar spec constants; size of a spec constant.
553+
while (!Descriptors.empty()) {
554+
auto [Id, Offset, Size] =
555+
Descriptors.consume<uint32_t, uint32_t, uint32_t>();
556+
557557
Ctx->getPlugin().call<PiApiKind::piextProgramSetSpecializationConstant>(
558-
NativePrg, /* ID */ It[0], /* Size */ It[2],
559-
SC.getValuePtr() + /* Offset */ It[1]);
560-
It += 3;
558+
NativePrg, Id, Size, SC.getValuePtr() + Offset);
561559
}
562560
}
563561
}

sycl/source/detail/program_manager/program_manager.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,11 +1277,10 @@ void ProgramManager::addImages(pi_device_binaries DeviceBinary) {
12771277
// * 4 bytes - Size of the underlying type in the device_global.
12781278
// * 4 bytes - 0 if device_global has device_image_scope and any value
12791279
// otherwise.
1280-
assert(DeviceGlobalInfo.size() == 16 && "Unexpected property size");
1281-
const std::uint32_t TypeSize =
1282-
*reinterpret_cast<const std::uint32_t *>(&DeviceGlobalInfo[8]);
1283-
const std::uint32_t DeviceImageScopeDecorated =
1284-
*reinterpret_cast<const std::uint32_t *>(&DeviceGlobalInfo[12]);
1280+
DeviceGlobalInfo.dropBytes(8);
1281+
auto [TypeSize, DeviceImageScopeDecorated] =
1282+
DeviceGlobalInfo.consume<std::uint32_t, std::uint32_t>();
1283+
assert(DeviceGlobalInfo.empty() && "Extra data left!");
12851284

12861285
auto ExistingDeviceGlobal = m_DeviceGlobals.find(DeviceGlobal->Name);
12871286
if (ExistingDeviceGlobal != m_DeviceGlobals.end()) {

0 commit comments

Comments
 (0)