Skip to content

Commit addab09

Browse files
authored
Merge pull request #10447 from github/alexdenisov/open-interception
Swift: open(2) interception
2 parents eefe457 + 9401eda commit addab09

12 files changed

+151
-13
lines changed

misc/bazel/workspace.bzl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ def codeql_workspace(repository_name = "codeql"):
2626
sha256 = sha256,
2727
)
2828

29+
http_archive(
30+
name = "fishhook",
31+
url = "https://github.com/facebook/fishhook/archive/aadc161ac3b80db07a9908851839a17ba63a9eb1.zip",
32+
build_file = "@%s//swift/tools/fishhook:BUILD.fishhook.bazel" % repository_name,
33+
strip_prefix = "fishhook-aadc161ac3b80db07a9908851839a17ba63a9eb1",
34+
sha256 = "9f2cdee6dcc2039d4c47d25ab5141fe0678ce6ed27ef482cab17fe9fa38a30ce",
35+
)
36+
2937
maybe(
3038
repo_rule = http_archive,
3139
name = "rules_pkg",

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::initRemapping(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::finalizeRemapping(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 initRemapping(const std::string& dir) {}
6+
void finalizeRemapping(const std::unordered_map<std::string, std::string>& mapping) {}
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 initRemapping(const std::string& dir);
9+
void finalizeRemapping(const std::unordered_map<std::string, std::string>& mapping);
10+
11+
} // namespace codeql
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
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+
static bool interceptionEnabled = false;
13+
14+
static int (*original_open)(const char*, int, ...) = nullptr;
15+
16+
static std::string fileHash(const std::string& filename) {
17+
int fd = original_open(filename.c_str(), O_RDONLY);
18+
if (fd == -1) {
19+
return {};
20+
}
21+
auto maybeMD5 = llvm::sys::fs::md5_contents(fd);
22+
close(fd);
23+
if (!maybeMD5) {
24+
return {};
25+
}
26+
return maybeMD5->digest().str().str();
27+
}
28+
29+
static int codeql_open(const char* path, int oflag, ...) {
30+
va_list ap = {0};
31+
mode_t mode = 0;
32+
if ((oflag & O_CREAT) != 0) {
33+
// mode only applies to O_CREAT
34+
va_start(ap, oflag);
35+
mode = va_arg(ap, int);
36+
va_end(ap);
37+
}
38+
39+
std::string newPath(path);
40+
41+
if (interceptionEnabled && llvm::sys::fs::exists(newPath)) {
42+
// TODO: check file magic instead
43+
if (llvm::StringRef(newPath).endswith(".swiftmodule")) {
44+
auto hash = fileHash(newPath);
45+
auto hashed = scratchDir + "/" + hash;
46+
if (!hash.empty() && llvm::sys::fs::exists(hashed)) {
47+
newPath = hashed;
48+
}
49+
}
50+
}
51+
52+
return original_open(newPath.c_str(), oflag, mode);
53+
}
54+
55+
void finalizeRemapping(const std::unordered_map<std::string, std::string>& mapping) {
56+
for (auto& [original, patched] : mapping) {
57+
// TODO: Check file magic instead
58+
if (!llvm::StringRef(original).endswith(".swiftmodule")) {
59+
continue;
60+
}
61+
auto hash = fileHash(original);
62+
auto hashed = scratchDir + "/" + hash;
63+
if (!hash.empty() && llvm::sys::fs::exists(patched)) {
64+
if (std::error_code ec = llvm::sys::fs::create_link(/* from */ patched, /* to */ hashed)) {
65+
llvm::errs() << "Cannot remap file '" << patched << "' -> '" << hashed
66+
<< "': " << ec.message() << "\n";
67+
}
68+
}
69+
}
70+
interceptionEnabled = false;
71+
}
72+
73+
void initRemapping(const std::string& dir) {
74+
scratchDir = dir;
75+
76+
struct rebinding binding[] = {
77+
{"open", reinterpret_cast<void*>(codeql_open), reinterpret_cast<void**>(&original_open)}};
78+
rebind_symbols(binding, 1);
79+
interceptionEnabled = true;
80+
}
81+
82+
} // namespace codeql

0 commit comments

Comments
 (0)