Skip to content

Commit fe4d1f5

Browse files
committed
fix: Improve detection of static frameworks
* Modules with .tbd files which weren't detected as system were wrongly being flagged as static, because `isStaticFramework` returned a `no_such_file_or_directory` error. (e.g. `Accelerate`) * Single architecture dynamic libraries were wrongly being flagged as static, because `isStaticFramework` returned an `invalid_argument` error (e.g. `MetalPerformanceShaders`) * Single architecture static libraries were accidentally being flagged as static, because `isStaticFramework` returned an `invalid_argument` error * Remove TODO comment as irrelevant (no crashes in debug mode)
1 parent b0244ee commit fe4d1f5

File tree

1 file changed

+28
-8
lines changed

1 file changed

+28
-8
lines changed

src/Binary/binarySerializer.cpp

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -216,27 +216,44 @@ static llvm::ErrorOr<bool> isStaticFramework(clang::Module* framework)
216216
path::append(path, library);
217217

218218
if (!fs::exists(path)) {
219+
path.append(".tbd");
220+
if (fs::exists(path)) {
221+
// A TBD file is a text-based file used by Apple. It contains information about a .DYLIB library.
222+
// TBD files were introduced in Xcode 7 in September 2015 in order to reduce the size of SDKs
223+
// that come with Xcode by linking to DYLIB libraries instead of storing the actual, larger DYLIB libraries.
224+
return false;
225+
}
226+
219227
return errc::no_such_file_or_directory;
220228
}
221229

230+
auto isDylib = [](MachOObjectFile* machObjectFile) -> bool {
231+
uint32_t filetype = (machObjectFile->is64Bit() ? machObjectFile->getHeader64().filetype : machObjectFile->getHeader().filetype);
232+
return (filetype == MachO::MH_DYLIB || filetype == MachO::MH_DYLIB_STUB || filetype == MachO::MH_DYLINKER);
233+
};
234+
222235
if (Expected<OwningBinary<Binary> > binaryOrErr = createBinary(path)) {
223236
Binary& binary = *binaryOrErr.get().getBinary();
224237

225238
if (MachOUniversalBinary* machoBinary = dyn_cast<MachOUniversalBinary>(&binary)) {
226239
for (const MachOUniversalBinary::ObjectForArch& object : machoBinary->objects()) {
227-
// TODO: If built in debug this will crash because the errors are not handled/checked
228240
if (Expected<std::unique_ptr<MachOObjectFile> > objectFile = object.getAsObjectFile()) {
229241
if (MachOObjectFile* machObjectFile = dyn_cast<MachOObjectFile>(objectFile.get().get())) {
230-
uint32_t filetype = (machObjectFile->is64Bit() ? machObjectFile->getHeader64().filetype : machObjectFile->getHeader().filetype);
231-
if (filetype == MachO::MH_DYLIB || filetype == MachO::MH_DYLIB_STUB) {
242+
if (isDylib(machObjectFile)) {
232243
return false;
233244
}
234245
}
235-
}
236-
else if (Expected<std::unique_ptr<Archive> > archive = object.getAsArchive()) {
246+
} else if (Expected<std::unique_ptr<Archive> > archive = object.getAsArchive()) {
237247
return true;
238248
}
239249
}
250+
// fallthrough and return error (no static, or dynamic library is detected inside the universal binary)
251+
} else if (MachOObjectFile* machObjectFile = dyn_cast<MachOObjectFile>(&binary)) {
252+
if (isDylib(machObjectFile)) {
253+
return false;
254+
}
255+
} else if (Archive* archive = dyn_cast<Archive>(&binary)) {
256+
return true;
240257
}
241258
}
242259

@@ -251,9 +268,12 @@ void binary::BinarySerializer::serializeModule(clang::Module* module, binary::Mo
251268
// System frameworks are always shared, so there's no need to check them anyways.
252269
if (module->IsSystem) {
253270
flags |= 1;
254-
}
255-
else if (llvm::ErrorOr<bool> isStatic = isStaticFramework(module)) {
256-
if (!isStatic.get()) {
271+
} else {
272+
llvm::ErrorOr<bool> isStatic = isStaticFramework(module);
273+
assert(isStatic.getError().value() == 0);
274+
275+
bool isDynamic = isStatic.getError().value() == 0 && !isStatic.get()
276+
if (isDynamic) {
257277
flags |= 1;
258278
}
259279
}

0 commit comments

Comments
 (0)