Skip to content

Commit c638789

Browse files
committed
Swift: open(2) interception
1 parent 7267722 commit c638789

12 files changed

+151
-13
lines changed

misc/bazel/workspace.bzl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
22
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
3+
load("@bazel_tools//tools/build_defs/repo:git.bzl", "new_git_repository")
34

45
_swift_prebuilt_version = "swift-5.6-RELEASE.42271.54"
56
_swift_sha_map = {
@@ -55,3 +56,11 @@ def codeql_workspace(repository_name = "codeql"):
5556
"https://github.com/bazelbuild/rules_python/archive/refs/tags/0.8.1.tar.gz",
5657
],
5758
)
59+
60+
new_git_repository(
61+
name = "fishhook",
62+
commit = "aadc161ac3b80db07a9908851839a17ba63a9eb1",
63+
shallow_since = "1634071885 -0400",
64+
build_file = "//swift/tools/fishhook:BUILD.fishhook.bazel",
65+
remote = "https://github.com/facebook/fishhook",
66+
)

swift/extractor/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ swift_cc_binary(
1010
deps = [
1111
"//swift/extractor/infra",
1212
"//swift/extractor/visitors",
13+
"//swift/extractor/remapping",
1314
"//swift/tools/prebuilt:swift-llvm-support",
1415
],
1516
)

