Skip to content

Commit 7bb9579

Browse files
committed
[Runtime] Fix copying in extended existential value witnesses.
Instead of copying the data and the type and witnesses separately, use the size in the value witness table and copy everything at once. copyTypeInto assumed the type was an ordinary existential. When it was actually an extended existential, it would do an incorrect cast and read part of a pointer as the number of witness tables to copy. This would typically result in a large buffer overflow and crash. At this point we already know the type's size, so we can use that info directly rather than essentially recomputing it. rdar://163980446
1 parent 6dbe0cb commit 7bb9579

File tree

2 files changed

+133
-54
lines changed

2 files changed

+133
-54
lines changed

stdlib/public/runtime/ExistentialMetadataImpl.h

Lines changed: 45 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,20 @@ namespace swift {
2525
namespace metadataimpl {
2626

2727
/// A common base class for opaque-existential and class-existential boxes.
28-
template <typename Impl> struct SWIFT_LIBRARY_VISIBILITY ExistentialBoxBase {};
28+
template <typename Impl>
29+
struct SWIFT_LIBRARY_VISIBILITY ExistentialBoxBase {
30+
template <class Container, class... A>
31+
static void copyBytes(Container *dest, Container *src, A... args) {
32+
memcpy(dest, src, src->getContainerStride(args...));
33+
}
34+
35+
template <class Container, class... A>
36+
static void copyTypeBytes(Container *dest, Container *src, A...args) {
37+
auto valueBytes = src->getValueSize();
38+
auto toCopy = src->getContainerStride(args...) - valueBytes;
39+
memcpy((char *)dest + valueBytes, (char *)src + valueBytes, toCopy);
40+
}
41+
};
2942

3043
/// A common base class for fixed and non-fixed opaque-existential box
3144
/// implementations.
@@ -83,7 +96,7 @@ struct SWIFT_LIBRARY_VISIBILITY OpaqueExistentialBoxBase
8396
template <class Container, class... A>
8497
static Container *initializeWithCopy(Container *dest, Container *src,
8598
A... args) {
86-
src->copyTypeInto(dest, args...);
99+
copyTypeBytes(dest, src, args...);
87100
auto *type = src->getType();
88101
auto *vwt = type->getValueWitnesses();
89102

@@ -104,10 +117,7 @@ struct SWIFT_LIBRARY_VISIBILITY OpaqueExistentialBoxBase
104117
template <class Container, class... A>
105118
static Container *initializeWithTake(Container *dest, Container *src,
106119
A... args) {
107-
src->copyTypeInto(dest, args...);
108-
auto from = src->getBuffer(args...);
109-
auto to = dest->getBuffer(args...);
110-
memcpy(to, from, sizeof(ValueBuffer));
120+
copyBytes(dest, src, args...);
111121
return dest;
112122
}
113123

@@ -151,7 +161,7 @@ struct SWIFT_LIBRARY_VISIBILITY OpaqueExistentialBoxBase
151161
// Move dest value aside so we can destroy it later.
152162
destType->vw_initializeWithTake(opaqueTmpBuffer, destValue);
153163

154-
src->copyTypeInto(dest, args...);
164+
copyTypeBytes(dest, src, args...);
155165
if (srcVwt->isValueInline()) {
156166
// Inline src value.
157167

@@ -172,7 +182,7 @@ struct SWIFT_LIBRARY_VISIBILITY OpaqueExistentialBoxBase
172182
auto *destRef =
173183
*reinterpret_cast<HeapObject **>(dest->getBuffer(args...));
174184

175-
src->copyTypeInto(dest, args...);
185+
copyTypeBytes(dest, src, args...);
176186
if (srcVwt->isValueInline()) {
177187

178188
// initWithCopy.
@@ -239,7 +249,7 @@ struct SWIFT_LIBRARY_VISIBILITY OpaqueExistentialBoxBase
239249
// Move dest value aside.
240250
destType->vw_initializeWithTake(opaqueTmpBuffer, destValue);
241251

242-
src->copyTypeInto(dest, args...);
252+
copyTypeBytes(dest, src, args...);
243253
if (srcVwt->isValueInline()) {
244254
// Inline src value.
245255

@@ -260,7 +270,7 @@ struct SWIFT_LIBRARY_VISIBILITY OpaqueExistentialBoxBase
260270
auto *destRef =
261271
*reinterpret_cast<HeapObject **>(dest->getBuffer(args...));
262272

263-
src->copyTypeInto(dest, args...);
273+
copyTypeBytes(dest, src, args...);
264274
if (srcVwt->isValueInline()) {
265275
// initWithCopy.
266276

@@ -291,12 +301,20 @@ template <unsigned NumWitnessTables>
291301
struct SWIFT_LIBRARY_VISIBILITY FixedOpaqueExistentialContainer {
292302
OpaqueExistentialContainer Header;
293303
const void *WitnessTables[NumWitnessTables];
304+
305+
static size_t getValueSize() {
306+
return sizeof(Header.Buffer);
307+
}
294308
};
295309
// We need to be able to instantiate for NumWitnessTables==0, which
296310
// requires an explicit specialization.
297311
template <>
298312
struct FixedOpaqueExistentialContainer<0> {
299313
OpaqueExistentialContainer Header;
314+
315+
static size_t getValueSize() {
316+
return sizeof(Header.Buffer);
317+
}
300318
};
301319

302320
/// A box implementation class for an opaque existential type with
@@ -311,10 +329,7 @@ struct SWIFT_LIBRARY_VISIBILITY OpaqueExistentialBox
311329
ValueBuffer *getBuffer() {
312330
return &this->Header.Buffer;
313331
}
314-
void copyTypeInto(Container *dest) const {
315-
this->Header.copyTypeInto(&dest->Header, NumWitnessTables);
316-
}
317-
332+
318333
static size_t getContainerStride() {
319334
return sizeof(Container);
320335
}
@@ -355,9 +370,6 @@ struct SWIFT_LIBRARY_VISIBILITY NonFixedOpaqueExistentialBox
355370
ValueBuffer *getBuffer(const Metadata *self) {
356371
return &Header.Buffer;
357372
}
358-
void copyTypeInto(Container *dest, const Metadata *self) {
359-
Header.copyTypeInto(&dest->Header, getNumWitnessTables(self));
360-
}
361373

362374
static unsigned getNumWitnessTables(const Metadata *self) {
363375
auto castSelf = static_cast<const ExistentialTypeMetadata*>(self);
@@ -377,7 +389,11 @@ struct SWIFT_LIBRARY_VISIBILITY NonFixedOpaqueExistentialBox
377389
}
378390

379391
static size_t getContainerStride(const Metadata *self) {
380-
return getStride(getNumWitnessTables(self));
392+
return self->vw_stride();
393+
}
394+
395+
static size_t getValueSize() {
396+
return sizeof(Header.Buffer);
381397
}
382398
};
383399

@@ -411,28 +427,25 @@ struct SWIFT_LIBRARY_VISIBILITY ClassExistentialBoxBase
411427
template <class Container, class... A>
412428
static Container *initializeWithCopy(Container *dest, Container *src,
413429
A... args) {
414-
src->copyTypeInto(dest, args...);
415430
auto newValue = *src->getValueSlot();
416-
*dest->getValueSlot() = newValue;
431+
copyBytes(dest, src, args...);
417432
swift_unknownObjectRetain(newValue);
418433
return dest;
419434
}
420435

421436
template <class Container, class... A>
422437
static Container *initializeWithTake(Container *dest, Container *src,
423438
A... args) {
424-
src->copyTypeInto(dest, args...);
425-
*dest->getValueSlot() = *src->getValueSlot();
439+
copyBytes(dest, src, args...);
426440
return dest;
427441
}
428442

429443
template <class Container, class... A>
430444
static Container *assignWithCopy(Container *dest, Container *src,
431445
A... args) {
432-
src->copyTypeInto(dest, args...);
433446
auto newValue = *src->getValueSlot();
434447
auto oldValue = *dest->getValueSlot();
435-
*dest->getValueSlot() = newValue;
448+
copyBytes(dest, src, args...);
436449
swift_unknownObjectRetain(newValue);
437450
swift_unknownObjectRelease(oldValue);
438451
return dest;
@@ -441,10 +454,8 @@ struct SWIFT_LIBRARY_VISIBILITY ClassExistentialBoxBase
441454
template <class Container, class... A>
442455
static Container *assignWithTake(Container *dest, Container *src,
443456
A... args) {
444-
src->copyTypeInto(dest, args...);
445-
auto newValue = *src->getValueSlot();
446457
auto oldValue = *dest->getValueSlot();
447-
*dest->getValueSlot() = newValue;
458+
copyBytes(dest, src, args...);
448459
swift_unknownObjectRelease(oldValue);
449460
return dest;
450461
}
@@ -470,10 +481,6 @@ struct SWIFT_LIBRARY_VISIBILITY ClassExistentialBox : ClassExistentialBoxBase {
470481
ClassExistentialContainer Header;
471482
const void *TypeInfo[NumWitnessTables];
472483

473-
void copyTypeInto(Container *dest) const {
474-
for (unsigned i = 0; i != NumWitnessTables; ++i)
475-
dest->TypeInfo[i] = TypeInfo[i];
476-
}
477484
void **getValueSlot() { return &Header.Value; }
478485
void * const *getValueSlot() const { return &Header.Value; }
479486

@@ -501,10 +508,6 @@ struct SWIFT_LIBRARY_VISIBILITY NonFixedClassExistentialBox
501508
return castSelf->Flags.getNumWitnessTables();
502509
}
503510

504-
void copyTypeInto(Container *dest, const Metadata *self) {
505-
Header.copyTypeInto(&dest->Header, getNumWitnessTables(self));
506-
}
507-
508511
void **getValueSlot() { return &Header.Value; }
509512
void * const *getValueSlot() const { return &Header.Value; }
510513

@@ -520,7 +523,7 @@ struct SWIFT_LIBRARY_VISIBILITY NonFixedClassExistentialBox
520523
return getSize(numWitnessTables);
521524
}
522525
static size_t getContainerStride(const Metadata *self) {
523-
return getStride(getNumWitnessTables(self));
526+
return self->vw_stride();
524527
}
525528
};
526529
using type = Container;
@@ -540,32 +543,28 @@ struct SWIFT_LIBRARY_VISIBILITY ExistentialMetatypeBoxBase
540543
template <class Container, class... A>
541544
static Container *initializeWithCopy(Container *dest, Container *src,
542545
A... args) {
543-
src->copyTypeInto(dest, args...);
544-
*dest->getValueSlot() = *src->getValueSlot();
545-
return dest;
546+
copyBytes(dest, src, args...);
547+
return dest;
546548
}
547549

548550
template <class Container, class... A>
549551
static Container *initializeWithTake(Container *dest, Container *src,
550552
A... args) {
551-
src->copyTypeInto(dest, args...);
552-
*dest->getValueSlot() = *src->getValueSlot();
553+
copyBytes(dest, src, args...);
553554
return dest;
554555
}
555556

556557
template <class Container, class... A>
557558
static Container *assignWithCopy(Container *dest, Container *src,
558559
A... args) {
559-
src->copyTypeInto(dest, args...);
560-
*dest->getValueSlot() = *src->getValueSlot();
560+
copyBytes(dest, src, args...);
561561
return dest;
562562
}
563563

564564
template <class Container, class... A>
565565
static Container *assignWithTake(Container *dest, Container *src,
566566
A... args) {
567-
src->copyTypeInto(dest, args...);
568-
*dest->getValueSlot() = *src->getValueSlot();
567+
copyBytes(dest, src, args...);
569568
return dest;
570569
}
571570

@@ -593,10 +592,6 @@ struct SWIFT_LIBRARY_VISIBILITY ExistentialMetatypeBox
593592
ExistentialMetatypeContainer Header;
594593
const void *TypeInfo[NumWitnessTables];
595594

596-
void copyTypeInto(Container *dest) const {
597-
for (unsigned i = 0; i != NumWitnessTables; ++i)
598-
dest->TypeInfo[i] = TypeInfo[i];
599-
}
600595
const Metadata **getValueSlot() { return &Header.Value; }
601596
const Metadata * const *getValueSlot() const { return &Header.Value; }
602597

@@ -624,10 +619,6 @@ struct SWIFT_LIBRARY_VISIBILITY NonFixedExistentialMetatypeBox
624619
return castSelf->Flags.getNumWitnessTables();
625620
}
626621

627-
void copyTypeInto(Container *dest, const Metadata *self) {
628-
Header.copyTypeInto(&dest->Header, getNumWitnessTables(self));
629-
}
630-
631622
const Metadata **getValueSlot() { return &Header.Value; }
632623
const Metadata * const *getValueSlot() const { return &Header.Value; }
633624

@@ -643,7 +634,7 @@ struct SWIFT_LIBRARY_VISIBILITY NonFixedExistentialMetatypeBox
643634
return getSize(numWitnessTables);
644635
}
645636
static size_t getContainerStride(const Metadata *self) {
646-
return getStride(getNumWitnessTables(self));
637+
return self->vw_stride();
647638
}
648639
};
649640
using type = Container;
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// RUN: %target-run-simple-swift | %FileCheck %s
2+
3+
// UNSUPPORTED: use_os_stdlib
4+
// UNSUPPORTED: back_deployment_runtime
5+
// REQUIRES: OS=macosx
6+
// REQUIRES: executable_test
7+
8+
protocol P1<P1T> {
9+
associatedtype P1T
10+
11+
func printValue()
12+
}
13+
14+
protocol P2<P2T> {
15+
associatedtype P2T
16+
}
17+
18+
protocol P3<P3T> {
19+
associatedtype P3T
20+
}
21+
22+
struct Small: P1, P2, P3 {
23+
typealias P1T = Int
24+
typealias P2T = Int
25+
typealias P3T = Int
26+
27+
var str = "I am Small"
28+
29+
func printValue() { print(str) }
30+
}
31+
32+
struct Big: P1, P2, P3 {
33+
typealias P1T = Int
34+
typealias P2T = Int
35+
typealias P3T = Int
36+
37+
var str = "I am Big"
38+
var str2 = ""
39+
var str3 = ""
40+
41+
func printValue() { print(str) }
42+
}
43+
44+
class Class: P1, P2, P3 {
45+
typealias P1T = Int
46+
typealias P2T = Int
47+
typealias P3T = Int
48+
49+
var str = "I am Class"
50+
51+
func printValue() { print(str) }
52+
}
53+
54+
func test<T>(_ value: T) {
55+
var array: [T] = []
56+
array.append(value)
57+
for v in array {
58+
(v as? P1)?.printValue()
59+
}
60+
}
61+
62+
// CHECK: I am Small
63+
test(Small() as any P1<Int>)
64+
// CHECK: I am Small
65+
test(Small() as any P1<Int> & P2<Int>)
66+
// CHECK: I am Small
67+
test(Small() as any P1<Int> & P2<Int> & P3<Int>)
68+
69+
// CHECK: I am Big
70+
test(Big() as any P1<Int>)
71+
// CHECK: I am Big
72+
test(Big() as any P1<Int> & P2<Int>)
73+
// CHECK: I am Big
74+
test(Big() as any P1<Int> & P2<Int> & P3<Int>)
75+
76+
// CHECK: I am Class
77+
test(Class() as any P1<Int>)
78+
// CHECK: I am Class
79+
test(Class() as any P1<Int> & P2<Int>)
80+
// CHECK: I am Class
81+
test(Class() as any P1<Int> & P2<Int> & P3<Int>)
82+
83+
// CHECK: I am Class
84+
test(Class() as any AnyObject & P1<Int>)
85+
// CHECK: I am Class
86+
test(Class() as any AnyObject & P1<Int> & P2<Int>)
87+
// CHECK: I am Class
88+
test(Class() as any AnyObject & P1<Int> & P2<Int> & P3<Int>)

0 commit comments

Comments
 (0)