Skip to content

Commit ff66b79

Browse files
authored
Merge pull request #17564 from jrose-apple/recovery-is-a-SILly-idea (#17591)
Start recovering from missing types in SIL deserialization rdar://problem/40899824 (cherry picked from commit 747e318)
1 parent 9f8f2a1 commit ff66b79

File tree

12 files changed

+245
-58
lines changed

12 files changed

+245
-58
lines changed

lib/Serialization/Deserialization.cpp

Lines changed: 40 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -129,17 +129,6 @@ void TypeError::anchor() {}
129129
const char ExtensionError::ID = '\0';
130130
void ExtensionError::anchor() {}
131131

132-
LLVM_NODISCARD
133-
static std::unique_ptr<llvm::ErrorInfoBase> takeErrorInfo(llvm::Error error) {
134-
std::unique_ptr<llvm::ErrorInfoBase> result;
135-
llvm::handleAllErrors(std::move(error),
136-
[&](std::unique_ptr<llvm::ErrorInfoBase> info) {
137-
result = std::move(info);
138-
});
139-
return result;
140-
}
141-
142-
143132
/// Skips a single record in the bitstream.
144133
///
145134
/// Returns true if the next entry is a record of type \p recordKind.
@@ -4816,27 +4805,42 @@ Expected<Type> ModuleFile::getTypeChecked(TypeID TID) {
48164805
}
48174806

