SIL: fix a memory leak, related to zombie functions

The leak happened in this scenario:
1. A function becomes dead and gets deleted (which means: it gets added to the zombie-list)
2. A function with the same name is created again. This can happen with specializations.

In such a case we just removed the zombie function from the zombie-list without deleting it.
But we cannot delete zombie functions, because they might still be referenced by metadata, like debug-info.

Therefore the right fix is to resurrect the zombie function if a new function is created with the same name.

rdar://problem/66931238
This commit is contained in:
Erik Eckstein
2020-09-10 14:51:40 +02:00
parent e9650cf4cb
commit 1d62d3481c
4 changed files with 92 additions and 38 deletions

View File

@@ -72,13 +72,29 @@ SILFunction::create(SILModule &M, SILLinkage linkage, StringRef name,
name = entry->getKey();
}
auto fn = new (M) SILFunction(M, linkage, name, loweredType, genericEnv, loc,
SILFunction *fn = M.removeFromZombieList(name);
if (fn) {
// Resurrect a zombie function.
// This happens for example if a specialized function gets dead and gets
// deleted. And afterwards the same specialization is created again.
fn->init(linkage, name, loweredType, genericEnv, loc, isBareSILFunction,
isTrans, isSerialized, entryCount, isThunk, classSubclassScope,
inlineStrategy, E, debugScope, isDynamic, isExactSelfClass);
assert(fn->empty());
} else {
fn = new (M) SILFunction(M, linkage, name, loweredType, genericEnv, loc,
isBareSILFunction, isTrans, isSerialized,
entryCount, isThunk, classSubclassScope,
inlineStrategy, E, insertBefore, debugScope,
inlineStrategy, E, debugScope,
isDynamic, isExactSelfClass);
}
if (entry) entry->setValue(fn);
if (insertBefore)
M.functions.insert(SILModule::iterator(insertBefore), fn);
else
M.functions.push_back(fn);
return fn;
}
@@ -90,41 +106,60 @@ SILFunction::SILFunction(SILModule &Module, SILLinkage Linkage, StringRef Name,
ProfileCounter entryCount, IsThunk_t isThunk,
SubclassScope classSubclassScope,
Inline_t inlineStrategy, EffectsKind E,
SILFunction *InsertBefore,
const SILDebugScope *DebugScope,
IsDynamicallyReplaceable_t isDynamic,
IsExactSelfClass_t isExactSelfClass)
: Module(Module), Name(Name), LoweredType(LoweredType),
GenericEnv(genericEnv), SpecializationInfo(nullptr),
EntryCount(entryCount),
Availability(AvailabilityContext::alwaysAvailable()),
Bare(isBareSILFunction), Transparent(isTrans),
Serialized(isSerialized), Thunk(isThunk),
ClassSubclassScope(unsigned(classSubclassScope)), GlobalInitFlag(false),
InlineStrategy(inlineStrategy), Linkage(unsigned(Linkage)),
HasCReferences(false), IsWeakImported(false),
IsDynamicReplaceable(isDynamic),
ExactSelfClass(isExactSelfClass),
Inlined(false), Zombie(false), HasOwnership(true),
WasDeserializedCanonical(false), IsWithoutActuallyEscapingThunk(false),
OptMode(unsigned(OptimizationMode::NotSet)),
EffectsKindAttr(unsigned(E)) {
assert(!Transparent || !IsDynamicReplaceable);
validateSubclassScope(classSubclassScope, isThunk, nullptr);
setDebugScope(DebugScope);
if (InsertBefore)
Module.functions.insert(SILModule::iterator(InsertBefore), this);
else
Module.functions.push_back(this);
Module.removeFromZombieList(Name);
: Module(Module), Availability(AvailabilityContext::alwaysAvailable()) {
init(Linkage, Name, LoweredType, genericEnv, Loc, isBareSILFunction, isTrans,
isSerialized, entryCount, isThunk, classSubclassScope, inlineStrategy,
E, DebugScope, isDynamic, isExactSelfClass);
// Set our BB list to have this function as its parent. This enables us to
// splice efficiently basic blocks in between functions.
BlockList.Parent = this;
}
void SILFunction::init(SILLinkage Linkage, StringRef Name,
CanSILFunctionType LoweredType,
GenericEnvironment *genericEnv,
Optional<SILLocation> Loc, IsBare_t isBareSILFunction,
IsTransparent_t isTrans, IsSerialized_t isSerialized,
ProfileCounter entryCount, IsThunk_t isThunk,
SubclassScope classSubclassScope,
Inline_t inlineStrategy, EffectsKind E,
const SILDebugScope *DebugScope,
IsDynamicallyReplaceable_t isDynamic,
IsExactSelfClass_t isExactSelfClass) {
this->Name = Name;
this->LoweredType = LoweredType;
this->GenericEnv = genericEnv;
this->SpecializationInfo = nullptr;
this->EntryCount = entryCount;
this->Availability = AvailabilityContext::alwaysAvailable();
this->Bare = isBareSILFunction;
this->Transparent = isTrans;
this->Serialized = isSerialized;
this->Thunk = isThunk;
this->ClassSubclassScope = unsigned(classSubclassScope);
this->GlobalInitFlag = false;
this->InlineStrategy = inlineStrategy;
this->Linkage = unsigned(Linkage);
this->HasCReferences = false;
this->IsWeakImported = false;
this->IsDynamicReplaceable = isDynamic;
this->ExactSelfClass = isExactSelfClass;
this->Inlined = false;
this->Zombie = false;
this->HasOwnership = true,
this->WasDeserializedCanonical = false;
this->IsWithoutActuallyEscapingThunk = false;
this->OptMode = unsigned(OptimizationMode::NotSet);
this->EffectsKindAttr = unsigned(E);
assert(!Transparent || !IsDynamicReplaceable);
validateSubclassScope(classSubclassScope, isThunk, nullptr);
setDebugScope(DebugScope);
}
SILFunction::~SILFunction() {
// If the function is recursive, a function_ref inst inside of the function
// will give the function a non-zero ref count triggering the assertion. Thus