Skip to content

Commit 79bf28a

Browse files
authored
[Runtime] Fix UB in layout string runtime functions (#66112) (#66130)
rdar://109790722 Layout strings are not guaranteed to be properly aligned, so we can't directly read from and write to it, but have to use memcpy instead.
1 parent 74fd8ce commit 79bf28a

File tree

2 files changed

+71
-48
lines changed

2 files changed

+71
-48
lines changed

stdlib/public/runtime/BytecodeLayouts.cpp

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,18 @@ static const size_t layoutStringHeaderSize = sizeof(uint64_t) + sizeof(size_t);
4141
/// offset
4242
template <typename T>
4343
T readBytes(const uint8_t *typeLayout, size_t &i) {
44-
T returnVal = *(const T *)(typeLayout + i);
44+
T returnVal;
45+
memcpy(&returnVal, typeLayout + i, sizeof(T));
4546
i += sizeof(T);
4647
return returnVal;
4748
}
4849

4950
/// Given a pointer, a value, and an offset, write the value at the given
50-
/// offset in big-endian order
51+
/// offset and increment offset by the size of T
5152
template <typename T>
52-
void writeBytes(uint8_t *typeLayout, size_t i, T value) {
53-
*((T*)(typeLayout + i)) = value;
53+
void writeBytes(uint8_t *typeLayout, size_t &i, T value) {
54+
memcpy(typeLayout + i, &value, sizeof(T));
55+
i += sizeof(T);
5456
}
5557

5658
Metadata *getExistentialTypeMetadata(OpaqueValue *object) {
@@ -63,7 +65,8 @@ const Metadata *getResilientTypeMetadata(const Metadata* metadata,
6365
const uint8_t *layoutStr,
6466
size_t &offset) {
6567
auto absolute = layoutStr + offset;
66-
auto relativeOffset = (uintptr_t)(intptr_t)(int32_t)readBytes<intptr_t>(layoutStr, offset);
68+
auto relativeOffset =
69+
(uintptr_t)(intptr_t)(int32_t)readBytes<intptr_t>(layoutStr, offset);
6770
MetadataAccessor fn;
6871

6972
#if SWIFT_PTRAUTH
@@ -330,12 +333,13 @@ void swift::swift_resolve_resilientAccessors(
330333

331334
switch (tag) {
332335
case RefCountingKind::Resilient: {
333-
auto *type = getResilientTypeMetadata(fieldType, fieldLayoutStr,
334-
i);
335-
uint8_t *curPos = (layoutStr + layoutStrOffset + currentOffset - layoutStringHeaderSize);
336-
*((uint64_t*)curPos) =
336+
auto *type = getResilientTypeMetadata(fieldType, fieldLayoutStr, i);
337+
size_t writeOffset = layoutStrOffset + currentOffset -
338+
layoutStringHeaderSize;
339+
uint64_t tagAndOffset =
337340
(((uint64_t)RefCountingKind::Metatype) << 56) | size;
338-
*((Metadata const* *)(curPos + sizeof(uint64_t))) = type;
341+
writeBytes(layoutStr, writeOffset, tagAndOffset);
342+
writeBytes(layoutStr, writeOffset, type);
339343
break;
340344
}
341345
case RefCountingKind::Metatype:

stdlib/public/runtime/Metadata.cpp

Lines changed: 57 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2641,24 +2641,40 @@ void swift::swift_initStructMetadata(StructMetadata *structType,
26412641
vwtable->publishLayout(layout);
26422642
}
26432643

2644-
enum LayoutStringFlags : uint64_t {
2645-
Empty = 0,
2646-
// TODO: Track other useful information tha can be used to optimize layout
2647-
// strings, like different reference kinds contained in the string
2648-
// number of ref counting operations (maybe up to 4), so we can
2649-
// use witness functions optimized for these cases.
2650-
HasRelativePointers = (1ULL << 63),
2651-
};
2644+
namespace {
2645+
enum LayoutStringFlags : uint64_t {
2646+
Empty = 0,
2647+
// TODO: Track other useful information tha can be used to optimize layout
2648+
// strings, like different reference kinds contained in the string
2649+
// number of ref counting operations (maybe up to 4), so we can
2650+
// use witness functions optimized for these cases.
2651+
HasRelativePointers = (1ULL << 63),
2652+
};
26522653

2653-
inline bool operator&(LayoutStringFlags a, LayoutStringFlags b) {
2654-
return (uint64_t(a) & uint64_t(b)) != 0;
2655-
}
2656-
inline LayoutStringFlags operator|(LayoutStringFlags a, LayoutStringFlags b) {
2657-
return LayoutStringFlags(uint64_t(a) | uint64_t(b));
2658-
}
2659-
inline LayoutStringFlags &operator|=(LayoutStringFlags &a, LayoutStringFlags b) {
2660-
return a = (a | b);
2661-
}
2654+
inline bool operator&(LayoutStringFlags a, LayoutStringFlags b) {
2655+
return (uint64_t(a) & uint64_t(b)) != 0;
2656+
}
2657+
inline LayoutStringFlags operator|(LayoutStringFlags a, LayoutStringFlags b) {
2658+
return LayoutStringFlags(uint64_t(a) | uint64_t(b));
2659+
}
2660+
inline LayoutStringFlags &operator|=(LayoutStringFlags &a, LayoutStringFlags b) {
2661+
return a = (a | b);
2662+
}
2663+
2664+
template <typename T>
2665+
inline T readBytes(const uint8_t *layoutStr, size_t &i) {
2666+
T returnVal;
2667+
memcpy(&returnVal, layoutStr + i, sizeof(T));
2668+
i += sizeof(T);
2669+
return returnVal;
2670+
}
2671+
2672+
template <typename T>
2673+
inline void writeBytes(uint8_t *layoutStr, size_t &i, T value) {
2674+
memcpy(layoutStr + i, &value, sizeof(T));
2675+
i += sizeof(T);
2676+
}
2677+
} // end anonymous namespace
26622678

26632679
void swift::swift_initStructMetadataWithLayoutString(
26642680
StructMetadata *structType, StructLayoutFlags layoutFlags, size_t numFields,
@@ -2732,9 +2748,9 @@ void swift::swift_initStructMetadataWithLayoutString(
27322748
uint8_t *layoutStr = (uint8_t *)MetadataAllocator(LayoutStringTag)
27332749
.Allocate(fixedLayoutStringSize + refCountBytes, alignof(uint8_t));
27342750

2735-
*((size_t*)(layoutStr + sizeof(uint64_t))) = refCountBytes;
2751+
size_t layoutStrOffset = sizeof(uint64_t);
27362752

2737-
size_t layoutStrOffset = layoutStringHeaderSize;
2753+
writeBytes(layoutStr, layoutStrOffset, refCountBytes);
27382754
size_t fullOffset = 0;
27392755
size_t previousFieldOffset = 0;
27402756
LayoutStringFlags flags = LayoutStringFlags::Empty;
@@ -2753,9 +2769,8 @@ void swift::swift_initStructMetadataWithLayoutString(
27532769
auto tag = fieldTag <= 0x2 ? RefCountingKind::UnknownUnowned :
27542770
RefCountingKind::UnknownWeak;
27552771

2756-
*(uint64_t *)(layoutStr + layoutStrOffset) =
2757-
((uint64_t)tag << 56) | offset;
2758-
layoutStrOffset += sizeof(uint64_t);
2772+
auto tagAndOffset = ((uint64_t)tag << 56) | offset;
2773+
writeBytes(layoutStr, layoutStrOffset, tagAndOffset);
27592774
}
27602775

27612776
fullOffset += fieldType->size;
@@ -2793,10 +2808,18 @@ void swift::swift_initStructMetadataWithLayoutString(
27932808
}
27942809

27952810
if (offset) {
2796-
*(uint64_t *)(layoutStr + layoutStrOffset) += offset;
2811+
auto layoutStrOffsetCopy = layoutStrOffset;
2812+
auto firstTagAndOffset =
2813+
readBytes<uint64_t>(layoutStr, layoutStrOffsetCopy);
2814+
layoutStrOffsetCopy = layoutStrOffset;
2815+
firstTagAndOffset += offset;
2816+
writeBytes(layoutStr, layoutStrOffsetCopy, firstTagAndOffset);
27972817
}
27982818

2799-
previousFieldOffset = *(const uint64_t*)(fieldLayoutStr + layoutStringHeaderSize + fieldRefCountBytes);
2819+
auto previousFieldOffsetOffset =
2820+
layoutStringHeaderSize + fieldRefCountBytes;
2821+
previousFieldOffset = readBytes<uint64_t>(fieldLayoutStr,
2822+
previousFieldOffsetOffset);
28002823
layoutStrOffset += fieldRefCountBytes;
28012824
} else {
28022825
previousFieldOffset += fieldType->vw_size();
@@ -2827,39 +2850,35 @@ void swift::swift_initStructMetadataWithLayoutString(
28272850
};
28282851
}
28292852

2830-
*(uint64_t*)(layoutStr + layoutStrOffset) =
2831-
((uint64_t)tag << 56) | offset;
2832-
layoutStrOffset += sizeof(uint64_t);
2853+
writeBytes(layoutStr, layoutStrOffset, ((uint64_t)tag << 56) | offset);
28332854
previousFieldOffset = fieldType->vw_size();
28342855
fullOffset += previousFieldOffset;
28352856
} else if (fieldType->isAnyExistentialType()) {
28362857
auto *existential = dyn_cast<ExistentialTypeMetadata>(fieldType);
28372858
assert(existential);
28382859
auto tag = existential->isClassBounded() ? RefCountingKind::Unknown
28392860
: RefCountingKind::Existential;
2840-
*(uint64_t*)(layoutStr + layoutStrOffset) =
2841-
((uint64_t)tag << 56) | offset;
2842-
layoutStrOffset += sizeof(uint64_t);
2861+
writeBytes(layoutStr, layoutStrOffset, ((uint64_t)tag << 56) | offset);
28432862
previousFieldOffset = fieldType->vw_size();
28442863
fullOffset += previousFieldOffset;
28452864
} else {
28462865
metadata:
2847-
*(uint64_t*)(layoutStr + layoutStrOffset) =
2848-
((uint64_t)RefCountingKind::Metatype << 56) | offset;
2849-
*(uintptr_t*)(layoutStr + layoutStrOffset + sizeof(uint64_t)) =
2850-
(uintptr_t)fieldType;
2851-
layoutStrOffset += sizeof(uint64_t) + sizeof(uintptr_t);
2866+
writeBytes(layoutStr, layoutStrOffset,
2867+
((uint64_t)RefCountingKind::Metatype << 56) | offset);
2868+
writeBytes(layoutStr, layoutStrOffset, fieldType);
28522869
previousFieldOffset = fieldType->vw_size();
28532870
fullOffset += previousFieldOffset;
28542871
}
28552872
}
28562873

2857-
*(uint64_t *)(layoutStr + layoutStrOffset) = previousFieldOffset;
2858-
*(uint64_t *)(layoutStr + layoutStrOffset + sizeof(uint64_t)) = 0;
2874+
writeBytes(layoutStr, layoutStrOffset, previousFieldOffset);
2875+
writeBytes(layoutStr, layoutStrOffset, 0);
28592876

28602877
// we mask out HasRelativePointers, because at this point they have all been
28612878
// resolved to metadata pointers
2862-
*(uint64_t *)(layoutStr) = ((uint64_t)flags) & ~((uint64_t)LayoutStringFlags::HasRelativePointers);
2879+
layoutStrOffset = 0;
2880+
writeBytes(layoutStr, layoutStrOffset,
2881+
((uint64_t)flags) & ~((uint64_t)LayoutStringFlags::HasRelativePointers));
28632882

28642883
structType->setLayoutString(layoutStr);
28652884

0 commit comments

Comments
 (0)