swift/extractor/SwiftExtractor.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,6 @@ void codeql::extractSwiftFiles(const SwiftExtractorConfiguration& config,
184184
while (!todo.empty()) {
185185
auto module = todo.back();
186186
todo.pop_back();
187-
llvm::errs() << "processing module " << module->getName() << '\n';
188187
bool isFromSourceFile = false;
189188
std::unordered_set<swift::ModuleDecl*> encounteredModules;
190189
for (auto file : module->getFiles()) {

swift/extractor/SwiftOutputRewrite.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#include "SwiftOutputRewrite.h"
1+
#include "swift/extractor/SwiftOutputRewrite.h"
22
#include "swift/extractor/SwiftExtractorConfiguration.h"
33
#include "swift/extractor/TargetTrapFile.h"
44

swift/extractor/SwiftOutputRewrite.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,5 @@ std::vector<std::string> collectVFSFiles(const SwiftExtractorConfiguration& conf
3232
// Creates empty trap files for output swiftmodule files
3333
void lockOutputSwiftModuleTraps(const SwiftExtractorConfiguration& config,
3434
const std::unordered_map<std::string, std::string>& remapping);
35+
3536
} // namespace codeql

swift/extractor/main.cpp

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
#include <swift/Basic/LLVMInitialize.h>
1010
#include <swift/FrontendTool/FrontendTool.h>
1111

12-
#include "SwiftExtractor.h"
13-
#include "SwiftOutputRewrite.h"
12+
#include "swift/extractor/SwiftExtractor.h"
13+
#include "swift/extractor/SwiftOutputRewrite.h"
14+
#include "swift/extractor/remapping/SwiftOpenInterception.h"
1415

1516
using namespace std::string_literals;
1617

@@ -21,14 +22,6 @@ class Observer : public swift::FrontendObserver {
2122
public:
2223
explicit Observer(const codeql::SwiftExtractorConfiguration& config) : config{config} {}
2324

24-
void parsedArgs(swift::CompilerInvocation& invocation) override {
25-
auto& overlays = invocation.getSearchPathOptions().VFSOverlayFiles;
26-
auto vfsFiles = codeql::collectVFSFiles(config);
27-
for (auto& vfsFile : vfsFiles) {
28-
overlays.push_back(vfsFile);
29-
}
30-
}
31-
3225
void performedSemanticAnalysis(swift::CompilerInstance& compiler) override {
3326
codeql::extractSwiftFiles(config, compiler);
3427
}
@@ -49,6 +42,7 @@ int main(int argc, char** argv) {
4942
// TODO: print usage
5043
return 1;
5144
}
45+
5246
// Required by Swift/LLVM
5347
PROGRAM_START(argc, argv);
5448
INITIALIZE_LLVM();
@@ -58,6 +52,8 @@ int main(int argc, char** argv) {
5852
configuration.sourceArchiveDir = getenv_or("CODEQL_EXTRACTOR_SWIFT_SOURCE_ARCHIVE_DIR", ".");
5953
configuration.scratchDir = getenv_or("CODEQL_EXTRACTOR_SWIFT_SCRATCH_DIR", ".");
6054

55+
codeql::initInterception(configuration.getTempArtifactDir());
56+
6157
configuration.frontendOptions.reserve(argc - 1);
6258
for (int i = 1; i < argc; i++) {
6359
configuration.frontendOptions.push_back(argv[i]);
@@ -67,7 +63,6 @@ int main(int argc, char** argv) {
6763
auto remapping =
6864
codeql::rewriteOutputsInPlace(configuration, configuration.patchedFrontendOptions);
6965
codeql::ensureDirectoriesForNewPathsExist(remapping);
70-
codeql::storeRemappingForVFS(configuration, remapping);
7166
codeql::lockOutputSwiftModuleTraps(configuration, remapping);
7267

7368
std::vector<const char*> args;
@@ -77,5 +72,8 @@ int main(int argc, char** argv) {
7772

7873
Observer observer(configuration);
7974
int frontend_rc = swift::performFrontend(args, "swift-extractor", (void*)main, &observer);
75+
76+
codeql::remapArtifacts(remapping);
77+
8078
return frontend_rc;
8179
}

swift/extractor/remapping/BUILD.bazel

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
load("//swift:rules.bzl", "swift_cc_library")
2+
3+
swift_cc_library(
4+
name = "remapping",
5+
srcs = select({
6+
"@platforms//os:linux": [
7+
"SwiftOpenInterception.Linux.cpp",
8+
],
9+
"@platforms//os:macos": [
10+
"SwiftOpenInterception.macOS.cpp",
11+
],
12+
}),
13+
hdrs = glob(["*.h"]),
14+
visibility = ["//swift:__subpackages__"],
15+
deps = [
16+
"//swift/tools/prebuilt:swift-llvm-support",
17+
] + select({
18+
"@platforms//os:linux": [],
19+
"@platforms//os:macos": [
20+
"@fishhook//:fishhook",
21+
],
22+
}),
23+
)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#include "swift/extractor/remapping/SwiftOpenInterception.h"
2+
3+
namespace codeql {
4+
// TBD
5+
void remapArtifacts(const std::unordered_map<std::string, std::string>& mapping) {}
6+
void initInterception(const std::string& dir) {}
7+
8+
} // namespace codeql
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#pragma once
2+
3+
#include <string>
4+
#include <unordered_map>
5+
6+
namespace codeql {
7+
8+
void initInterception(const std::string& dir);
9+
void remapArtifacts(const std::unordered_map<std::string, std::string>& mapping);
10+
11+
} // namespace codeql
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#include "swift/extractor/remapping/SwiftOpenInterception.h"
2+
#include <fishhook.h>
3+
#include <llvm/Support/raw_ostream.h>
4+
#include <llvm/Support/FileSystem.h>
5+
#include <llvm/Support/Path.h>
6+
#include <fcntl.h>
7+
#include <unistd.h>
8+
9+
namespace codeql {
10+
11+
static std::string scratchDir;
12+
13+
static int (*original_open)(const char*, int, ...) = nullptr;
14+
15+
static std::string fileHash(const std::string& filename) {
16+
int fd = original_open(filename.c_str(), O_RDONLY);
17+
if (fd == -1) {
18+
return {};
19+
}
20+
auto maybeMD5 = llvm::sys::fs::md5_contents(fd);
21+
close(fd);
22+
if (!maybeMD5) {
23+
return {};
24+
}
25+
return maybeMD5->digest().str().str();
26+
}
27+
28+
static int codeql_open(const char* path, int oflag, ...) {
29+
va_list ap = {0};
30+
mode_t mode = 0;
31+
if ((oflag & O_CREAT) != 0) {
32+
// mode only applies to O_CREAT
33+
va_start(ap, oflag);
34+
mode = va_arg(ap, int);
35+
va_end(ap);
36+
}
37+
38+
std::string newPath(path);
39+
40+
if (llvm::sys::fs::exists(newPath)) {
41+
// TODO: check file magic instead
42+
if (llvm::StringRef(newPath).endswith(".swiftmodule")) {
43+
auto hash = fileHash(newPath);
44+
auto hashed = scratchDir + "/" + hash;
45+
if (!hash.empty() && llvm::sys::fs::exists(hashed)) {
46+
newPath = hashed;
47+
}
48+
}
49+
}
50+
51+
return original_open(newPath.c_str(), oflag, mode);
52+
}
53+
54+
void remapArtifacts(const std::unordered_map<std::string, std::string>& mapping) {
55+
for (auto& [original, patched] : mapping) {
56+
// TODO: Check file magic instead
57+
if (!llvm::StringRef(original).endswith(".swiftmodule")) {
58+
continue;
59+
}
60+
auto hash = fileHash(original);
61+
auto hashed = scratchDir + "/" + hash;
62+
if (!hash.empty() && llvm::sys::fs::exists(patched)) {
63+
if (std::error_code ec = llvm::sys::fs::create_link(/* from */ patched, /* to */ hashed)) {
64+
llvm::errs() << "Cannot remap file '" << patched << "' -> '" << hashed
65+
<< "': " << ec.message() << "\n";
66+
}
67+
}
68+
}
69+
}
70+
71+
void initInterception(const std::string& dir) {
72+
scratchDir = dir;
73+
74+
struct rebinding binding[] = {
75+
{"open", reinterpret_cast<void*>(codeql_open), reinterpret_cast<void**>(&original_open)}};
76+
rebind_symbols(binding, 1);
77+
}
78+
79+
} // namespace codeql

0 commit comments

Comments
 (0)