48184807
auto processParameter = [&](TypeID typeID, uint64_t rawConvention)
4819-
-> Optional<SILParameterInfo> {
4808+
-> llvm::Expected<SILParameterInfo> {
48204809
auto convention = getActualParameterConvention(rawConvention);
4821-
auto type = getType(typeID);
4822-
if (!convention || !type) return None;
4823-
return SILParameterInfo(type->getCanonicalType(), *convention);
4810+
if (!convention) {
4811+
error();
4812+
llvm_unreachable("an error is a fatal exit at this point");
4813+
}
4814+
auto type = getTypeChecked(typeID);
4815+
if (!type)
4816+
return type.takeError();
4817+
return SILParameterInfo(type.get()->getCanonicalType(), *convention);
48244818
};
48254819

48264820
auto processYield = [&](TypeID typeID, uint64_t rawConvention)
4827-
-> Optional<SILYieldInfo> {
4821+
-> llvm::Expected<SILYieldInfo> {
48284822
auto convention = getActualParameterConvention(rawConvention);
4829-
auto type = getType(typeID);
4830-
if (!convention || !type) return None;
4831-
return SILYieldInfo(type->getCanonicalType(), *convention);
4823+
if (!convention) {
4824+
error();
4825+
llvm_unreachable("an error is a fatal exit at this point");
4826+
}
4827+
auto type = getTypeChecked(typeID);
4828+
if (!type)
4829+
return type.takeError();
4830+
return SILYieldInfo(type.get()->getCanonicalType(), *convention);
48324831
};
48334832

48344833
auto processResult = [&](TypeID typeID, uint64_t rawConvention)
4835-
-> Optional<SILResultInfo> {
4834+
-> llvm::Expected<SILResultInfo> {
48364835
auto convention = getActualResultConvention(rawConvention);
4837-
auto type = getType(typeID);
4838-
if (!convention || !type) return None;
4839-
return SILResultInfo(type->getCanonicalType(), *convention);
4836+
if (!convention) {
4837+
error();
4838+
llvm_unreachable("an error is a fatal exit at this point");
4839+
}
4840+
auto type = getTypeChecked(typeID);
4841+
if (!type)
4842+
return type.takeError();
4843+
return SILResultInfo(type.get()->getCanonicalType(), *convention);
48404844
};
48414845

48424846
// Bounds check. FIXME: overflow
@@ -4855,11 +4859,9 @@ Expected<Type> ModuleFile::getTypeChecked(TypeID TID) {
48554859
auto typeID = variableData[nextVariableDataIndex++];
48564860
auto rawConvention = variableData[nextVariableDataIndex++];
48574861
auto param = processParameter(typeID, rawConvention);
4858-
if (!param) {
4859-
error();
4860-
return nullptr;
4861-
}
4862-
allParams.push_back(*param);
4862+
if (!param)
4863+
return param.takeError();
4864+
allParams.push_back(param.get());
48634865
}
48644866

48654867
// Process the yields.
@@ -4869,11 +4871,9 @@ Expected<Type> ModuleFile::getTypeChecked(TypeID TID) {
48694871
auto typeID = variableData[nextVariableDataIndex++];
48704872
auto rawConvention = variableData[nextVariableDataIndex++];
48714873
auto yield = processYield(typeID, rawConvention);
4872-
if (!yield) {
4873-
error();
4874-
return nullptr;
4875-
}
4876-
allYields.push_back(*yield);
4874+
if (!yield)
4875+
return yield.takeError();
4876+
allYields.push_back(yield.get());
48774877
}
48784878

48794879
// Process the results.
@@ -4883,23 +4883,20 @@ Expected<Type> ModuleFile::getTypeChecked(TypeID TID) {
48834883
auto typeID = variableData[nextVariableDataIndex++];
48844884
auto rawConvention = variableData[nextVariableDataIndex++];
48854885
auto result = processResult(typeID, rawConvention);
4886-
if (!result) {
4887-
error();
4888-
return nullptr;
4889-
}
4890-
allResults.push_back(*result);
4886+
if (!result)
4887+
return result.takeError();
4888+
allResults.push_back(result.get());
48914889
}
48924890

48934891
// Process the error result.
48944892
Optional<SILResultInfo> errorResult;
48954893
if (hasErrorResult) {
48964894
auto typeID = variableData[nextVariableDataIndex++];
48974895
auto rawConvention = variableData[nextVariableDataIndex++];
4898-
errorResult = processResult(typeID, rawConvention);
4899-
if (!errorResult) {
4900-
error();
4901-
return nullptr;
4902-
}
4896+
auto maybeErrorResult = processResult(typeID, rawConvention);
4897+
if (!maybeErrorResult)
4898+
return maybeErrorResult.takeError();
4899+
errorResult = maybeErrorResult.get();
49034900
}
49044901

49054902
Optional<ProtocolConformanceRef> witnessMethodConformance;

lib/Serialization/DeserializationErrors.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,41 @@ class ExtensionError : public llvm::ErrorInfo<ExtensionError> {
355355
}
356356
};
357357

358+
class SILEntityError : public llvm::ErrorInfo<SILEntityError> {
359+
friend ErrorInfo;
360+
static const char ID;
361+
void anchor() override;
362+
363+
std::unique_ptr<ErrorInfoBase> underlyingReason;
364+
StringRef name;
365+
public:
366+
SILEntityError(StringRef name, std::unique_ptr<ErrorInfoBase> reason)
367+
: underlyingReason(std::move(reason)), name(name) {}
368+
369+
void log(raw_ostream &OS) const override {
370+
OS << "could not deserialize SIL entity '" << name << "'";
371+
if (underlyingReason) {
372+
OS << ": ";
373+
underlyingReason->log(OS);
374+
}
375+
}
376+
377+
std::error_code convertToErrorCode() const override {
378+
return llvm::inconvertibleErrorCode();
379+
}
380+
};
381+
382+
LLVM_NODISCARD
383+
static inline std::unique_ptr<llvm::ErrorInfoBase>
384+
takeErrorInfo(llvm::Error error) {
385+
std::unique_ptr<llvm::ErrorInfoBase> result;
386+
llvm::handleAllErrors(std::move(error),
387+
[&](std::unique_ptr<llvm::ErrorInfoBase> info) {
388+
result = std::move(info);
389+
});
390+
return result;
391+
}
392+
358393
class PrettyStackTraceModuleFile : public llvm::PrettyStackTraceEntry {
359394
const char *Action;
360395
const ModuleFile &MF;

lib/Serialization/DeserializeSIL.cpp

Lines changed: 78 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,16 @@
1212

1313
#define DEBUG_TYPE "deserialize"
1414
#include "DeserializeSIL.h"
15+
16+
#include "DeserializationErrors.h"
17+
#include "SILFormat.h"
18+
1519
#include "swift/Basic/Defer.h"
1620
#include "swift/Basic/PrettyStackTrace.h"
1721
#include "swift/AST/GenericSignature.h"
1822
#include "swift/AST/ProtocolConformance.h"
1923
#include "swift/AST/PrettyStackTrace.h"
2024
#include "swift/Serialization/ModuleFile.h"
21-
#include "SILFormat.h"
2225
#include "swift/SIL/SILArgument.h"
2326
#include "swift/SIL/SILBuilder.h"
2427
#include "swift/SIL/SILDebugScope.h"
@@ -38,6 +41,9 @@ using namespace swift::serialization;
3841
using namespace swift::serialization::sil_block;
3942
using namespace llvm::support;
4043

44+
const char SILEntityError::ID = '\0';
45+
void SILEntityError::anchor() {}
46+
4147
STATISTIC(NumDeserializedFunc, "Number of deserialized SIL functions");
4248

4349
static Optional<StringLiteralInst::Encoding>
@@ -340,7 +346,14 @@ SILFunction *SILDeserializer::getFuncForReference(StringRef name,
340346
// Otherwise, look for a function with this name in the module.
341347
auto iter = FuncTable->find(name);
342348
if (iter != FuncTable->end()) {
343-
fn = readSILFunction(*iter, nullptr, name, /*declarationOnly*/ true);
349+
auto maybeFn = readSILFunctionChecked(*iter, nullptr, name,
350+
/*declarationOnly*/ true);
351+
if (maybeFn) {
352+
fn = maybeFn.get();
353+
} else {
354+
// Ignore the failure; we'll synthesize a bogus function instead.
355+
llvm::consumeError(maybeFn.takeError());
356+
}
344357
}
345358
}
346359

@@ -363,7 +376,15 @@ SILFunction *SILDeserializer::getFuncForReference(StringRef name) {
363376
if (iter == FuncTable->end())
364377
return nullptr;
365378

366-
return readSILFunction(*iter, nullptr, name, /*declarationOnly*/ true);
379+
auto maybeFn = readSILFunctionChecked(*iter, nullptr, name,
380+
/*declarationOnly*/ true);
381+
if (!maybeFn) {
382+
// Ignore the failure and just pretend the function doesn't exist
383+
llvm::consumeError(maybeFn.takeError());
384+
return nullptr;
385+
}
386+
387+
return maybeFn.get();
367388
}
368389

369390
/// Helper function to find a SILGlobalVariable given its name. It first checks
@@ -387,6 +408,19 @@ SILFunction *SILDeserializer::readSILFunction(DeclID FID,
387408
StringRef name,
388409
bool declarationOnly,
389410
bool errorIfEmptyBody) {
411+
llvm::Expected<SILFunction *> deserialized =
412+
readSILFunctionChecked(FID, existingFn, name, declarationOnly,
413+
errorIfEmptyBody);
414+
if (!deserialized) {
415+
MF->fatal(deserialized.takeError());
416+
}
417+
return deserialized.get();
418+
}
419+
420+
llvm::Expected<SILFunction *>
421+
SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn,
422+
StringRef name, bool declarationOnly,
423+
bool errorIfEmptyBody) {
390424
// We can't deserialize function bodies after IRGen lowering passes have
391425
// happened since other definitions in the module will no longer be in
392426
// canonical SIL form.
@@ -445,7 +479,16 @@ SILFunction *SILDeserializer::readSILFunction(DeclID FID,
445479
MF->error();
446480
return nullptr;
447481
}
448-
auto ty = getSILType(MF->getType(funcTyID), SILValueCategory::Object);
482+
auto astType = MF->getTypeChecked(funcTyID);
483+
if (!astType) {
484+
if (!existingFn || errorIfEmptyBody) {
485+
return llvm::make_error<SILEntityError>(
486+
name, takeErrorInfo(astType.takeError()));
487+
}
488+
llvm::consumeError(astType.takeError());
489+
return existingFn;
490+
}
491+
auto ty = getSILType(astType.get(), SILValueCategory::Object);
449492
if (!ty.is<SILFunctionType>()) {
450493
DEBUG(llvm::dbgs() << "not a function type for SILFunction\n");
451494
MF->error();
@@ -2433,14 +2476,21 @@ SILFunction *SILDeserializer::lookupSILFunction(SILFunction *InFunc) {
24332476
if (iter == FuncTable->end())
24342477
return nullptr;
24352478

2436-
auto Func = readSILFunction(*iter, InFunc, name, /*declarationOnly*/ false);
2437-
if (Func) {
2479+
auto maybeFunc = readSILFunctionChecked(*iter, InFunc, name,
2480+
/*declarationOnly*/ false);
2481+
if (!maybeFunc) {
2482+
// Ignore the error; treat it as if we didn't have a definition.
2483+
llvm::consumeError(maybeFunc.takeError());
2484+
return nullptr;
2485+
}
2486+
2487+
if (maybeFunc.get()) {
24382488
DEBUG(llvm::dbgs() << "Deserialize SIL:\n";
2439-
Func->dump());
2440-
assert(InFunc->getName() == Func->getName());
2489+
maybeFunc.get()->dump());
2490+
assert(InFunc->getName() == maybeFunc.get()->getName());
24412491
}
24422492

2443-
return Func;
2493+
return maybeFunc.get();
24442494
}
24452495

24462496
/// Check for existence of a function with a given name and required linkage.
@@ -2517,11 +2567,20 @@ SILFunction *SILDeserializer::lookupSILFunction(StringRef name,
25172567
if (iter == FuncTable->end())
25182568
return nullptr;
25192569

2520-
auto Func = readSILFunction(*iter, nullptr, name, declarationOnly);
2521-
if (Func)
2570+
auto maybeFunc = readSILFunctionChecked(*iter, nullptr, name,
2571+
declarationOnly);
2572+
2573+
if (!maybeFunc) {
2574+
// Ignore the error; treat it as if we didn't have a definition.
2575+
llvm::consumeError(maybeFunc.takeError());
2576+
return nullptr;
2577+
}
2578+
2579+
if (maybeFunc.get()) {
25222580
DEBUG(llvm::dbgs() << "Deserialize SIL:\n";
2523-
Func->dump());
2524-
return Func;
2581+
maybeFunc.get()->dump());
2582+
}
2583+
return maybeFunc.get();
25252584
}
25262585

25272586
SILGlobalVariable *SILDeserializer::readGlobalVar(StringRef Name) {
@@ -2617,8 +2676,12 @@ void SILDeserializer::getAllSILFunctions() {
26172676
auto DI = FuncTable->find(*KI);
26182677
assert(DI != FuncTable->end() && "There should never be a key without data.");
26192678

2620-
readSILFunction(*DI, nullptr, *KI, false,
2621-
false/*errorIfEmptyBody*/);
2679+
auto maybeFunc = readSILFunctionChecked(*DI, nullptr, *KI, false,
2680+
false/*errorIfEmptyBody*/);
2681+
if (!maybeFunc) {
2682+
// Ignore the error; treat it as if we didn't have a definition.
2683+
llvm::consumeError(maybeFunc.takeError());
2684+
}
26222685
}
26232686
}
26242687

lib/Serialization/DeserializeSIL.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ namespace swift {
7979
SILFunction *readSILFunction(serialization::DeclID, SILFunction *InFunc,
8080
StringRef Name, bool declarationOnly,
8181
bool errorIfEmptyBody = true);
82+
/// Read a SIL function.
83+
llvm::Expected<SILFunction *>
84+
readSILFunctionChecked(serialization::DeclID, SILFunction *InFunc,
85+
StringRef Name, bool declarationOnly,
86+
bool errorIfEmptyBody = true);
87+
8288
/// Read a SIL basic block within a given SIL function.
8389
SILBasicBlock *readSILBasicBlock(SILFunction *Fn,
8490
SILBasicBlock *Prev,
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// struct SoonToBeMissing {
2+
// int value;
3+
// };
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module Types { header "Types.h" }
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
struct SoonToBeMissing {
2+
int value;
3+
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module Types { header "Types.h" }
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -parse-sil %s -emit-sib -o %t/Library.sib -module-name Library -I %S/Inputs/good-modules -parse-stdlib
3+
// RUN: %target-sil-opt %t/Library.sib -I %S/Inputs/good-modules | %FileCheck %s
4+
// RUN: %target-sil-opt %t/Library.sib -I %S/Inputs/bad-modules | %FileCheck -check-prefix=CHECK-RECOVERY %s
5+
// RUN: %target-sil-opt %t/Library.sib -I %S/Inputs/bad-modules | %FileCheck -check-prefix=CHECK-RECOVERY-NEGATIVE %s
6+
7+
// CHECK-LABEL: sil_stage raw
8+
// CHECK-RECOVERY-LABEL: sil_stage raw
9+
10+
sil_stage raw
11+
import Types
12+
13+
// CHECK-LABEL: sil @missingParam : $@convention(thin) (SoonToBeMissing) -> () {
14+
// CHECK-RECOVERY-NEGATIVE-NOT: sil @missingParam
15+
sil @missingParam : $@convention(thin) (SoonToBeMissing) -> () {
16+
entry(%arg: $SoonToBeMissing):
17+
%9999 = tuple()
18+
return %9999 : $()
19+
}
20+
21+
// CHECK-LABEL: sil @missingResult : $@convention(thin) () -> SoonToBeMissing {
22+
// CHECK-RECOVERY-NEGATIVE-NOT: sil @missingResult
23+
sil @missingResult : $@convention(thin) () -> (SoonToBeMissing) {
24+
entry:
25+
unreachable
26+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module rdar40899824Helper { header "rdar40899824Helper.h" }

0 commit comments

Comments
 (0)