mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user