Skip to content

Commit 2c295ab

Browse files
authored
[IRGen] Properly handle empty payloads in getEnumTagMultipayload (#60590)
* [IRGen] Properly handle empty payloads in getEnumTagMultipayload rdar://97914498 The generated code assumed that payloads would always be at least 1 byte long, ignoring the possibility of empty payloads, causing runtime crashes when using empty payloads in multi payload enums. * Fix test * Remove unnecessary basic block
1 parent 29caf1d commit 2c295ab

File tree

2 files changed

+40
-1
lines changed

2 files changed

+40
-1
lines changed

lib/IRGen/TypeLayout.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2321,7 +2321,7 @@ EnumTypeLayoutEntry::getEnumTagMultipayload(IRGenFunction &IGF,
23212321
auto usePayloadBB = IGF.createBasicBlock("use-payload-for-tag");
23222322
auto numPayloads = IGM.getInt32(cases.size());
23232323
auto usePayloadValue = Builder.CreateICmpUGE(loadedTag, numPayloads);
2324-
auto tagValue = llvm::PHINode::Create(IGM.Int32Ty, 3);
2324+
auto tagValue = llvm::PHINode::Create(IGM.Int32Ty, 4);
23252325
tagValue->addIncoming(loadedTag, Builder.GetInsertBlock());
23262326
Builder.CreateCondBr(usePayloadValue, usePayloadBB, resultBB);
23272327

@@ -2330,6 +2330,13 @@ EnumTypeLayoutEntry::getEnumTagMultipayload(IRGenFunction &IGF,
23302330
auto truncSize = Builder.CreateZExtOrTrunc(maxPayloadSize(IGF), IGM.Int32Ty);
23312331
auto sizeGTE4 = Builder.CreateICmpUGE(truncSize, four);
23322332
auto sizeClampedTo4 = Builder.CreateSelect(sizeGTE4, four, truncSize);
2333+
auto sizeGreaterZeroBB = IGF.createBasicBlock("");
2334+
auto zero = IGM.getInt32(0);
2335+
auto sizeGreaterZero = Builder.CreateICmpUGT(sizeClampedTo4, zero);
2336+
tagValue->addIncoming(loadedTag, Builder.GetInsertBlock());
2337+
Builder.CreateCondBr(sizeGreaterZero, sizeGreaterZeroBB, resultBB);
2338+
2339+
Builder.emitBlock(sizeGreaterZeroBB);
23332340
auto payloadValue = emitLoad1to4Bytes(IGF, enumAddr, sizeClampedTo4);
23342341
auto payloadGTE4BB = IGF.createBasicBlock("");
23352342
auto payloadLT4BB = IGF.createBasicBlock("");

test/Interpreter/rdar97914498.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swiftc_driver -Xfrontend -disable-availability-checking -O -Xllvm -sil-opt-pass-count=0 -Xfrontend -disable-llvm-optzns %s -o %t/out
3+
// RUN: %target-codesign %t/out
4+
// RUN: %target-run %t/out
5+
6+
// REQUIRES: executable_test
7+
// REQUIRES: foundation
8+
9+
// This is a regression test that ensures that empty payloads in multi
10+
// payload enums are properly handled.
11+
12+
import Foundation
13+
14+
@inline(never)
15+
func crash() {
16+
let testURL = URL(string: "https://www.google.com")!
17+
let r = Resource<()>(url: testURL, method: .get)
18+
print(r.url)
19+
}
20+
21+
enum HTTPMethod<Payload> {
22+
case get
23+
case post(Payload)
24+
case patch(Payload)
25+
}
26+
27+
struct Resource<Payload> {
28+
let url: URL
29+
let method: HTTPMethod<Payload>
30+
}
31+
32+
crash()

0 commit comments

Comments
 (0)