[clang] [clang-tools-extra] [llvm] [llvm][clang] Sandbox filesystem reads (PR #162151)
Jan Svoboda via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 16 10:55:54 PDT 2025
https://github.com/jansvoboda11 updated https://github.com/llvm/llvm-project/pull/162151
>From 0e29083706a92cb06f2a3fa564390dbb799104ee Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Wed, 16 Jul 2025 11:24:41 -0700
Subject: [PATCH 01/19] [llvm][clang] Sandbox IO operations (infrastructure)
---
clang/lib/Driver/Job.cpp | 5 ++++
llvm/include/llvm/Support/IOSandbox.h | 20 +++++++++++++++
llvm/lib/Support/IOSandbox.cpp | 19 ++++++++++++++
llvm/lib/Support/IOSandboxInternal.h | 36 +++++++++++++++++++++++++++
llvm/lib/Support/Signals.cpp | 4 +++
5 files changed, 84 insertions(+)
create mode 100644 llvm/include/llvm/Support/IOSandbox.h
create mode 100644 llvm/lib/Support/IOSandbox.cpp
create mode 100644 llvm/lib/Support/IOSandboxInternal.h
diff --git a/clang/lib/Driver/Job.cpp b/clang/lib/Driver/Job.cpp
index 715429bcd2096..ab6cd2973dd6e 100644
--- a/clang/lib/Driver/Job.cpp
+++ b/clang/lib/Driver/Job.cpp
@@ -21,6 +21,7 @@
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/IOSandbox.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Program.h"
@@ -426,6 +427,10 @@ int CC1Command::Execute(ArrayRef<std::optional<StringRef>> Redirects,
if (ExecutionFailed)
*ExecutionFailed = false;
+ // Enabling the sandbox here allows us to restore its previous state even when
+ // this cc1 invocation crashes.
+ auto EnableSandbox = llvm::sys::sandbox_scoped_enable();
+
llvm::CrashRecoveryContext CRC;
CRC.DumpStackAndCleanupOnFailure = true;
diff --git a/llvm/include/llvm/Support/IOSandbox.h b/llvm/include/llvm/Support/IOSandbox.h
new file mode 100644
index 0000000000000..1a8fb9788e3f6
--- /dev/null
+++ b/llvm/include/llvm/Support/IOSandbox.h
@@ -0,0 +1,20 @@
+//===- IOSandbox.h ----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_IOSANDBOX_H
+#define LLVM_SUPPORT_IOSANDBOX_H
+
+#include "llvm/Support/SaveAndRestore.h"
+
+namespace llvm::sys {
+SaveAndRestore<bool> sandbox_scoped_enable();
+SaveAndRestore<bool> sandbox_scoped_disable();
+void sandbox_violation_if_enabled();
+} // namespace llvm::sys
+
+#endif
diff --git a/llvm/lib/Support/IOSandbox.cpp b/llvm/lib/Support/IOSandbox.cpp
new file mode 100644
index 0000000000000..a046d38b48fc3
--- /dev/null
+++ b/llvm/lib/Support/IOSandbox.cpp
@@ -0,0 +1,19 @@
+#include "llvm/Support/IOSandbox.h"
+
+#include <cassert>
+
+using namespace llvm;
+
+thread_local bool IOSandboxEnabled = false;
+
+SaveAndRestore<bool> sys::sandbox_scoped_enable() {
+ return {IOSandboxEnabled, true};
+}
+
+SaveAndRestore<bool> sys::sandbox_scoped_disable() {
+ return {IOSandboxEnabled, false};
+}
+
+void sys::sandbox_violation_if_enabled() {
+ assert(!IOSandboxEnabled && "sandbox violation");
+}
diff --git a/llvm/lib/Support/IOSandboxInternal.h b/llvm/lib/Support/IOSandboxInternal.h
new file mode 100644
index 0000000000000..184b220417fff
--- /dev/null
+++ b/llvm/lib/Support/IOSandboxInternal.h
@@ -0,0 +1,36 @@
+#ifndef LLVM_SUPPORT_IOSANDBOXINTERNAL_H
+#define LLVM_SUPPORT_IOSANDBOXINTERNAL_H
+
+#include "llvm/Support/IOSandbox.h"
+
+namespace llvm {
+namespace detail {
+template <class FnTy> struct Interposed;
+
+template <class RetTy, class... ArgTy> struct Interposed<RetTy (*)(ArgTy...)> {
+ RetTy (*Fn)(ArgTy...);
+
+ RetTy operator()(ArgTy... Arg) const {
+ sys::sandbox_violation_if_enabled();
+ return Fn(std::forward<ArgTy>(Arg)...);
+ }
+};
+
+template <class RetTy, class... ArgTy>
+struct Interposed<RetTy (*)(ArgTy..., ...)> {
+ RetTy (*Fn)(ArgTy..., ...);
+
+ template <class... CVarArgTy>
+ RetTy operator()(ArgTy... Arg, CVarArgTy... CVarArg) const {
+ sys::sandbox_violation_if_enabled();
+ return Fn(std::forward<ArgTy>(Arg)..., std::forward<CVarArgTy>(CVarArg)...);
+ }
+};
+
+template <class FnTy> constexpr auto interpose(FnTy Fn) {
+ return Interposed<FnTy>{Fn};
+}
+} // namespace detail
+} // namespace llvm
+
+#endif
diff --git a/llvm/lib/Support/Signals.cpp b/llvm/lib/Support/Signals.cpp
index f8a14a45ddc3e..076ec293750af 100644
--- a/llvm/lib/Support/Signals.cpp
+++ b/llvm/lib/Support/Signals.cpp
@@ -23,6 +23,7 @@
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/IOSandbox.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
@@ -95,6 +96,9 @@ CallBacksToRun() {
// Signal-safe.
void sys::RunSignalHandlers() {
+ // Let's not interfere with stack trace symbolication and friends.
+ auto BypassSandbox = sandbox_scoped_disable();
+
for (CallbackAndCookie &RunMe : CallBacksToRun()) {
auto Expected = CallbackAndCookie::Status::Initialized;
auto Desired = CallbackAndCookie::Status::Executing;
>From be3530feb1f1d6f2798fae379a322ee77d09c566 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Wed, 16 Jul 2025 11:20:25 -0700
Subject: [PATCH 02/19] [llvm][clang] Sandbox IO operations (getting
`vfs::RealFileSystem`)
---
clang/lib/CodeGen/BackendUtil.cpp | 3 +++
clang/tools/driver/cc1_main.cpp | 7 ++++++-
clang/tools/driver/cc1as_main.cpp | 6 +++++-
llvm/lib/Support/VirtualFileSystem.cpp | 3 +++
4 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 602068436101b..3066bd8313777 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -46,6 +46,7 @@
#include "llvm/Support/BuryPointer.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/IOSandbox.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Program.h"
@@ -1434,6 +1435,8 @@ void clang::emitBackendOutput(CompilerInstance &CI, CodeGenOptions &CGOpts,
std::unique_ptr<llvm::Module> EmptyModule;
if (!CGOpts.ThinLTOIndexFile.empty()) {
+ // FIXME(sandboxing): Figure out how to support distributed indexing.
+ auto BypassSandbox = sys::sandbox_scoped_disable();
// If we are performing a ThinLTO importing compile, load the function index
// into memory and pass it into runThinLTOBackend, which will run the
// function importer and invoke LTO passes.
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index 49f8843515a35..f8588d0ac4549 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -38,6 +38,7 @@
#include "llvm/Support/BuryPointer.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/IOSandbox.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
@@ -272,7 +273,11 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
CompilerInvocation::GetResourcesPath(Argv0, MainAddr);
/// Create the actual file system.
- Clang->createVirtualFileSystem(llvm::vfs::getRealFileSystem(), DiagsBuffer);
+ auto VFS = [] {
+ auto BypassSandbox = llvm::sys::sandbox_scoped_disable();
+ return llvm::vfs::getRealFileSystem();
+ }();
+ Clang->createVirtualFileSystem(std::move(VFS), DiagsBuffer);
// Create the actual diagnostics engine.
Clang->createDiagnostics();
diff --git a/clang/tools/driver/cc1as_main.cpp b/clang/tools/driver/cc1as_main.cpp
index 50da2f8449a22..4210267664f5b 100644
--- a/clang/tools/driver/cc1as_main.cpp
+++ b/clang/tools/driver/cc1as_main.cpp
@@ -45,6 +45,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/IOSandbox.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
@@ -672,7 +673,10 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
DiagClient->setPrefix("clang -cc1as");
DiagnosticsEngine Diags(DiagnosticIDs::create(), DiagOpts, DiagClient);
- auto VFS = vfs::getRealFileSystem();
+ auto VFS = [] {
+ auto BypassSandbox = sys::sandbox_scoped_disable();
+ return vfs::getRealFileSystem();
+ }();
// Set an error handler, so that any LLVM backend diagnostics go through our
// error handler.
diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp
index c754b30d8de4a..1d27d02a27f47 100644
--- a/llvm/lib/Support/VirtualFileSystem.cpp
+++ b/llvm/lib/Support/VirtualFileSystem.cpp
@@ -31,6 +31,7 @@
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FileSystem/UniqueID.h"
+#include "llvm/Support/IOSandbox.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SMLoc.h"
@@ -399,10 +400,12 @@ void RealFileSystem::printImpl(raw_ostream &OS, PrintType Type,
IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() {
static IntrusiveRefCntPtr<FileSystem> FS =
makeIntrusiveRefCnt<RealFileSystem>(true);
+ sys::sandbox_violation_if_enabled();
return FS;
}
std::unique_ptr<FileSystem> vfs::createPhysicalFileSystem() {
+ sys::sandbox_violation_if_enabled();
return std::make_unique<RealFileSystem>(false);
}
>From 9c944d688bab8e8ca3f776547021b1f564e8b00c Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Thu, 10 Jul 2025 08:01:31 -0700
Subject: [PATCH 03/19] [llvm][clang] Sandbox IO operations (read, pread)
---
clang/lib/Serialization/GlobalModuleIndex.cpp | 4 ++
clang/tools/driver/cc1_main.cpp | 20 +++---
clang/tools/driver/cc1as_main.cpp | 7 +-
llvm/lib/Support/IOSandboxInternal.h | 10 +++
llvm/lib/Support/Unix/Path.inc | 68 ++++++++++---------
llvm/lib/Support/VirtualFileSystem.cpp | 11 ++-
6 files changed, 76 insertions(+), 44 deletions(-)
diff --git a/clang/lib/Serialization/GlobalModuleIndex.cpp b/clang/lib/Serialization/GlobalModuleIndex.cpp
index 1e2272c48bd04..613121a9596fd 100644
--- a/clang/lib/Serialization/GlobalModuleIndex.cpp
+++ b/clang/lib/Serialization/GlobalModuleIndex.cpp
@@ -24,6 +24,7 @@
#include "llvm/Bitstream/BitstreamWriter.h"
#include "llvm/Support/DJB.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/IOSandbox.h"
#include "llvm/Support/LockFileManager.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/OnDiskHashTable.h"
@@ -250,6 +251,9 @@ GlobalModuleIndex::~GlobalModuleIndex() {
std::pair<GlobalModuleIndex *, llvm::Error>
GlobalModuleIndex::readIndex(StringRef Path) {
+ // This is a compiler-internal input/output, let's bypass the sandbox.
+ auto BypassSandbox = llvm::sys::sandbox_scoped_disable();
+
// Load the index file, if it's there.
llvm::SmallString<128> IndexPath;
IndexPath += Path;
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index f8588d0ac4549..af30ba68dfde4 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -307,15 +307,19 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
// If any timers were active but haven't been destroyed yet, print their
// results now. This happens in -disable-free mode.
- std::unique_ptr<raw_ostream> IOFile = llvm::CreateInfoOutputFile();
- if (Clang->getCodeGenOpts().TimePassesJson) {
- *IOFile << "{\n";
- llvm::TimerGroup::printAllJSONValues(*IOFile, "");
- *IOFile << "\n}\n";
- } else if (!Clang->getCodeGenOpts().TimePassesStatsFile) {
- llvm::TimerGroup::printAll(*IOFile);
+ {
+ // This isn't a formal input or output of the compiler.
+ auto BypassSandbox = llvm::sys::sandbox_scoped_disable();
+ std::unique_ptr<raw_ostream> IOFile = llvm::CreateInfoOutputFile();
+ if (Clang->getCodeGenOpts().TimePassesJson) {
+ *IOFile << "{\n";
+ llvm::TimerGroup::printAllJSONValues(*IOFile, "");
+ *IOFile << "\n}\n";
+ } else if (!Clang->getCodeGenOpts().TimePassesStatsFile) {
+ llvm::TimerGroup::printAll(*IOFile);
+ }
+ llvm::TimerGroup::clearAll();
}
- llvm::TimerGroup::clearAll();
if (llvm::timeTraceProfilerEnabled()) {
// It is possible that the compiler instance doesn't own a file manager here
diff --git a/clang/tools/driver/cc1as_main.cpp b/clang/tools/driver/cc1as_main.cpp
index 4210267664f5b..285a128add1e1 100644
--- a/clang/tools/driver/cc1as_main.cpp
+++ b/clang/tools/driver/cc1as_main.cpp
@@ -426,8 +426,11 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
if (!TheTarget)
return Diags.Report(diag::err_target_unknown_triple) << Opts.Triple.str();
- ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
- MemoryBuffer::getFileOrSTDIN(Opts.InputFile, /*IsText=*/true);
+ ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer = [=] {
+ // FIXME(sandboxing): Make this a proper input file.
+ auto BypassSandbox = sys::sandbox_scoped_disable();
+ return MemoryBuffer::getFileOrSTDIN(Opts.InputFile, /*IsText=*/true);
+ }();
if (std::error_code EC = Buffer.getError()) {
return Diags.Report(diag::err_fe_error_reading)
diff --git a/llvm/lib/Support/IOSandboxInternal.h b/llvm/lib/Support/IOSandboxInternal.h
index 184b220417fff..72845966d5eb3 100644
--- a/llvm/lib/Support/IOSandboxInternal.h
+++ b/llvm/lib/Support/IOSandboxInternal.h
@@ -3,6 +3,13 @@
#include "llvm/Support/IOSandbox.h"
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+extern thread_local bool IOSandboxEnabled;
+
namespace llvm {
namespace detail {
template <class FnTy> struct Interposed;
@@ -31,6 +38,9 @@ template <class FnTy> constexpr auto interpose(FnTy Fn) {
return Interposed<FnTy>{Fn};
}
} // namespace detail
+
+static constexpr auto read = detail::interpose(::read);
+static constexpr auto pread = detail::interpose(::pread);
} // namespace llvm
#endif
diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc
index 0d991ead72416..fa27f86241b7d 100644
--- a/llvm/lib/Support/Unix/Path.inc
+++ b/llvm/lib/Support/Unix/Path.inc
@@ -114,6 +114,8 @@ typedef uint_t uint;
#define STATVFS_F_FLAG(vfs) (vfs).f_flags
#endif
+#include "IOSandboxInternal.h"
+
using namespace llvm;
namespace llvm {
@@ -197,7 +199,7 @@ std::string getMainExecutable(const char *argv0, void *MainAddr) {
uint32_t size = sizeof(exe_path);
if (_NSGetExecutablePath(exe_path, &size) == 0) {
char link_path[PATH_MAX];
- if (realpath(exe_path, link_path))
+ if (::realpath(exe_path, link_path))
return link_path;
}
#elif defined(__FreeBSD__)
@@ -368,7 +370,7 @@ ErrorOr<space_info> disk_space(const Twine &Path) {
std::error_code current_path(SmallVectorImpl<char> &result) {
result.clear();
- const char *pwd = ::getenv("PWD");
+ const char *pwd = getenv("PWD");
llvm::sys::fs::file_status PWDStatus, DotStatus;
if (pwd && llvm::sys::path::is_absolute(pwd) &&
!llvm::sys::fs::status(pwd, PWDStatus) &&
@@ -381,7 +383,7 @@ std::error_code current_path(SmallVectorImpl<char> &result) {
result.resize_for_overwrite(PATH_MAX);
while (true) {
- if (::getcwd(result.data(), result.size()) == nullptr) {
+ if (getcwd(result.data(), result.size()) == nullptr) {
// See if there was a real error.
if (errno != ENOMEM) {
result.clear();
@@ -402,7 +404,7 @@ std::error_code set_current_path(const Twine &path) {
SmallString<128> path_storage;
StringRef p = path.toNullTerminatedStringRef(path_storage);
- if (::chdir(p.begin()) == -1)
+ if (chdir(p.begin()) == -1)
return errnoAsErrorCode();
return std::error_code();
@@ -413,7 +415,7 @@ std::error_code create_directory(const Twine &path, bool IgnoreExisting,
SmallString<128> path_storage;
StringRef p = path.toNullTerminatedStringRef(path_storage);
- if (::mkdir(p.begin(), Perms) == -1) {
+ if (mkdir(p.begin(), Perms) == -1) {
if (errno != EEXIST || !IgnoreExisting)
return errnoAsErrorCode();
}
@@ -430,7 +432,7 @@ std::error_code create_link(const Twine &to, const Twine &from) {
StringRef f = from.toNullTerminatedStringRef(from_storage);
StringRef t = to.toNullTerminatedStringRef(to_storage);
- if (::symlink(t.begin(), f.begin()) == -1)
+ if (symlink(t.begin(), f.begin()) == -1)
return errnoAsErrorCode();
return std::error_code();
@@ -443,7 +445,7 @@ std::error_code create_hard_link(const Twine &to, const Twine &from) {
StringRef f = from.toNullTerminatedStringRef(from_storage);
StringRef t = to.toNullTerminatedStringRef(to_storage);
- if (::link(t.begin(), f.begin()) == -1)
+ if (link(t.begin(), f.begin()) == -1)
return errnoAsErrorCode();
return std::error_code();
@@ -594,7 +596,7 @@ std::error_code rename(const Twine &from, const Twine &to) {
std::error_code resize_file(int FD, uint64_t Size) {
// Use ftruncate as a fallback. It may or may not allocate space. At least on
// OS X with HFS+ it does.
- if (::ftruncate(FD, Size) == -1)
+ if (ftruncate(FD, Size) == -1)
return errnoAsErrorCode();
return std::error_code();
@@ -764,13 +766,13 @@ std::error_code status(const Twine &Path, file_status &Result, bool Follow) {
StringRef P = Path.toNullTerminatedStringRef(PathStorage);
struct stat Status;
- int StatRet = (Follow ? ::stat : ::lstat)(P.begin(), &Status);
+ int StatRet = (Follow ? stat : lstat)(P.begin(), &Status);
return fillStatus(StatRet, Status, Result);
}
std::error_code status(int FD, file_status &Result) {
struct stat Status;
- int StatRet = ::fstat(FD, &Status);
+ int StatRet = fstat(FD, &Status);
return fillStatus(StatRet, Status, Result);
}
@@ -786,13 +788,13 @@ std::error_code setPermissions(const Twine &Path, perms Permissions) {
SmallString<128> PathStorage;
StringRef P = Path.toNullTerminatedStringRef(PathStorage);
- if (::chmod(P.begin(), Permissions))
+ if (chmod(P.begin(), Permissions))
return errnoAsErrorCode();
return std::error_code();
}
std::error_code setPermissions(int FD, perms Permissions) {
- if (::fchmod(FD, Permissions))
+ if (fchmod(FD, Permissions))
return errnoAsErrorCode();
return std::error_code();
}
@@ -803,7 +805,7 @@ std::error_code setLastAccessAndModificationTime(int FD, TimePoint<> AccessTime,
timespec Times[2];
Times[0] = sys::toTimeSpec(AccessTime);
Times[1] = sys::toTimeSpec(ModificationTime);
- if (::futimens(FD, Times))
+ if (futimens(FD, Times))
return errnoAsErrorCode();
return std::error_code();
#elif defined(HAVE_FUTIMES)
@@ -813,7 +815,7 @@ std::error_code setLastAccessAndModificationTime(int FD, TimePoint<> AccessTime,
Times[1] =
sys::toTimeVal(std::chrono::time_point_cast<std::chrono::microseconds>(
ModificationTime));
- if (::futimes(FD, Times))
+ if (futimes(FD, Times))
return errnoAsErrorCode();
return std::error_code();
#elif defined(__MVS__)
@@ -861,7 +863,7 @@ std::error_code mapped_file_region::init(int FD, uint64_t Offset,
}
#endif // #if defined (__APPLE__)
- Mapping = ::mmap(nullptr, Size, prot, flags, FD, Offset);
+ Mapping = mmap(nullptr, Size, prot, flags, FD, Offset);
if (Mapping == MAP_FAILED)
return errnoAsErrorCode();
return std::error_code();
@@ -878,7 +880,7 @@ mapped_file_region::mapped_file_region(int fd, mapmode mode, size_t length,
void mapped_file_region::unmapImpl() {
if (Mapping)
- ::munmap(Mapping, Size);
+ munmap(Mapping, Size);
}
std::error_code mapped_file_region::sync() const {
@@ -906,7 +908,7 @@ std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
StringRef path,
bool follow_symlinks) {
SmallString<128> path_null(path);
- DIR *directory = ::opendir(path_null.c_str());
+ DIR *directory = opendir(path_null.c_str());
if (!directory)
return errnoAsErrorCode();
@@ -919,7 +921,7 @@ std::error_code detail::directory_iterator_construct(detail::DirIterState &it,
std::error_code detail::directory_iterator_destruct(detail::DirIterState &it) {
if (it.IterationHandle)
- ::closedir(reinterpret_cast<DIR *>(it.IterationHandle));
+ closedir(reinterpret_cast<DIR *>(it.IterationHandle));
it.IterationHandle = 0;
it.CurrentEntry = directory_entry();
return std::error_code();
@@ -941,7 +943,7 @@ static file_type direntType(dirent *Entry) {
std::error_code detail::directory_iterator_increment(detail::DirIterState &It) {
errno = 0;
- dirent *CurDir = ::readdir(reinterpret_cast<DIR *>(It.IterationHandle));
+ dirent *CurDir = readdir(reinterpret_cast<DIR *>(It.IterationHandle));
if (CurDir == nullptr && errno != 0) {
return errnoAsErrorCode();
} else if (CurDir != nullptr) {
@@ -976,7 +978,7 @@ ErrorOr<basic_file_status> directory_entry::status() const {
static bool hasProcSelfFD() {
// If we have a /proc filesystem mounted, we can quickly establish the
// real name of the file with readlink
- static const bool Result = (::access("/proc/self/fd", R_OK) == 0);
+ static const bool Result = (access("/proc/self/fd", R_OK) == 0);
return Result;
}
#endif
@@ -1031,9 +1033,9 @@ std::error_code openFile(const Twine &Name, int &ResultFD,
SmallString<128> Storage;
StringRef P = Name.toNullTerminatedStringRef(Storage);
- // Call ::open in a lambda to avoid overload resolution in RetryAfterSignal
+ // Call open in a lambda to avoid overload resolution in RetryAfterSignal
// when open is overloaded, such as in Bionic.
- auto Open = [&]() { return ::open(P.begin(), OpenFlags, Mode); };
+ auto Open = [&]() { return open(P.begin(), OpenFlags, Mode); };
if ((ResultFD = sys::RetryAfterSignal(-1, Open)) < 0)
return errnoAsErrorCode();
#ifndef O_CLOEXEC
@@ -1155,7 +1157,7 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD,
// When F_GETPATH is availble, it is the quickest way to get
// the real path name.
char Buffer[PATH_MAX];
- if (::fcntl(ResultFD, F_GETPATH, Buffer) != -1)
+ if (fcntl(ResultFD, F_GETPATH, Buffer) != -1)
RealPath->append(Buffer, Buffer + strlen(Buffer));
#else
char Buffer[PATH_MAX];
@@ -1163,7 +1165,7 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD,
if (hasProcSelfFD()) {
char ProcPath[64];
snprintf(ProcPath, sizeof(ProcPath), "/proc/self/fd/%d", ResultFD);
- ssize_t CharCount = ::readlink(ProcPath, Buffer, sizeof(Buffer));
+ ssize_t CharCount = readlink(ProcPath, Buffer, sizeof(Buffer));
if (CharCount > 0)
RealPath->append(Buffer, Buffer + CharCount);
} else {
@@ -1171,8 +1173,8 @@ std::error_code openFileForRead(const Twine &Name, int &ResultFD,
SmallString<128> Storage;
StringRef P = Name.toNullTerminatedStringRef(Storage);
- // Use ::realpath to get the real path name
- if (::realpath(P.begin(), Buffer) != nullptr)
+ // Use realpath to get the real path name
+ if (realpath(P.begin(), Buffer) != nullptr)
RealPath->append(Buffer, Buffer + strlen(Buffer));
#if defined(TRY_PROC_SELF_FD)
}
@@ -1224,11 +1226,11 @@ Expected<size_t> readNativeFileSlice(file_t FD, MutableArrayRef<char> Buf,
#endif
#ifdef HAVE_PREAD
ssize_t NumRead =
- sys::RetryAfterSignal(-1, ::pread, FD, Buf.data(), Size, Offset);
+ sys::RetryAfterSignal(-1, pread, FD, Buf.data(), Size, Offset);
#else
if (lseek(FD, Offset, SEEK_SET) == -1)
return errorCodeToError(errnoAsErrorCode());
- ssize_t NumRead = sys::RetryAfterSignal(-1, ::read, FD, Buf.data(), Size);
+ ssize_t NumRead = sys::RetryAfterSignal(-1, read, FD, Buf.data(), Size);
#endif
if (NumRead == -1)
return errorCodeToError(errnoAsErrorCode());
@@ -1253,7 +1255,7 @@ std::error_code tryLockFile(int FD, std::chrono::milliseconds Timeout,
Lock.l_whence = SEEK_SET;
Lock.l_start = 0;
Lock.l_len = 0;
- if (::fcntl(FD, F_SETLK, &Lock) != -1)
+ if (fcntl(FD, F_SETLK, &Lock) != -1)
return std::error_code();
int Error = errno;
if (Error != EACCES && Error != EAGAIN)
@@ -1279,7 +1281,7 @@ std::error_code lockFile(int FD, LockKind Kind) {
Lock.l_whence = SEEK_SET;
Lock.l_start = 0;
Lock.l_len = 0;
- if (::fcntl(FD, F_SETLKW, &Lock) != -1)
+ if (fcntl(FD, F_SETLKW, &Lock) != -1)
return std::error_code();
return errnoAsErrorCode();
}
@@ -1290,7 +1292,7 @@ std::error_code unlockFile(int FD) {
Lock.l_whence = SEEK_SET;
Lock.l_start = 0;
Lock.l_len = 0;
- if (::fcntl(FD, F_SETLK, &Lock) != -1)
+ if (fcntl(FD, F_SETLK, &Lock) != -1)
return std::error_code();
return errnoAsErrorCode();
}
@@ -1357,14 +1359,14 @@ std::error_code real_path(const Twine &path, SmallVectorImpl<char> &dest,
SmallString<128> Storage;
StringRef P = path.toNullTerminatedStringRef(Storage);
char Buffer[PATH_MAX];
- if (::realpath(P.begin(), Buffer) == nullptr)
+ if (realpath(P.begin(), Buffer) == nullptr)
return errnoAsErrorCode();
dest.append(Buffer, Buffer + strlen(Buffer));
return std::error_code();
}
std::error_code changeFileOwnership(int FD, uint32_t Owner, uint32_t Group) {
- auto FChown = [&]() { return ::fchown(FD, Owner, Group); };
+ auto FChown = [&]() { return fchown(FD, Owner, Group); };
// Retry if fchown call fails due to interruption.
if ((sys::RetryAfterSignal(-1, FChown)) < 0)
return errnoAsErrorCode();
diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp
index 1d27d02a27f47..ecd50a8004f70 100644
--- a/llvm/lib/Support/VirtualFileSystem.cpp
+++ b/llvm/lib/Support/VirtualFileSystem.cpp
@@ -222,6 +222,7 @@ RealFile::~RealFile() { close(); }
ErrorOr<Status> RealFile::status() {
assert(FD != kInvalidFile && "cannot stat closed file");
if (!S.isStatusKnown()) {
+ auto BypassSandbox = sys::sandbox_scoped_disable();
file_status RealStatus;
if (std::error_code EC = sys::fs::status(FD, RealStatus))
return EC;
@@ -238,6 +239,7 @@ ErrorOr<std::unique_ptr<MemoryBuffer>>
RealFile::getBuffer(const Twine &Name, int64_t FileSize,
bool RequiresNullTerminator, bool IsVolatile) {
assert(FD != kInvalidFile && "cannot get buffer for closed file");
+ auto BypassSandbox = sys::sandbox_scoped_disable();
return MemoryBuffer::getOpenFile(FD, Name, FileSize, RequiresNullTerminator,
IsVolatile);
}
@@ -307,6 +309,7 @@ class RealFileSystem : public FileSystem {
ErrorOr<std::unique_ptr<File>>
openFileForReadWithFlags(const Twine &Name, sys::fs::OpenFlags Flags) {
+ auto BypassSandbox = sys::sandbox_scoped_disable();
SmallString<256> RealName, Storage;
Expected<file_t> FDOrErr = sys::fs::openNativeFileForRead(
adjustPath(Name, Storage), Flags, &RealName);
@@ -328,6 +331,7 @@ class RealFileSystem : public FileSystem {
} // namespace
ErrorOr<Status> RealFileSystem::status(const Twine &Path) {
+ auto BypassSandbox = sys::sandbox_scoped_disable();
SmallString<256> Storage;
sys::fs::file_status RealStatus;
if (std::error_code EC =
@@ -352,6 +356,7 @@ llvm::ErrorOr<std::string> RealFileSystem::getCurrentWorkingDirectory() const {
if (WD)
return WD->getError();
+ auto BypassSandbox = sys::sandbox_scoped_disable();
SmallString<128> Dir;
if (std::error_code EC = llvm::sys::fs::current_path(Dir))
return EC;
@@ -382,6 +387,7 @@ std::error_code RealFileSystem::isLocal(const Twine &Path, bool &Result) {
std::error_code RealFileSystem::getRealPath(const Twine &Path,
SmallVectorImpl<char> &Output) {
+ auto BypassSandbox = sys::sandbox_scoped_disable();
SmallString<256> Storage;
return llvm::sys::fs::real_path(adjustPath(Path, Storage), Output);
}
@@ -415,12 +421,15 @@ class RealFSDirIter : public llvm::vfs::detail::DirIterImpl {
llvm::sys::fs::directory_iterator Iter;
public:
- RealFSDirIter(const Twine &Path, std::error_code &EC) : Iter(Path, EC) {
+ RealFSDirIter(const Twine &Path, std::error_code &EC) {
+ auto BypassSandbox = sys::sandbox_scoped_disable();
+ Iter = llvm::sys::fs::directory_iterator{Path, EC};
if (Iter != llvm::sys::fs::directory_iterator())
CurrentEntry = directory_entry(Iter->path(), Iter->type());
}
std::error_code increment() override {
+ auto BypassSandbox = sys::sandbox_scoped_disable();
std::error_code EC;
Iter.increment(EC);
CurrentEntry = (Iter == llvm::sys::fs::directory_iterator())
>From 4a28775603ec70b80d1359509b968dad1bbcfb6f Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Thu, 10 Jul 2025 14:11:14 -0700
Subject: [PATCH 04/19] [llvm][clang] Sandbox IO operations (mmap)
---
clang/lib/Driver/Driver.cpp | 3 +++
llvm/lib/Support/IOSandboxInternal.h | 4 ++++
2 files changed, 7 insertions(+)
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 40ea513e85427..7cf23fdb2b97b 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -87,6 +87,7 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/IOSandbox.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
@@ -1870,6 +1871,8 @@ bool Driver::getCrashDiagnosticFile(StringRef ReproCrashFilename,
using namespace llvm::sys;
assert(llvm::Triple(llvm::sys::getProcessTriple()).isOSDarwin() &&
"Only knows about .crash files on Darwin");
+ // This is not a formal output of the compiler, let's bypass the sandbox.
+ auto BypassSandbox = sandbox_scoped_disable();
// The .crash file can be found on at ~/Library/Logs/DiagnosticReports/
// (or /Library/Logs/DiagnosticReports for root) and has the filename pattern
diff --git a/llvm/lib/Support/IOSandboxInternal.h b/llvm/lib/Support/IOSandboxInternal.h
index 72845966d5eb3..f784ef7131403 100644
--- a/llvm/lib/Support/IOSandboxInternal.h
+++ b/llvm/lib/Support/IOSandboxInternal.h
@@ -7,6 +7,9 @@
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
extern thread_local bool IOSandboxEnabled;
@@ -41,6 +44,7 @@ template <class FnTy> constexpr auto interpose(FnTy Fn) {
static constexpr auto read = detail::interpose(::read);
static constexpr auto pread = detail::interpose(::pread);
+static constexpr auto mmap = detail::interpose(::mmap);
} // namespace llvm
#endif
>From 1b017822596f2206c4b343aaff79cc65c4ffa3d3 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Thu, 10 Jul 2025 14:31:20 -0700
Subject: [PATCH 05/19] [llvm][clang] Sandbox IO operations (readdir)
---
clang/lib/Serialization/GlobalModuleIndex.cpp | 3 +++
clang/lib/Serialization/ModuleCache.cpp | 4 ++++
llvm/lib/Support/IOSandboxInternal.h | 2 ++
3 files changed, 9 insertions(+)
diff --git a/clang/lib/Serialization/GlobalModuleIndex.cpp b/clang/lib/Serialization/GlobalModuleIndex.cpp
index 613121a9596fd..99d90054cb09f 100644
--- a/clang/lib/Serialization/GlobalModuleIndex.cpp
+++ b/clang/lib/Serialization/GlobalModuleIndex.cpp
@@ -847,6 +847,9 @@ llvm::Error
GlobalModuleIndex::writeIndex(FileManager &FileMgr,
const PCHContainerReader &PCHContainerRdr,
StringRef Path) {
+ // This is a compiler-internal input/output, let's bypass the sandbox.
+ auto BypassSandbox = llvm::sys::sandbox_scoped_disable();
+
llvm::SmallString<128> IndexPath;
IndexPath += Path;
llvm::sys::path::append(IndexPath, IndexFileName);
diff --git a/clang/lib/Serialization/ModuleCache.cpp b/clang/lib/Serialization/ModuleCache.cpp
index 9850956380423..28772da83b465 100644
--- a/clang/lib/Serialization/ModuleCache.cpp
+++ b/clang/lib/Serialization/ModuleCache.cpp
@@ -11,6 +11,7 @@
#include "clang/Serialization/InMemoryModuleCache.h"
#include "clang/Serialization/ModuleFile.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/IOSandbox.h"
#include "llvm/Support/LockFileManager.h"
#include "llvm/Support/Path.h"
@@ -27,6 +28,9 @@ void clang::maybePruneImpl(StringRef Path, time_t PruneInterval,
if (PruneInterval <= 0 || PruneAfter <= 0)
return;
+ // This is a compiler-internal input/output, let's bypass the sandbox.
+ auto BypassSandbox = llvm::sys::sandbox_scoped_disable();
+
llvm::SmallString<128> TimestampFile(Path);
llvm::sys::path::append(TimestampFile, "modules.timestamp");
diff --git a/llvm/lib/Support/IOSandboxInternal.h b/llvm/lib/Support/IOSandboxInternal.h
index f784ef7131403..163c0cfc9dad8 100644
--- a/llvm/lib/Support/IOSandboxInternal.h
+++ b/llvm/lib/Support/IOSandboxInternal.h
@@ -10,6 +10,7 @@
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
+#include <dirent.h>
extern thread_local bool IOSandboxEnabled;
@@ -45,6 +46,7 @@ template <class FnTy> constexpr auto interpose(FnTy Fn) {
static constexpr auto read = detail::interpose(::read);
static constexpr auto pread = detail::interpose(::pread);
static constexpr auto mmap = detail::interpose(::mmap);
+static constexpr auto readdir = detail::interpose(::readdir);
} // namespace llvm
#endif
>From 85f9ca62a382acb393619c53e8032a9395efddb3 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Thu, 10 Jul 2025 15:46:01 -0700
Subject: [PATCH 06/19] [llvm][clang] Sandbox IO operations (stat, lstat,
fstat)
---
clang/lib/Serialization/ModuleCache.cpp | 2 ++
clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp | 4 ++++
llvm/lib/Support/IOSandboxInternal.h | 4 ++++
llvm/lib/Support/LockFileManager.cpp | 5 +++++
llvm/lib/Support/VirtualOutputBackends.cpp | 5 +++++
llvm/lib/Support/raw_ostream.cpp | 4 ++++
6 files changed, 24 insertions(+)
diff --git a/clang/lib/Serialization/ModuleCache.cpp b/clang/lib/Serialization/ModuleCache.cpp
index 28772da83b465..6a3675620977d 100644
--- a/clang/lib/Serialization/ModuleCache.cpp
+++ b/clang/lib/Serialization/ModuleCache.cpp
@@ -119,6 +119,8 @@ class CrossProcessModuleCache : public ModuleCache {
}
std::time_t getModuleTimestamp(StringRef ModuleFilename) override {
+ // This is a compiler-internal input/output, let's bypass the sandbox.
+ auto SandboxBypass = llvm::sys::sandbox_scoped_disable();
std::string TimestampFilename =
serialization::ModuleFile::getTimestampFilename(ModuleFilename);
llvm::sys::fs::file_status Status;
diff --git a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index 217b853305ed1..11e53a5132563 100644
--- a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
@@ -37,6 +37,7 @@
#include "llvm/Support/Errc.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/IOSandbox.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
@@ -257,6 +258,9 @@ void HTMLDiagnostics::FlushDiagnosticsImpl(
void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
FilesMade *filesMade) {
+ // FIXME(sandboxing): Remove this by adopting `llvm::vfs::OutputBackend`.
+ auto SandboxBypass = llvm::sys::sandbox_scoped_disable();
+
// Create the HTML directory if it is missing.
if (!createdDir) {
createdDir = true;
diff --git a/llvm/lib/Support/IOSandboxInternal.h b/llvm/lib/Support/IOSandboxInternal.h
index 163c0cfc9dad8..044b7dd9bd781 100644
--- a/llvm/lib/Support/IOSandboxInternal.h
+++ b/llvm/lib/Support/IOSandboxInternal.h
@@ -4,6 +4,7 @@
#include "llvm/Support/IOSandbox.h"
#include <stdio.h>
+#include <sys/stat.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
@@ -47,6 +48,9 @@ static constexpr auto read = detail::interpose(::read);
static constexpr auto pread = detail::interpose(::pread);
static constexpr auto mmap = detail::interpose(::mmap);
static constexpr auto readdir = detail::interpose(::readdir);
+static constexpr auto stat = detail::interpose(::stat);
+static constexpr auto lstat = detail::interpose(::lstat);
+static constexpr auto fstat = detail::interpose(::fstat);
} // namespace llvm
#endif
diff --git a/llvm/lib/Support/LockFileManager.cpp b/llvm/lib/Support/LockFileManager.cpp
index cdded51108b50..54c42e4dd53e6 100644
--- a/llvm/lib/Support/LockFileManager.cpp
+++ b/llvm/lib/Support/LockFileManager.cpp
@@ -14,6 +14,7 @@
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/ExponentialBackoff.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/IOSandbox.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
@@ -51,6 +52,8 @@ using namespace llvm;
/// \returns The process ID of the process that owns this lock file
std::optional<LockFileManager::OwnedByAnother>
LockFileManager::readLockFile(StringRef LockFileName) {
+ auto SandboxBypass = sys::sandbox_scoped_disable();
+
// Read the owning host and PID out of the lock file. If it appears that the
// owning process is dead, the lock file is invalid.
ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr =
@@ -246,6 +249,8 @@ Expected<bool> LockFileManager::tryLock() {
}
LockFileManager::~LockFileManager() {
+ auto SandboxBypass = sys::sandbox_scoped_disable();
+
if (!std::holds_alternative<OwnedByUs>(Owner))
return;
diff --git a/llvm/lib/Support/VirtualOutputBackends.cpp b/llvm/lib/Support/VirtualOutputBackends.cpp
index de59b8ab63a53..82ee6df891120 100644
--- a/llvm/lib/Support/VirtualOutputBackends.cpp
+++ b/llvm/lib/Support/VirtualOutputBackends.cpp
@@ -18,6 +18,7 @@
#include "llvm/Support/VirtualOutputBackends.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/IOSandbox.h"
#include "llvm/Support/LockFileManager.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
@@ -553,6 +554,8 @@ Error OnDiskOutputFile::keep() {
}
Error OnDiskOutputFile::discard() {
+ auto BypassSandbox = sys::sandbox_scoped_disable();
+
// Destroy the streams to flush them.
if (auto E = reset())
return E;
@@ -582,6 +585,8 @@ Error OnDiskOutputBackend::makeAbsolute(SmallVectorImpl<char> &Path) const {
Expected<std::unique_ptr<OutputFileImpl>>
OnDiskOutputBackend::createFileImpl(StringRef Path,
std::optional<OutputConfig> Config) {
+ auto BypassSandbox = sys::sandbox_scoped_disable();
+
SmallString<256> AbsPath;
if (Path != "-") {
AbsPath = Path;
diff --git a/llvm/lib/Support/raw_ostream.cpp b/llvm/lib/Support/raw_ostream.cpp
index 07b99896543bd..0ea5f024c82c5 100644
--- a/llvm/lib/Support/raw_ostream.cpp
+++ b/llvm/lib/Support/raw_ostream.cpp
@@ -20,6 +20,7 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/IOSandbox.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/NativeFormatting.h"
#include "llvm/Support/Process.h"
@@ -617,6 +618,9 @@ raw_fd_ostream::raw_fd_ostream(StringRef Filename, std::error_code &EC,
raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered,
OStreamKind K)
: raw_pwrite_stream(unbuffered, K), FD(fd), ShouldClose(shouldClose) {
+ // FIXME(sandboxing): Remove this by adopting `llvm::vfs::OutputBackend`.
+ auto BypassSandbox = sys::sandbox_scoped_disable();
+
if (FD < 0 ) {
ShouldClose = false;
return;
>From 637ff5eeac4e4f4c2f5230e6ffffb3a0d14d816c Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Tue, 15 Jul 2025 15:50:29 -0700
Subject: [PATCH 07/19] [llvm][clang] Sandbox IO operations (getcwd)
---
llvm/lib/Support/IOSandboxInternal.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/llvm/lib/Support/IOSandboxInternal.h b/llvm/lib/Support/IOSandboxInternal.h
index 044b7dd9bd781..9e7bb7d6f4567 100644
--- a/llvm/lib/Support/IOSandboxInternal.h
+++ b/llvm/lib/Support/IOSandboxInternal.h
@@ -51,6 +51,7 @@ static constexpr auto readdir = detail::interpose(::readdir);
static constexpr auto stat = detail::interpose(::stat);
static constexpr auto lstat = detail::interpose(::lstat);
static constexpr auto fstat = detail::interpose(::fstat);
+static constexpr auto getcwd = detail::interpose(::getcwd);
} // namespace llvm
#endif
>From 54de166adeafd87417663272f42ed6025be44bf9 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Tue, 15 Jul 2025 15:51:46 -0700
Subject: [PATCH 08/19] [llvm][clang] Sandbox IO operations (realpath)
---
llvm/lib/Support/IOSandboxInternal.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/llvm/lib/Support/IOSandboxInternal.h b/llvm/lib/Support/IOSandboxInternal.h
index 9e7bb7d6f4567..80fa79220cc54 100644
--- a/llvm/lib/Support/IOSandboxInternal.h
+++ b/llvm/lib/Support/IOSandboxInternal.h
@@ -52,6 +52,7 @@ static constexpr auto stat = detail::interpose(::stat);
static constexpr auto lstat = detail::interpose(::lstat);
static constexpr auto fstat = detail::interpose(::fstat);
static constexpr auto getcwd = detail::interpose(::getcwd);
+static constexpr auto realpath = detail::interpose(::realpath);
} // namespace llvm
#endif
>From 84e59fa0ca27ed7671e248101d398c1687b18041 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Tue, 15 Jul 2025 15:52:09 -0700
Subject: [PATCH 09/19] [llvm][clang] Sandbox IO operations (readlink)
---
llvm/lib/Support/IOSandboxInternal.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/llvm/lib/Support/IOSandboxInternal.h b/llvm/lib/Support/IOSandboxInternal.h
index 80fa79220cc54..b7b8b10a87e78 100644
--- a/llvm/lib/Support/IOSandboxInternal.h
+++ b/llvm/lib/Support/IOSandboxInternal.h
@@ -53,6 +53,7 @@ static constexpr auto lstat = detail::interpose(::lstat);
static constexpr auto fstat = detail::interpose(::fstat);
static constexpr auto getcwd = detail::interpose(::getcwd);
static constexpr auto realpath = detail::interpose(::realpath);
+static constexpr auto readlink = detail::interpose(::readlink);
} // namespace llvm
#endif
>From 175f70e761a73e1599083cf4b34e48ed8372ed0c Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Tue, 15 Jul 2025 15:52:51 -0700
Subject: [PATCH 10/19] [llvm][clang] Sandbox IO operations (access)
---
llvm/lib/Support/IOSandboxInternal.h | 1 +
llvm/lib/Support/Unix/Path.inc | 4 ++--
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Support/IOSandboxInternal.h b/llvm/lib/Support/IOSandboxInternal.h
index b7b8b10a87e78..3e953c53c6e2a 100644
--- a/llvm/lib/Support/IOSandboxInternal.h
+++ b/llvm/lib/Support/IOSandboxInternal.h
@@ -48,6 +48,7 @@ static constexpr auto read = detail::interpose(::read);
static constexpr auto pread = detail::interpose(::pread);
static constexpr auto mmap = detail::interpose(::mmap);
static constexpr auto readdir = detail::interpose(::readdir);
+static constexpr auto access = detail::interpose(::access);
static constexpr auto stat = detail::interpose(::stat);
static constexpr auto lstat = detail::interpose(::lstat);
static constexpr auto fstat = detail::interpose(::fstat);
diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc
index fa27f86241b7d..f51c847a5f457 100644
--- a/llvm/lib/Support/Unix/Path.inc
+++ b/llvm/lib/Support/Unix/Path.inc
@@ -623,7 +623,7 @@ std::error_code access(const Twine &Path, AccessMode Mode) {
SmallString<128> PathStorage;
StringRef P = Path.toNullTerminatedStringRef(PathStorage);
- if (::access(P.begin(), convertAccessMode(Mode)) == -1)
+ if (llvm::access(P.begin(), convertAccessMode(Mode)) == -1)
return errnoAsErrorCode();
if (Mode == AccessMode::Execute) {
@@ -978,7 +978,7 @@ ErrorOr<basic_file_status> directory_entry::status() const {
static bool hasProcSelfFD() {
// If we have a /proc filesystem mounted, we can quickly establish the
// real name of the file with readlink
- static const bool Result = (access("/proc/self/fd", R_OK) == 0);
+ static const bool Result = (llvm::access("/proc/self/fd", R_OK) == 0);
return Result;
}
#endif
>From 17ca1e05d57a085e05735840207f174f49877287 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Wed, 1 Oct 2025 15:44:03 -0700
Subject: [PATCH 11/19] Rename, re-layer, add build setting
---
clang/lib/CodeGen/BackendUtil.cpp | 2 +-
clang/lib/Driver/Driver.cpp | 2 +-
clang/lib/Driver/Job.cpp | 2 +-
clang/lib/Serialization/GlobalModuleIndex.cpp | 4 +-
clang/lib/Serialization/ModuleCache.cpp | 4 +-
.../StaticAnalyzer/Core/HTMLDiagnostics.cpp | 2 +-
clang/tools/driver/cc1_main.cpp | 4 +-
clang/tools/driver/cc1as_main.cpp | 4 +-
llvm/CMakeLists.txt | 1 +
llvm/include/llvm/Support/IOSandbox.h | 72 +++++++++++++++++--
llvm/lib/Support/IOSandbox.cpp | 19 -----
llvm/lib/Support/IOSandboxInternal.h | 60 ----------------
llvm/lib/Support/LockFileManager.cpp | 4 +-
llvm/lib/Support/Signals.cpp | 2 +-
llvm/lib/Support/Unix/Path.inc | 26 ++++++-
llvm/lib/Support/VirtualFileSystem.cpp | 20 +++---
llvm/lib/Support/VirtualOutputBackends.cpp | 4 +-
llvm/lib/Support/raw_ostream.cpp | 2 +-
18 files changed, 121 insertions(+), 113 deletions(-)
delete mode 100644 llvm/lib/Support/IOSandbox.cpp
delete mode 100644 llvm/lib/Support/IOSandboxInternal.h
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 3066bd8313777..5a53e2a106b8b 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -1436,7 +1436,7 @@ void clang::emitBackendOutput(CompilerInstance &CI, CodeGenOptions &CGOpts,
std::unique_ptr<llvm::Module> EmptyModule;
if (!CGOpts.ThinLTOIndexFile.empty()) {
// FIXME(sandboxing): Figure out how to support distributed indexing.
- auto BypassSandbox = sys::sandbox_scoped_disable();
+ auto BypassSandbox = sys::sandbox::scopedDisable();
// If we are performing a ThinLTO importing compile, load the function index
// into memory and pass it into runThinLTOBackend, which will run the
// function importer and invoke LTO passes.
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 7cf23fdb2b97b..95a09cd3afe3f 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -1872,7 +1872,7 @@ bool Driver::getCrashDiagnosticFile(StringRef ReproCrashFilename,
assert(llvm::Triple(llvm::sys::getProcessTriple()).isOSDarwin() &&
"Only knows about .crash files on Darwin");
// This is not a formal output of the compiler, let's bypass the sandbox.
- auto BypassSandbox = sandbox_scoped_disable();
+ auto BypassSandbox = sandbox::scopedDisable();
// The .crash file can be found on at ~/Library/Logs/DiagnosticReports/
// (or /Library/Logs/DiagnosticReports for root) and has the filename pattern
diff --git a/clang/lib/Driver/Job.cpp b/clang/lib/Driver/Job.cpp
index ab6cd2973dd6e..da7a1f2e07e90 100644
--- a/clang/lib/Driver/Job.cpp
+++ b/clang/lib/Driver/Job.cpp
@@ -429,7 +429,7 @@ int CC1Command::Execute(ArrayRef<std::optional<StringRef>> Redirects,
// Enabling the sandbox here allows us to restore its previous state even when
// this cc1 invocation crashes.
- auto EnableSandbox = llvm::sys::sandbox_scoped_enable();
+ auto EnableSandbox = llvm::sys::sandbox::scopedEnable();
llvm::CrashRecoveryContext CRC;
CRC.DumpStackAndCleanupOnFailure = true;
diff --git a/clang/lib/Serialization/GlobalModuleIndex.cpp b/clang/lib/Serialization/GlobalModuleIndex.cpp
index 99d90054cb09f..2246a3ac0a57e 100644
--- a/clang/lib/Serialization/GlobalModuleIndex.cpp
+++ b/clang/lib/Serialization/GlobalModuleIndex.cpp
@@ -252,7 +252,7 @@ GlobalModuleIndex::~GlobalModuleIndex() {
std::pair<GlobalModuleIndex *, llvm::Error>
GlobalModuleIndex::readIndex(StringRef Path) {
// This is a compiler-internal input/output, let's bypass the sandbox.
- auto BypassSandbox = llvm::sys::sandbox_scoped_disable();
+ auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
// Load the index file, if it's there.
llvm::SmallString<128> IndexPath;
@@ -848,7 +848,7 @@ GlobalModuleIndex::writeIndex(FileManager &FileMgr,
const PCHContainerReader &PCHContainerRdr,
StringRef Path) {
// This is a compiler-internal input/output, let's bypass the sandbox.
- auto BypassSandbox = llvm::sys::sandbox_scoped_disable();
+ auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
llvm::SmallString<128> IndexPath;
IndexPath += Path;
diff --git a/clang/lib/Serialization/ModuleCache.cpp b/clang/lib/Serialization/ModuleCache.cpp
index 6a3675620977d..1a521920e9dd6 100644
--- a/clang/lib/Serialization/ModuleCache.cpp
+++ b/clang/lib/Serialization/ModuleCache.cpp
@@ -29,7 +29,7 @@ void clang::maybePruneImpl(StringRef Path, time_t PruneInterval,
return;
// This is a compiler-internal input/output, let's bypass the sandbox.
- auto BypassSandbox = llvm::sys::sandbox_scoped_disable();
+ auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
llvm::SmallString<128> TimestampFile(Path);
llvm::sys::path::append(TimestampFile, "modules.timestamp");
@@ -120,7 +120,7 @@ class CrossProcessModuleCache : public ModuleCache {
std::time_t getModuleTimestamp(StringRef ModuleFilename) override {
// This is a compiler-internal input/output, let's bypass the sandbox.
- auto SandboxBypass = llvm::sys::sandbox_scoped_disable();
+ auto SandboxBypass = llvm::sys::sandbox::scopedDisable();
std::string TimestampFilename =
serialization::ModuleFile::getTimestampFilename(ModuleFilename);
llvm::sys::fs::file_status Status;
diff --git a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index 11e53a5132563..aae4f4161fad4 100644
--- a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
@@ -259,7 +259,7 @@ void HTMLDiagnostics::FlushDiagnosticsImpl(
void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
FilesMade *filesMade) {
// FIXME(sandboxing): Remove this by adopting `llvm::vfs::OutputBackend`.
- auto SandboxBypass = llvm::sys::sandbox_scoped_disable();
+ auto SandboxBypass = llvm::sys::sandbox::scopedDisable();
// Create the HTML directory if it is missing.
if (!createdDir) {
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index af30ba68dfde4..579b441e5cb9c 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -274,7 +274,7 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
/// Create the actual file system.
auto VFS = [] {
- auto BypassSandbox = llvm::sys::sandbox_scoped_disable();
+ auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
return llvm::vfs::getRealFileSystem();
}();
Clang->createVirtualFileSystem(std::move(VFS), DiagsBuffer);
@@ -309,7 +309,7 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
// results now. This happens in -disable-free mode.
{
// This isn't a formal input or output of the compiler.
- auto BypassSandbox = llvm::sys::sandbox_scoped_disable();
+ auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
std::unique_ptr<raw_ostream> IOFile = llvm::CreateInfoOutputFile();
if (Clang->getCodeGenOpts().TimePassesJson) {
*IOFile << "{\n";
diff --git a/clang/tools/driver/cc1as_main.cpp b/clang/tools/driver/cc1as_main.cpp
index 285a128add1e1..c2f45ee370fb3 100644
--- a/clang/tools/driver/cc1as_main.cpp
+++ b/clang/tools/driver/cc1as_main.cpp
@@ -428,7 +428,7 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer = [=] {
// FIXME(sandboxing): Make this a proper input file.
- auto BypassSandbox = sys::sandbox_scoped_disable();
+ auto BypassSandbox = sys::sandbox::scopedDisable();
return MemoryBuffer::getFileOrSTDIN(Opts.InputFile, /*IsText=*/true);
}();
@@ -677,7 +677,7 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
DiagnosticsEngine Diags(DiagnosticIDs::create(), DiagOpts, DiagClient);
auto VFS = [] {
- auto BypassSandbox = sys::sandbox_scoped_disable();
+ auto BypassSandbox = sys::sandbox::scopedDisable();
return vfs::getRealFileSystem();
}();
diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt
index c450ee5a3d72e..ac81506a02993 100644
--- a/llvm/CMakeLists.txt
+++ b/llvm/CMakeLists.txt
@@ -697,6 +697,7 @@ option(LLVM_ENABLE_WERROR "Fail and stop if a warning is triggered." OFF)
option(LLVM_ENABLE_DUMP "Enable dump functions even when assertions are disabled" OFF)
option(LLVM_UNREACHABLE_OPTIMIZE "Optimize llvm_unreachable() as undefined behavior (default), guaranteed trap when OFF" ON)
+option(LLVM_ENABLE_IO_SANDBOX "Enable IO sandboxing in supported tools" OFF)
if( NOT uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG" )
option(LLVM_ENABLE_ASSERTIONS "Enable assertions" OFF)
diff --git a/llvm/include/llvm/Support/IOSandbox.h b/llvm/include/llvm/Support/IOSandbox.h
index 1a8fb9788e3f6..cf6f4f2b857a0 100644
--- a/llvm/include/llvm/Support/IOSandbox.h
+++ b/llvm/include/llvm/Support/IOSandbox.h
@@ -9,12 +9,74 @@
#ifndef LLVM_SUPPORT_IOSANDBOX_H
#define LLVM_SUPPORT_IOSANDBOX_H
+// Always enable IO sandboxing in debug/assert builds for development,
+// but allow enablement even for release/no-assert builds for production.
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_IO_SANDBOX)
+
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/SaveAndRestore.h"
-namespace llvm::sys {
-SaveAndRestore<bool> sandbox_scoped_enable();
-SaveAndRestore<bool> sandbox_scoped_disable();
-void sandbox_violation_if_enabled();
-} // namespace llvm::sys
+namespace llvm::sys::sandbox {
+inline thread_local bool Enabled = false;
+inline SaveAndRestore<bool> scopedEnable() { return {Enabled, true}; }
+inline SaveAndRestore<bool> scopedDisable() { return {Enabled, false}; }
+inline void violationIfEnabled() {
+ if (Enabled)
+ reportFatalInternalError("IO sandbox violation");
+}
+} // namespace llvm::sys::sandbox
+
+#else
+
+namespace llvm::sys::sandbox {
+inline int scopedEnable() {}
+inline int scopedDisable() {}
+inline void violationIfEnabled() {}
+} // namespace llvm::sys::sandbox
+
+#endif
+
+namespace llvm::sys::sandbox {
+/// Facility for seamlessly interposing function calls and sandbox enforcement.
+/// This is intended for creating static functors like so:
+///
+/// // before
+/// #include <unistd.h>
+/// namespace x {
+/// void perform_read() { read(); } // not sandboxed
+/// }
+///
+/// // after
+/// #include <unistd.h>
+/// namespace x {
+/// static constexpr auto read = llvm::sys::sandbox::interpose(::read);
+/// void perform_read() { read(); } // sandboxed
+/// }
+template <class FnTy> struct Interposed;
+
+template <class RetTy, class... ArgTy> struct Interposed<RetTy (*)(ArgTy...)> {
+ RetTy (*Fn)(ArgTy...);
+
+ RetTy operator()(ArgTy... Arg) const {
+ violationIfEnabled();
+ return Fn(std::forward<ArgTy>(Arg)...);
+ }
+};
+
+template <class RetTy, class... ArgTy>
+struct Interposed<RetTy (*)(ArgTy..., ...)> {
+ RetTy (*Fn)(ArgTy..., ...);
+
+ template <class... CVarArgTy>
+ RetTy operator()(ArgTy... Arg, CVarArgTy... CVarArg) const {
+ violationIfEnabled();
+ return Fn(std::forward<ArgTy>(Arg)..., std::forward<CVarArgTy>(CVarArg)...);
+ }
+};
+
+template <class FnTy> constexpr auto interpose(FnTy Fn) {
+ return Interposed<FnTy>{Fn};
+}
+} // namespace llvm::sys::sandbox
#endif
diff --git a/llvm/lib/Support/IOSandbox.cpp b/llvm/lib/Support/IOSandbox.cpp
deleted file mode 100644
index a046d38b48fc3..0000000000000
--- a/llvm/lib/Support/IOSandbox.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-#include "llvm/Support/IOSandbox.h"
-
-#include <cassert>
-
-using namespace llvm;
-
-thread_local bool IOSandboxEnabled = false;
-
-SaveAndRestore<bool> sys::sandbox_scoped_enable() {
- return {IOSandboxEnabled, true};
-}
-
-SaveAndRestore<bool> sys::sandbox_scoped_disable() {
- return {IOSandboxEnabled, false};
-}
-
-void sys::sandbox_violation_if_enabled() {
- assert(!IOSandboxEnabled && "sandbox violation");
-}
diff --git a/llvm/lib/Support/IOSandboxInternal.h b/llvm/lib/Support/IOSandboxInternal.h
deleted file mode 100644
index 3e953c53c6e2a..0000000000000
--- a/llvm/lib/Support/IOSandboxInternal.h
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef LLVM_SUPPORT_IOSANDBOXINTERNAL_H
-#define LLVM_SUPPORT_IOSANDBOXINTERNAL_H
-
-#include "llvm/Support/IOSandbox.h"
-
-#include <stdio.h>
-#include <sys/stat.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_SYS_MMAN_H
-#include <sys/mman.h>
-#endif
-#include <dirent.h>
-
-extern thread_local bool IOSandboxEnabled;
-
-namespace llvm {
-namespace detail {
-template <class FnTy> struct Interposed;
-
-template <class RetTy, class... ArgTy> struct Interposed<RetTy (*)(ArgTy...)> {
- RetTy (*Fn)(ArgTy...);
-
- RetTy operator()(ArgTy... Arg) const {
- sys::sandbox_violation_if_enabled();
- return Fn(std::forward<ArgTy>(Arg)...);
- }
-};
-
-template <class RetTy, class... ArgTy>
-struct Interposed<RetTy (*)(ArgTy..., ...)> {
- RetTy (*Fn)(ArgTy..., ...);
-
- template <class... CVarArgTy>
- RetTy operator()(ArgTy... Arg, CVarArgTy... CVarArg) const {
- sys::sandbox_violation_if_enabled();
- return Fn(std::forward<ArgTy>(Arg)..., std::forward<CVarArgTy>(CVarArg)...);
- }
-};
-
-template <class FnTy> constexpr auto interpose(FnTy Fn) {
- return Interposed<FnTy>{Fn};
-}
-} // namespace detail
-
-static constexpr auto read = detail::interpose(::read);
-static constexpr auto pread = detail::interpose(::pread);
-static constexpr auto mmap = detail::interpose(::mmap);
-static constexpr auto readdir = detail::interpose(::readdir);
-static constexpr auto access = detail::interpose(::access);
-static constexpr auto stat = detail::interpose(::stat);
-static constexpr auto lstat = detail::interpose(::lstat);
-static constexpr auto fstat = detail::interpose(::fstat);
-static constexpr auto getcwd = detail::interpose(::getcwd);
-static constexpr auto realpath = detail::interpose(::realpath);
-static constexpr auto readlink = detail::interpose(::readlink);
-} // namespace llvm
-
-#endif
diff --git a/llvm/lib/Support/LockFileManager.cpp b/llvm/lib/Support/LockFileManager.cpp
index 54c42e4dd53e6..795bffbbc648c 100644
--- a/llvm/lib/Support/LockFileManager.cpp
+++ b/llvm/lib/Support/LockFileManager.cpp
@@ -52,7 +52,7 @@ using namespace llvm;
/// \returns The process ID of the process that owns this lock file
std::optional<LockFileManager::OwnedByAnother>
LockFileManager::readLockFile(StringRef LockFileName) {
- auto SandboxBypass = sys::sandbox_scoped_disable();
+ auto SandboxBypass = sys::sandbox::scopedDisable();
// Read the owning host and PID out of the lock file. If it appears that the
// owning process is dead, the lock file is invalid.
@@ -249,7 +249,7 @@ Expected<bool> LockFileManager::tryLock() {
}
LockFileManager::~LockFileManager() {
- auto SandboxBypass = sys::sandbox_scoped_disable();
+ auto SandboxBypass = sys::sandbox::scopedDisable();
if (!std::holds_alternative<OwnedByUs>(Owner))
return;
diff --git a/llvm/lib/Support/Signals.cpp b/llvm/lib/Support/Signals.cpp
index 076ec293750af..f160a135f623d 100644
--- a/llvm/lib/Support/Signals.cpp
+++ b/llvm/lib/Support/Signals.cpp
@@ -97,7 +97,7 @@ CallBacksToRun() {
// Signal-safe.
void sys::RunSignalHandlers() {
// Let's not interfere with stack trace symbolication and friends.
- auto BypassSandbox = sandbox_scoped_disable();
+ auto BypassSandbox = sandbox::scopedDisable();
for (CallbackAndCookie &RunMe : CallBacksToRun()) {
auto Expected = CallbackAndCookie::Status::Initialized;
diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc
index f51c847a5f457..ba99c07f3b463 100644
--- a/llvm/lib/Support/Unix/Path.inc
+++ b/llvm/lib/Support/Unix/Path.inc
@@ -114,7 +114,31 @@ typedef uint_t uint;
#define STATVFS_F_FLAG(vfs) (vfs).f_flags
#endif
-#include "IOSandboxInternal.h"
+#include <stdio.h>
+#include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+#include <dirent.h>
+
+#include "llvm/Support/IOSandbox.h"
+
+namespace llvm {
+static constexpr auto read = sys::sandbox::interpose(::read);
+static constexpr auto pread = sys::sandbox::interpose(::pread);
+static constexpr auto mmap = sys::sandbox::interpose(::mmap);
+static constexpr auto readdir = sys::sandbox::interpose(::readdir);
+static constexpr auto access = sys::sandbox::interpose(::access);
+static constexpr auto stat = sys::sandbox::interpose(::stat);
+static constexpr auto lstat = sys::sandbox::interpose(::lstat);
+static constexpr auto fstat = sys::sandbox::interpose(::fstat);
+static constexpr auto getcwd = sys::sandbox::interpose(::getcwd);
+static constexpr auto realpath = sys::sandbox::interpose(::realpath);
+static constexpr auto readlink = sys::sandbox::interpose(::readlink);
+} // namespace llvm
using namespace llvm;
diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp
index ecd50a8004f70..62fe07d3e4af0 100644
--- a/llvm/lib/Support/VirtualFileSystem.cpp
+++ b/llvm/lib/Support/VirtualFileSystem.cpp
@@ -222,7 +222,7 @@ RealFile::~RealFile() { close(); }
ErrorOr<Status> RealFile::status() {
assert(FD != kInvalidFile && "cannot stat closed file");
if (!S.isStatusKnown()) {
- auto BypassSandbox = sys::sandbox_scoped_disable();
+ auto BypassSandbox = sys::sandbox::scopedDisable();
file_status RealStatus;
if (std::error_code EC = sys::fs::status(FD, RealStatus))
return EC;
@@ -239,7 +239,7 @@ ErrorOr<std::unique_ptr<MemoryBuffer>>
RealFile::getBuffer(const Twine &Name, int64_t FileSize,
bool RequiresNullTerminator, bool IsVolatile) {
assert(FD != kInvalidFile && "cannot get buffer for closed file");
- auto BypassSandbox = sys::sandbox_scoped_disable();
+ auto BypassSandbox = sys::sandbox::scopedDisable();
return MemoryBuffer::getOpenFile(FD, Name, FileSize, RequiresNullTerminator,
IsVolatile);
}
@@ -309,7 +309,7 @@ class RealFileSystem : public FileSystem {
ErrorOr<std::unique_ptr<File>>
openFileForReadWithFlags(const Twine &Name, sys::fs::OpenFlags Flags) {
- auto BypassSandbox = sys::sandbox_scoped_disable();
+ auto BypassSandbox = sys::sandbox::scopedDisable();
SmallString<256> RealName, Storage;
Expected<file_t> FDOrErr = sys::fs::openNativeFileForRead(
adjustPath(Name, Storage), Flags, &RealName);
@@ -331,7 +331,7 @@ class RealFileSystem : public FileSystem {
} // namespace
ErrorOr<Status> RealFileSystem::status(const Twine &Path) {
- auto BypassSandbox = sys::sandbox_scoped_disable();
+ auto BypassSandbox = sys::sandbox::scopedDisable();
SmallString<256> Storage;
sys::fs::file_status RealStatus;
if (std::error_code EC =
@@ -356,7 +356,7 @@ llvm::ErrorOr<std::string> RealFileSystem::getCurrentWorkingDirectory() const {
if (WD)
return WD->getError();
- auto BypassSandbox = sys::sandbox_scoped_disable();
+ auto BypassSandbox = sys::sandbox::scopedDisable();
SmallString<128> Dir;
if (std::error_code EC = llvm::sys::fs::current_path(Dir))
return EC;
@@ -387,7 +387,7 @@ std::error_code RealFileSystem::isLocal(const Twine &Path, bool &Result) {
std::error_code RealFileSystem::getRealPath(const Twine &Path,
SmallVectorImpl<char> &Output) {
- auto BypassSandbox = sys::sandbox_scoped_disable();
+ auto BypassSandbox = sys::sandbox::scopedDisable();
SmallString<256> Storage;
return llvm::sys::fs::real_path(adjustPath(Path, Storage), Output);
}
@@ -406,12 +406,12 @@ void RealFileSystem::printImpl(raw_ostream &OS, PrintType Type,
IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() {
static IntrusiveRefCntPtr<FileSystem> FS =
makeIntrusiveRefCnt<RealFileSystem>(true);
- sys::sandbox_violation_if_enabled();
+ sys::sandbox::violationIfEnabled();
return FS;
}
std::unique_ptr<FileSystem> vfs::createPhysicalFileSystem() {
- sys::sandbox_violation_if_enabled();
+ sys::sandbox::violationIfEnabled();
return std::make_unique<RealFileSystem>(false);
}
@@ -422,14 +422,14 @@ class RealFSDirIter : public llvm::vfs::detail::DirIterImpl {
public:
RealFSDirIter(const Twine &Path, std::error_code &EC) {
- auto BypassSandbox = sys::sandbox_scoped_disable();
+ auto BypassSandbox = sys::sandbox::scopedDisable();
Iter = llvm::sys::fs::directory_iterator{Path, EC};
if (Iter != llvm::sys::fs::directory_iterator())
CurrentEntry = directory_entry(Iter->path(), Iter->type());
}
std::error_code increment() override {
- auto BypassSandbox = sys::sandbox_scoped_disable();
+ auto BypassSandbox = sys::sandbox::scopedDisable();
std::error_code EC;
Iter.increment(EC);
CurrentEntry = (Iter == llvm::sys::fs::directory_iterator())
diff --git a/llvm/lib/Support/VirtualOutputBackends.cpp b/llvm/lib/Support/VirtualOutputBackends.cpp
index 82ee6df891120..61b29b1955bca 100644
--- a/llvm/lib/Support/VirtualOutputBackends.cpp
+++ b/llvm/lib/Support/VirtualOutputBackends.cpp
@@ -554,7 +554,7 @@ Error OnDiskOutputFile::keep() {
}
Error OnDiskOutputFile::discard() {
- auto BypassSandbox = sys::sandbox_scoped_disable();
+ auto BypassSandbox = sys::sandbox::scopedDisable();
// Destroy the streams to flush them.
if (auto E = reset())
@@ -585,7 +585,7 @@ Error OnDiskOutputBackend::makeAbsolute(SmallVectorImpl<char> &Path) const {
Expected<std::unique_ptr<OutputFileImpl>>
OnDiskOutputBackend::createFileImpl(StringRef Path,
std::optional<OutputConfig> Config) {
- auto BypassSandbox = sys::sandbox_scoped_disable();
+ auto BypassSandbox = sys::sandbox::scopedDisable();
SmallString<256> AbsPath;
if (Path != "-") {
diff --git a/llvm/lib/Support/raw_ostream.cpp b/llvm/lib/Support/raw_ostream.cpp
index 0ea5f024c82c5..3b608706f6c55 100644
--- a/llvm/lib/Support/raw_ostream.cpp
+++ b/llvm/lib/Support/raw_ostream.cpp
@@ -619,7 +619,7 @@ raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered,
OStreamKind K)
: raw_pwrite_stream(unbuffered, K), FD(fd), ShouldClose(shouldClose) {
// FIXME(sandboxing): Remove this by adopting `llvm::vfs::OutputBackend`.
- auto BypassSandbox = sys::sandbox_scoped_disable();
+ auto BypassSandbox = sys::sandbox::scopedDisable();
if (FD < 0 ) {
ShouldClose = false;
>From 5ac2edd54f8b85635b52cede3404ed4021630846 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Mon, 6 Oct 2025 14:32:55 -0700
Subject: [PATCH 12/19] [[maybe_unused]], proper CMake flag setup
---
clang/lib/CodeGen/BackendUtil.cpp | 2 +-
clang/lib/Driver/Driver.cpp | 2 +-
clang/lib/Driver/Job.cpp | 2 +-
clang/lib/Serialization/GlobalModuleIndex.cpp | 4 ++--
clang/lib/Serialization/ModuleCache.cpp | 4 ++--
.../lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp | 2 +-
clang/tools/driver/cc1_main.cpp | 4 ++--
clang/tools/driver/cc1as_main.cpp | 4 ++--
llvm/include/llvm/Config/llvm-config.h.cmake | 3 +++
llvm/include/llvm/Support/IOSandbox.h | 4 ++--
llvm/lib/Support/LockFileManager.cpp | 4 ++--
llvm/lib/Support/Signals.cpp | 2 +-
llvm/lib/Support/VirtualFileSystem.cpp | 16 ++++++++--------
llvm/lib/Support/VirtualOutputBackends.cpp | 4 ++--
llvm/lib/Support/raw_ostream.cpp | 2 +-
15 files changed, 31 insertions(+), 28 deletions(-)
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 5a53e2a106b8b..4a57dedb0e800 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -1436,7 +1436,7 @@ void clang::emitBackendOutput(CompilerInstance &CI, CodeGenOptions &CGOpts,
std::unique_ptr<llvm::Module> EmptyModule;
if (!CGOpts.ThinLTOIndexFile.empty()) {
// FIXME(sandboxing): Figure out how to support distributed indexing.
- auto BypassSandbox = sys::sandbox::scopedDisable();
+ [[maybe_unused]] auto BypassSandbox = sys::sandbox::scopedDisable();
// If we are performing a ThinLTO importing compile, load the function index
// into memory and pass it into runThinLTOBackend, which will run the
// function importer and invoke LTO passes.
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 95a09cd3afe3f..ede5fb0e94423 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -1872,7 +1872,7 @@ bool Driver::getCrashDiagnosticFile(StringRef ReproCrashFilename,
assert(llvm::Triple(llvm::sys::getProcessTriple()).isOSDarwin() &&
"Only knows about .crash files on Darwin");
// This is not a formal output of the compiler, let's bypass the sandbox.
- auto BypassSandbox = sandbox::scopedDisable();
+ [[maybe_unused]] auto BypassSandbox = sandbox::scopedDisable();
// The .crash file can be found on at ~/Library/Logs/DiagnosticReports/
// (or /Library/Logs/DiagnosticReports for root) and has the filename pattern
diff --git a/clang/lib/Driver/Job.cpp b/clang/lib/Driver/Job.cpp
index da7a1f2e07e90..e52d1069b4209 100644
--- a/clang/lib/Driver/Job.cpp
+++ b/clang/lib/Driver/Job.cpp
@@ -429,7 +429,7 @@ int CC1Command::Execute(ArrayRef<std::optional<StringRef>> Redirects,
// Enabling the sandbox here allows us to restore its previous state even when
// this cc1 invocation crashes.
- auto EnableSandbox = llvm::sys::sandbox::scopedEnable();
+ [[maybe_unused]] auto EnableSandbox = llvm::sys::sandbox::scopedEnable();
llvm::CrashRecoveryContext CRC;
CRC.DumpStackAndCleanupOnFailure = true;
diff --git a/clang/lib/Serialization/GlobalModuleIndex.cpp b/clang/lib/Serialization/GlobalModuleIndex.cpp
index 2246a3ac0a57e..297f5645b1645 100644
--- a/clang/lib/Serialization/GlobalModuleIndex.cpp
+++ b/clang/lib/Serialization/GlobalModuleIndex.cpp
@@ -252,7 +252,7 @@ GlobalModuleIndex::~GlobalModuleIndex() {
std::pair<GlobalModuleIndex *, llvm::Error>
GlobalModuleIndex::readIndex(StringRef Path) {
// This is a compiler-internal input/output, let's bypass the sandbox.
- auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
+ [[maybe_unused]] auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
// Load the index file, if it's there.
llvm::SmallString<128> IndexPath;
@@ -848,7 +848,7 @@ GlobalModuleIndex::writeIndex(FileManager &FileMgr,
const PCHContainerReader &PCHContainerRdr,
StringRef Path) {
// This is a compiler-internal input/output, let's bypass the sandbox.
- auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
+ [[maybe_unused]] auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
llvm::SmallString<128> IndexPath;
IndexPath += Path;
diff --git a/clang/lib/Serialization/ModuleCache.cpp b/clang/lib/Serialization/ModuleCache.cpp
index 1a521920e9dd6..1ae4d6fdc6247 100644
--- a/clang/lib/Serialization/ModuleCache.cpp
+++ b/clang/lib/Serialization/ModuleCache.cpp
@@ -29,7 +29,7 @@ void clang::maybePruneImpl(StringRef Path, time_t PruneInterval,
return;
// This is a compiler-internal input/output, let's bypass the sandbox.
- auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
+ [[maybe_unused]] auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
llvm::SmallString<128> TimestampFile(Path);
llvm::sys::path::append(TimestampFile, "modules.timestamp");
@@ -120,7 +120,7 @@ class CrossProcessModuleCache : public ModuleCache {
std::time_t getModuleTimestamp(StringRef ModuleFilename) override {
// This is a compiler-internal input/output, let's bypass the sandbox.
- auto SandboxBypass = llvm::sys::sandbox::scopedDisable();
+ [[maybe_unused]] auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
std::string TimestampFilename =
serialization::ModuleFile::getTimestampFilename(ModuleFilename);
llvm::sys::fs::file_status Status;
diff --git a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index aae4f4161fad4..b201b644359e9 100644
--- a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
@@ -259,7 +259,7 @@ void HTMLDiagnostics::FlushDiagnosticsImpl(
void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
FilesMade *filesMade) {
// FIXME(sandboxing): Remove this by adopting `llvm::vfs::OutputBackend`.
- auto SandboxBypass = llvm::sys::sandbox::scopedDisable();
+ [[maybe_unused]] auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
// Create the HTML directory if it is missing.
if (!createdDir) {
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index 579b441e5cb9c..7da2f95eb5fdc 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -274,7 +274,7 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
/// Create the actual file system.
auto VFS = [] {
- auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
+ [[maybe_unused]] auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
return llvm::vfs::getRealFileSystem();
}();
Clang->createVirtualFileSystem(std::move(VFS), DiagsBuffer);
@@ -309,7 +309,7 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
// results now. This happens in -disable-free mode.
{
// This isn't a formal input or output of the compiler.
- auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
+ [[maybe_unused]] auto BypassSandbox = llvm::sys::sandbox::scopedDisable();
std::unique_ptr<raw_ostream> IOFile = llvm::CreateInfoOutputFile();
if (Clang->getCodeGenOpts().TimePassesJson) {
*IOFile << "{\n";
diff --git a/clang/tools/driver/cc1as_main.cpp b/clang/tools/driver/cc1as_main.cpp
index c2f45ee370fb3..eed2bb59f32bf 100644
--- a/clang/tools/driver/cc1as_main.cpp
+++ b/clang/tools/driver/cc1as_main.cpp
@@ -428,7 +428,7 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer = [=] {
// FIXME(sandboxing): Make this a proper input file.
- auto BypassSandbox = sys::sandbox::scopedDisable();
+ [[maybe_unused]] auto BypassSandbox = sys::sandbox::scopedDisable();
return MemoryBuffer::getFileOrSTDIN(Opts.InputFile, /*IsText=*/true);
}();
@@ -677,7 +677,7 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
DiagnosticsEngine Diags(DiagnosticIDs::create(), DiagOpts, DiagClient);
auto VFS = [] {
- auto BypassSandbox = sys::sandbox::scopedDisable();
+ [[maybe_unused]] auto BypassSandbox = sys::sandbox::scopedDisable();
return vfs::getRealFileSystem();
}();
diff --git a/llvm/include/llvm/Config/llvm-config.h.cmake b/llvm/include/llvm/Config/llvm-config.h.cmake
index 6488d6c01b5c6..9ac0115ee2184 100644
--- a/llvm/include/llvm/Config/llvm-config.h.cmake
+++ b/llvm/include/llvm/Config/llvm-config.h.cmake
@@ -126,6 +126,9 @@
* in non assert builds */
#cmakedefine01 LLVM_UNREACHABLE_OPTIMIZE
+/* Define if building LLVM with LLVM_ENABLE_IO_SANDBOX */
+#cmakedefine01 LLVM_ENABLE_IO_SANDBOX
+
/* Define to 1 if you have the DIA SDK installed, and to 0 if you don't. */
#cmakedefine01 LLVM_ENABLE_DIA_SDK
diff --git a/llvm/include/llvm/Support/IOSandbox.h b/llvm/include/llvm/Support/IOSandbox.h
index cf6f4f2b857a0..db0e134c48e5f 100644
--- a/llvm/include/llvm/Support/IOSandbox.h
+++ b/llvm/include/llvm/Support/IOSandbox.h
@@ -29,8 +29,8 @@ inline void violationIfEnabled() {
#else
namespace llvm::sys::sandbox {
-inline int scopedEnable() {}
-inline int scopedDisable() {}
+inline int scopedEnable() { return 0; }
+inline int scopedDisable() { return 0; }
inline void violationIfEnabled() {}
} // namespace llvm::sys::sandbox
diff --git a/llvm/lib/Support/LockFileManager.cpp b/llvm/lib/Support/LockFileManager.cpp
index 795bffbbc648c..586f4c98ae32c 100644
--- a/llvm/lib/Support/LockFileManager.cpp
+++ b/llvm/lib/Support/LockFileManager.cpp
@@ -52,7 +52,7 @@ using namespace llvm;
/// \returns The process ID of the process that owns this lock file
std::optional<LockFileManager::OwnedByAnother>
LockFileManager::readLockFile(StringRef LockFileName) {
- auto SandboxBypass = sys::sandbox::scopedDisable();
+ [[maybe_unused]] auto BypassSandbox = sys::sandbox::scopedDisable();
// Read the owning host and PID out of the lock file. If it appears that the
// owning process is dead, the lock file is invalid.
@@ -249,7 +249,7 @@ Expected<bool> LockFileManager::tryLock() {
}
LockFileManager::~LockFileManager() {
- auto SandboxBypass = sys::sandbox::scopedDisable();
+ [[maybe_unused]] auto BypassSandbox = sys::sandbox::scopedDisable();
if (!std::holds_alternative<OwnedByUs>(Owner))
return;
diff --git a/llvm/lib/Support/Signals.cpp b/llvm/lib/Support/Signals.cpp
index f160a135f623d..786c4576f13e3 100644
--- a/llvm/lib/Support/Signals.cpp
+++ b/llvm/lib/Support/Signals.cpp
@@ -97,7 +97,7 @@ CallBacksToRun() {
// Signal-safe.
void sys::RunSignalHandlers() {
// Let's not interfere with stack trace symbolication and friends.
- auto BypassSandbox = sandbox::scopedDisable();
+ [[maybe_unused]] auto BypassSandbox = sandbox::scopedDisable();
for (CallbackAndCookie &RunMe : CallBacksToRun()) {
auto Expected = CallbackAndCookie::Status::Initialized;
diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp
index 62fe07d3e4af0..0683cf8b3bd1f 100644
--- a/llvm/lib/Support/VirtualFileSystem.cpp
+++ b/llvm/lib/Support/VirtualFileSystem.cpp
@@ -222,7 +222,7 @@ RealFile::~RealFile() { close(); }
ErrorOr<Status> RealFile::status() {
assert(FD != kInvalidFile && "cannot stat closed file");
if (!S.isStatusKnown()) {
- auto BypassSandbox = sys::sandbox::scopedDisable();
+ [[maybe_unused]] auto BypassSandbox = sys::sandbox::scopedDisable();
file_status RealStatus;
if (std::error_code EC = sys::fs::status(FD, RealStatus))
return EC;
@@ -239,7 +239,7 @@ ErrorOr<std::unique_ptr<MemoryBuffer>>
RealFile::getBuffer(const Twine &Name, int64_t FileSize,
bool RequiresNullTerminator, bool IsVolatile) {
assert(FD != kInvalidFile && "cannot get buffer for closed file");
- auto BypassSandbox = sys::sandbox::scopedDisable();
+ [[maybe_unused]] auto BypassSandbox = sys::sandbox::scopedDisable();
return MemoryBuffer::getOpenFile(FD, Name, FileSize, RequiresNullTerminator,
IsVolatile);
}
@@ -309,7 +309,7 @@ class RealFileSystem : public FileSystem {
ErrorOr<std::unique_ptr<File>>
openFileForReadWithFlags(const Twine &Name, sys::fs::OpenFlags Flags) {
- auto BypassSandbox = sys::sandbox::scopedDisable();
+ [[maybe_unused]] auto BypassSandbox = sys::sandbox::scopedDisable();
SmallString<256> RealName, Storage;
Expected<file_t> FDOrErr = sys::fs::openNativeFileForRead(
adjustPath(Name, Storage), Flags, &RealName);
@@ -331,7 +331,7 @@ class RealFileSystem : public FileSystem {
} // namespace
ErrorOr<Status> RealFileSystem::status(const Twine &Path) {
- auto BypassSandbox = sys::sandbox::scopedDisable();
+ [[maybe_unused]] auto BypassSandbox = sys::sandbox::scopedDisable();
SmallString<256> Storage;
sys::fs::file_status RealStatus;
if (std::error_code EC =
@@ -356,7 +356,7 @@ llvm::ErrorOr<std::string> RealFileSystem::getCurrentWorkingDirectory() const {
if (WD)
return WD->getError();
- auto BypassSandbox = sys::sandbox::scopedDisable();
+ [[maybe_unused]] auto BypassSandbox = sys::sandbox::scopedDisable();
SmallString<128> Dir;
if (std::error_code EC = llvm::sys::fs::current_path(Dir))
return EC;
@@ -387,7 +387,7 @@ std::error_code RealFileSystem::isLocal(const Twine &Path, bool &Result) {
std::error_code RealFileSystem::getRealPath(const Twine &Path,
SmallVectorImpl<char> &Output) {
- auto BypassSandbox = sys::sandbox::scopedDisable();
+ [[maybe_unused]] auto BypassSandbox = sys::sandbox::scopedDisable();
SmallString<256> Storage;
return llvm::sys::fs::real_path(adjustPath(Path, Storage), Output);
}
@@ -422,14 +422,14 @@ class RealFSDirIter : public llvm::vfs::detail::DirIterImpl {
public:
RealFSDirIter(const Twine &Path, std::error_code &EC) {
- auto BypassSandbox = sys::sandbox::scopedDisable();
+ [[maybe_unused]] auto BypassSandbox = sys::sandbox::scopedDisable();
Iter = llvm::sys::fs::directory_iterator{Path, EC};
if (Iter != llvm::sys::fs::directory_iterator())
CurrentEntry = directory_entry(Iter->path(), Iter->type());
}
std::error_code increment() override {
- auto BypassSandbox = sys::sandbox::scopedDisable();
+ [[maybe_unused]] auto BypassSandbox = sys::sandbox::scopedDisable();
std::error_code EC;
Iter.increment(EC);
CurrentEntry = (Iter == llvm::sys::fs::directory_iterator())
diff --git a/llvm/lib/Support/VirtualOutputBackends.cpp b/llvm/lib/Support/VirtualOutputBackends.cpp
index 61b29b1955bca..90b4c3173b28d 100644
--- a/llvm/lib/Support/VirtualOutputBackends.cpp
+++ b/llvm/lib/Support/VirtualOutputBackends.cpp
@@ -554,7 +554,7 @@ Error OnDiskOutputFile::keep() {
}
Error OnDiskOutputFile::discard() {
- auto BypassSandbox = sys::sandbox::scopedDisable();
+ [[maybe_unused]] auto BypassSandbox = sys::sandbox::scopedDisable();
// Destroy the streams to flush them.
if (auto E = reset())
@@ -585,7 +585,7 @@ Error OnDiskOutputBackend::makeAbsolute(SmallVectorImpl<char> &Path) const {
Expected<std::unique_ptr<OutputFileImpl>>
OnDiskOutputBackend::createFileImpl(StringRef Path,
std::optional<OutputConfig> Config) {
- auto BypassSandbox = sys::sandbox::scopedDisable();
+ [[maybe_unused]] auto BypassSandbox = sys::sandbox::scopedDisable();
SmallString<256> AbsPath;
if (Path != "-") {
diff --git a/llvm/lib/Support/raw_ostream.cpp b/llvm/lib/Support/raw_ostream.cpp
index 3b608706f6c55..99ac3e1d75b47 100644
--- a/llvm/lib/Support/raw_ostream.cpp
+++ b/llvm/lib/Support/raw_ostream.cpp
@@ -619,7 +619,7 @@ raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered,
OStreamKind K)
: raw_pwrite_stream(unbuffered, K), FD(fd), ShouldClose(shouldClose) {
// FIXME(sandboxing): Remove this by adopting `llvm::vfs::OutputBackend`.
- auto BypassSandbox = sys::sandbox::scopedDisable();
+ [[maybe_unused]] auto BypassSandbox = sys::sandbox::scopedDisable();
if (FD < 0 ) {
ShouldClose = false;
>From 0792e518f2f53a44e1d0c5b22f439756c5031f9f Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Mon, 6 Oct 2025 14:48:46 -0700
Subject: [PATCH 13/19] noexcept
---
llvm/include/llvm/Support/IOSandbox.h | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/llvm/include/llvm/Support/IOSandbox.h b/llvm/include/llvm/Support/IOSandbox.h
index db0e134c48e5f..400767f711d58 100644
--- a/llvm/include/llvm/Support/IOSandbox.h
+++ b/llvm/include/llvm/Support/IOSandbox.h
@@ -54,21 +54,22 @@ namespace llvm::sys::sandbox {
/// }
template <class FnTy> struct Interposed;
-template <class RetTy, class... ArgTy> struct Interposed<RetTy (*)(ArgTy...)> {
+template <class RetTy, class... ArgTy, bool NE>
+struct Interposed<RetTy (*)(ArgTy...) noexcept(NE)> {
RetTy (*Fn)(ArgTy...);
- RetTy operator()(ArgTy... Arg) const {
+ RetTy operator()(ArgTy... Arg) const noexcept(NE) {
violationIfEnabled();
return Fn(std::forward<ArgTy>(Arg)...);
}
};
-template <class RetTy, class... ArgTy>
-struct Interposed<RetTy (*)(ArgTy..., ...)> {
+template <class RetTy, class... ArgTy, bool NE>
+struct Interposed<RetTy (*)(ArgTy..., ...) noexcept(NE)> {
RetTy (*Fn)(ArgTy..., ...);
template <class... CVarArgTy>
- RetTy operator()(ArgTy... Arg, CVarArgTy... CVarArg) const {
+ RetTy operator()(ArgTy... Arg, CVarArgTy... CVarArg) const noexcept(NE) {
violationIfEnabled();
return Fn(std::forward<ArgTy>(Arg)..., std::forward<CVarArgTy>(CVarArg)...);
}
>From f5fb3fddd31b8bbf9b72b9d4314cf6e68218e4b4 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Mon, 6 Oct 2025 15:27:55 -0700
Subject: [PATCH 14/19] MSVC noexcept(X) workaround
---
llvm/include/llvm/Support/IOSandbox.h | 32 ++++++++++++++++++++++-----
1 file changed, 26 insertions(+), 6 deletions(-)
diff --git a/llvm/include/llvm/Support/IOSandbox.h b/llvm/include/llvm/Support/IOSandbox.h
index 400767f711d58..e5267fe2b5c39 100644
--- a/llvm/include/llvm/Support/IOSandbox.h
+++ b/llvm/include/llvm/Support/IOSandbox.h
@@ -54,22 +54,42 @@ namespace llvm::sys::sandbox {
/// }
template <class FnTy> struct Interposed;
-template <class RetTy, class... ArgTy, bool NE>
-struct Interposed<RetTy (*)(ArgTy...) noexcept(NE)> {
+template <class RetTy, class... ArgTy> struct Interposed<RetTy (*)(ArgTy...)> {
RetTy (*Fn)(ArgTy...);
- RetTy operator()(ArgTy... Arg) const noexcept(NE) {
+ RetTy operator()(ArgTy... Arg) const {
violationIfEnabled();
return Fn(std::forward<ArgTy>(Arg)...);
}
};
-template <class RetTy, class... ArgTy, bool NE>
-struct Interposed<RetTy (*)(ArgTy..., ...) noexcept(NE)> {
+template <class RetTy, class... ArgTy>
+struct Interposed<RetTy (*)(ArgTy...) noexcept> {
+ RetTy (*Fn)(ArgTy...) noexcept;
+
+ RetTy operator()(ArgTy... Arg) const noexcept {
+ violationIfEnabled();
+ return Fn(std::forward<ArgTy>(Arg)...);
+ }
+};
+
+template <class RetTy, class... ArgTy>
+struct Interposed<RetTy (*)(ArgTy..., ...)> {
RetTy (*Fn)(ArgTy..., ...);
template <class... CVarArgTy>
- RetTy operator()(ArgTy... Arg, CVarArgTy... CVarArg) const noexcept(NE) {
+ RetTy operator()(ArgTy... Arg, CVarArgTy... CVarArg) const {
+ violationIfEnabled();
+ return Fn(std::forward<ArgTy>(Arg)..., std::forward<CVarArgTy>(CVarArg)...);
+ }
+};
+
+template <class RetTy, class... ArgTy>
+struct Interposed<RetTy (*)(ArgTy..., ...) noexcept> {
+ RetTy (*Fn)(ArgTy..., ...) noexcept;
+
+ template <class... CVarArgTy>
+ RetTy operator()(ArgTy... Arg, CVarArgTy... CVarArg) const noexcept {
violationIfEnabled();
return Fn(std::forward<ArgTy>(Arg)..., std::forward<CVarArgTy>(CVarArg)...);
}
>From 5d6acd9e20e1205cc93dc2a5d6f015e00c6e0387 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Tue, 7 Oct 2025 12:16:47 -0700
Subject: [PATCH 15/19] Initial version of a clang-tidy check
---
.../clang-tidy/llvm/CMakeLists.txt | 1 +
.../clang-tidy/llvm/IOSandboxCheck.cpp | 319 ++++++++++++++++++
.../clang-tidy/llvm/IOSandboxCheck.h | 31 ++
.../clang-tidy/llvm/LLVMTidyModule.cpp | 2 +
4 files changed, 353 insertions(+)
create mode 100644 clang-tools-extra/clang-tidy/llvm/IOSandboxCheck.cpp
create mode 100644 clang-tools-extra/clang-tidy/llvm/IOSandboxCheck.h
diff --git a/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt b/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt
index 78ef0444305ff..73c8dc4f17696 100644
--- a/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt
@@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS
add_clang_library(clangTidyLLVMModule STATIC
HeaderGuardCheck.cpp
IncludeOrderCheck.cpp
+ IOSandboxCheck.cpp
LLVMTidyModule.cpp
PreferIsaOrDynCastInConditionalsCheck.cpp
PreferRegisterOverUnsignedCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/llvm/IOSandboxCheck.cpp b/clang-tools-extra/clang-tidy/llvm/IOSandboxCheck.cpp
new file mode 100644
index 0000000000000..92247524ee548
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/llvm/IOSandboxCheck.cpp
@@ -0,0 +1,319 @@
+//===--- FilesystemAccessCheck.cpp - clang-tidy --------------------------===//
+//
+// Enforces controlled filesystem access patterns
+//
+//===----------------------------------------------------------------------===//
+
+#include "IOSandboxCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::llvm_check {
+// Low-level filesystem functions that should only be called from llvm::sys::fs
+static const llvm::StringSet<> &getForbiddenFilesystemFunctions() {
+ static const llvm::StringSet<> Functions = {
+ // POSIX file operations
+ "open",
+ "openat",
+ "creat",
+ "close",
+ "read",
+ "write",
+ "pread",
+ "pwrite",
+ "lseek",
+ "ftruncate",
+ "truncate",
+ "stat",
+ "fstat",
+ "lstat",
+ "fstatat",
+ "access",
+ "faccessat",
+ "chmod",
+ "fchmod",
+ "fchmodat",
+ "chown",
+ "fchown",
+ "lchown",
+ "fchownat",
+ "link",
+ "linkat",
+ "symlink",
+ "symlinkat",
+ "readlink",
+ "readlinkat",
+ "unlink",
+ "unlinkat",
+ "remove",
+ "rename",
+ "renameat",
+ "mkdir",
+ "mkdirat",
+ "rmdir",
+ "opendir",
+ "readdir",
+ "closedir",
+ "fdopendir",
+ "chdir",
+ "fchdir",
+ "getcwd",
+ "dup",
+ "dup2",
+ "dup3",
+ "fcntl",
+ "pipe",
+ "pipe2",
+ "mkfifo",
+ "mkfifoat",
+ "mknod",
+ "mknodat",
+ "utimes",
+ "futimes",
+ "utimensat",
+ "futimens",
+
+ // C standard library file operations
+ "fopen",
+ "freopen",
+ "fclose",
+ "fflush",
+ "fread",
+ "fwrite",
+ "fgetc",
+ "fputc",
+ "fgets",
+ "fputs",
+ "fseek",
+ "ftell",
+ "rewind",
+ "fgetpos",
+ "fsetpos",
+ "tmpfile",
+ "tmpnam",
+ "tempnam",
+
+ // Windows file operations
+ "CreateFileA",
+ "CreateFileW",
+ "CreateFile",
+ "ReadFile",
+ "WriteFile",
+ "CloseHandle",
+ "DeleteFileA",
+ "DeleteFileW",
+ "DeleteFile",
+ "MoveFileA",
+ "MoveFileW",
+ "MoveFile",
+ "CopyFileA",
+ "CopyFileW",
+ "CopyFile",
+ "GetFileAttributesA",
+ "GetFileAttributesW",
+ "GetFileAttributes",
+ "SetFileAttributesA",
+ "SetFileAttributesW",
+ "SetFileAttributes",
+ "CreateDirectoryA",
+ "CreateDirectoryW",
+ "CreateDirectory",
+ "RemoveDirectoryA",
+ "RemoveDirectoryW",
+ "RemoveDirectory",
+ "FindFirstFileA",
+ "FindFirstFileW",
+ "FindFirstFile",
+ "FindNextFileA",
+ "FindNextFileW",
+ "FindNextFile",
+ "FindClose",
+ "GetCurrentDirectoryA",
+ "GetCurrentDirectoryW",
+ "SetCurrentDirectoryA",
+ "SetCurrentDirectoryW",
+
+ // Memory-mapped files
+ "mmap",
+ "munmap",
+ "mprotect",
+ "msync",
+ "MapViewOfFile",
+ "UnmapViewOfFile",
+ };
+ return Functions;
+}
+
+static bool isInLLVMSysFsNamespace(const FunctionDecl *FD) {
+ if (!FD)
+ return false;
+
+ auto IsAnonymousNamespace = [](const DeclContext *DC) {
+ if (!DC)
+ return false;
+ const auto *ND = dyn_cast<NamespaceDecl>(DC);
+ if (!ND)
+ return false;
+ return ND->isAnonymousNamespace();
+ };
+
+ auto GetNamedNamespace = [](const DeclContext *DC) -> const NamespaceDecl * {
+ if (!DC)
+ return nullptr;
+ const auto *ND = dyn_cast<NamespaceDecl>(DC);
+ if (!ND)
+ return nullptr;
+ if (ND->isAnonymousNamespace())
+ return nullptr;
+ return ND;
+ };
+
+ const DeclContext *DC = FD->getDeclContext();
+
+ // Walk up the context chain looking for llvm::sys::fs
+ SmallVector<StringRef> ReverseNamespaces;
+ while (IsAnonymousNamespace(DC))
+ DC = DC->getParent();
+ while (const auto *ND = GetNamedNamespace(DC)) {
+ ReverseNamespaces.push_back(ND->getName());
+ DC = DC->getParent();
+ }
+ auto Namespaces = llvm::reverse(ReverseNamespaces);
+
+ return llvm::equal(Namespaces, SmallVector<StringRef>{"llvm", "sys", "fs"});
+}
+
+static bool isLLVMSysFsCall(const CallExpr *CE) {
+ if (!CE)
+ return false;
+
+ const FunctionDecl *Callee = CE->getDirectCallee();
+ if (!Callee)
+ return false;
+
+ return isInLLVMSysFsNamespace(Callee) && !Callee->isOverloadedOperator();
+}
+
+static bool isForbiddenFilesystemCall(const CallExpr *CE) {
+ if (!CE)
+ return false;
+
+ const FunctionDecl *Callee = CE->getDirectCallee();
+ if (!Callee)
+ return false;
+
+ const auto &ForbiddenFuncs = getForbiddenFilesystemFunctions();
+
+ return ForbiddenFuncs.contains(Callee->getQualifiedNameAsString());
+}
+
+static bool hasSandboxBypass(const FunctionDecl *FD, SourceLocation CallLoc) {
+ if (!FD || !FD->hasBody())
+ return false;
+
+ const Stmt *Body = FD->getBody();
+ if (!Body)
+ return false;
+
+ // Look for variable declarations of the bypass type
+ // We need to check if the bypass variable is declared before the call site
+ class BypassFinder : public RecursiveASTVisitor<BypassFinder> {
+ public:
+ bool FoundBypass = false;
+ SourceLocation CallLocation;
+ const SourceManager *SM;
+
+ bool VisitVarDecl(VarDecl *VD) {
+ if (!VD)
+ return true;
+
+ // Check if this is a sandbox bypass variable
+ const Type *T = VD->getType().getTypePtrOrNull();
+ if (!T)
+ return true;
+
+ const CXXRecordDecl *RD = T->getAsCXXRecordDecl();
+ if (!RD)
+ return true;
+
+ // Check for ScopedSandboxDisable or similar RAII types
+ std::string TypeName = RD->getQualifiedNameAsString();
+ if (TypeName.find("ScopedSandboxDisable") != std::string::npos ||
+ TypeName.find("scopedDisable") != std::string::npos) {
+
+ // Check if this declaration comes before the call
+ if (SM &&
+ SM->isBeforeInTranslationUnit(VD->getLocation(), CallLocation)) {
+ FoundBypass = true;
+ return false; // Stop searching
+ }
+ }
+
+ return true;
+ }
+ };
+
+ BypassFinder Finder;
+ Finder.CallLocation = CallLoc;
+ Finder.SM = &FD->getASTContext().getSourceManager();
+ Finder.TraverseStmt(const_cast<Stmt *>(Body));
+
+ return Finder.FoundBypass;
+}
+
+void IOSandboxCheck::registerMatchers(MatchFinder *Finder) {
+ // Match any call expression within a function.
+ Finder->addMatcher(
+ callExpr(hasAncestor(functionDecl().bind("parent_func"))).bind("call"),
+ this);
+
+ // Also match variable declarations to find sandbox bypass objects
+ Finder->addMatcher(
+ varDecl(hasType(cxxRecordDecl(hasName("ScopedSandboxDisable"))),
+ hasAncestor(functionDecl().bind("func_with_bypass")))
+ .bind("bypass_var"),
+ this);
+}
+
+void IOSandboxCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
+ const auto *ParentFunc = Result.Nodes.getNodeAs<FunctionDecl>("parent_func");
+
+ if (!Call || !ParentFunc)
+ return;
+
+ // Skip system headers and template instantiations
+ if (Call->getBeginLoc().isInvalid() ||
+ Result.Context->getSourceManager().isInSystemHeader(
+ Call->getBeginLoc()) ||
+ ParentFunc->isTemplateInstantiation())
+ return;
+
+ // Rule 1: Check if calling llvm::sys::fs without sandbox bypass
+ if (isLLVMSysFsCall(Call)) {
+ if (!hasSandboxBypass(ParentFunc, Call->getBeginLoc())) {
+ diag(Call->getBeginLoc(), "call to llvm::sys::fs function")
+ << Call->getSourceRange();
+ }
+ return; // Don't check rule 2 for llvm::sys::fs calls
+ }
+
+ // Rule 2: Check if calling forbidden filesystem functions outside
+ // llvm::sys::fs
+ if (isForbiddenFilesystemCall(Call)) {
+ if (!isInLLVMSysFsNamespace(ParentFunc)) {
+ const auto *Callee = Call->getDirectCallee();
+ std::string CalleeName = Callee ? Callee->getNameAsString() : "unknown";
+
+ diag(Call->getBeginLoc(),
+ "low-level filesystem function '%0' may only be called from a "
+ "llvm::sys::fs function")
+ << CalleeName << Call->getSourceRange();
+ }
+ }
+}
+} // namespace clang::tidy::llvm_check
diff --git a/clang-tools-extra/clang-tidy/llvm/IOSandboxCheck.h b/clang-tools-extra/clang-tidy/llvm/IOSandboxCheck.h
new file mode 100644
index 0000000000000..99886989bdae7
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/llvm/IOSandboxCheck.h
@@ -0,0 +1,31 @@
+//===--- LLVMFilesystemAccessCheck.h - clang-tidy ---------------*- C++ -*-===//
+//
+// Enforces controlled filesystem access patterns
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_IOSANDBOXCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_IOSANDBOXCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::llvm_check {
+
+/// Enforces two rules for filesystem access:
+/// 1. Functions calling llvm::sys::fs must have a sandbox bypass RAII object
+/// 2. Only llvm::sys::fs functions may call low-level filesystem functions
+///
+/// For the user-facing documentation see:
+/// https://clang.llvm.org/extra/clang-tidy/checks/llvm/io-sandbox.html
+class IOSandboxCheck : public ClangTidyCheck {
+public:
+ IOSandboxCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace clang::tidy::llvm_check
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_IOSANDBOXCHECK_H
diff --git a/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp b/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp
index ed65cd1720457..be32495746035 100644
--- a/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp
@@ -13,6 +13,7 @@
#include "../readability/NamespaceCommentCheck.h"
#include "../readability/QualifiedAutoCheck.h"
#include "HeaderGuardCheck.h"
+#include "IOSandboxCheck.h"
#include "IncludeOrderCheck.h"
#include "PreferIsaOrDynCastInConditionalsCheck.h"
#include "PreferRegisterOverUnsignedCheck.h"
@@ -31,6 +32,7 @@ class LLVMModule : public ClangTidyModule {
"llvm-else-after-return");
CheckFactories.registerCheck<LLVMHeaderGuardCheck>("llvm-header-guard");
CheckFactories.registerCheck<IncludeOrderCheck>("llvm-include-order");
+ CheckFactories.registerCheck<IOSandboxCheck>("llvm-io-sandbox");
CheckFactories.registerCheck<readability::NamespaceCommentCheck>(
"llvm-namespace-comment");
CheckFactories.registerCheck<PreferIsaOrDynCastInConditionalsCheck>(
>From 26abceea738edd6abea4e061463711c0aa6b40dd Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Wed, 15 Oct 2025 16:22:44 -0700
Subject: [PATCH 16/19] AsmPrinter + BTFDebug
---
llvm/include/llvm/CodeGen/AsmPrinter.h | 3 ---
llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 1 -
llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp | 9 +++++++--
llvm/lib/Target/BPF/BTFDebug.cpp | 10 ++++++++--
4 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index 9ace2555b4b62..0c73eddca3526 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -110,9 +110,6 @@ class LLVM_ABI AsmPrinter : public MachineFunctionPass {
/// generating (such as the current section etc).
std::unique_ptr<MCStreamer> OutStreamer;
- /// The VFS to resolve asm include directives.
- IntrusiveRefCntPtr<vfs::FileSystem> VFS;
-
/// The current machine function.
MachineFunction *MF = nullptr;
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index e2af0c5925248..06262f9ce3147 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -477,7 +477,6 @@ void AsmPrinter::getAnalysisUsage(AnalysisUsage &AU) const {
}
bool AsmPrinter::doInitialization(Module &M) {
- VFS = vfs::getRealFileSystem();
auto *MMIWP = getAnalysisIfAvailable<MachineModuleInfoWrapperPass>();
MMI = MMIWP ? &MMIWP->getMMI() : nullptr;
HasSplitStack = false;
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp
index 8dd8b9da9c50c..6b0fd456391e2 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp
@@ -98,8 +98,13 @@ void AsmPrinter::emitInlineAsm(StringRef Str, const MCSubtargetInfo &STI,
unsigned BufNum = addInlineAsmDiagBuffer(Str, LocMDNode);
SourceMgr &SrcMgr = *MMI->getContext().getInlineSourceManager();
- SrcMgr.setIncludeDirs(MCOptions.IASSearchPaths);
- SrcMgr.setVirtualFileSystem(VFS);
+ // FIXME(sandboxing): This is not executed in tests, but might be common.
+ // Propagating vfs::FileSystem here is lots of work,
+ // consider bypassing the sandbox.
+ if (!MCOptions.IASSearchPaths.empty()) {
+ SrcMgr.setIncludeDirs(MCOptions.IASSearchPaths);
+ SrcMgr.setVirtualFileSystem(vfs::getRealFileSystem());
+ }
std::unique_ptr<MCAsmParser> Parser(
createMCAsmParser(SrcMgr, OutContext, *OutStreamer, *MAI, BufNum));
diff --git a/llvm/lib/Target/BPF/BTFDebug.cpp b/llvm/lib/Target/BPF/BTFDebug.cpp
index ba4b48990c647..f0c82427ad057 100644
--- a/llvm/lib/Target/BPF/BTFDebug.cpp
+++ b/llvm/lib/Target/BPF/BTFDebug.cpp
@@ -23,6 +23,7 @@
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCStreamer.h"
+#include "llvm/Support/IOSandbox.h"
#include "llvm/Support/LineIterator.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
@@ -1017,12 +1018,17 @@ std::string BTFDebug::populateFileContent(const DIFile *File) {
std::string Line;
Content.push_back(Line); // Line 0 for empty string
+ auto LoadFile = [](StringRef FileName) {
+ // FIXME(sandboxing): Propagating vfs::FileSystem here is lots of work.
+ [[maybe_unused]] auto BypassSandbox = sys::sandbox::scopedDisable();
+ return MemoryBuffer::getFile(FileName);
+ };
+
std::unique_ptr<MemoryBuffer> Buf;
auto Source = File->getSource();
if (Source)
Buf = MemoryBuffer::getMemBufferCopy(*Source);
- else if (ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
- MemoryBuffer::getFile(FileName))
+ else if (ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = LoadFile(FileName))
Buf = std::move(*BufOrErr);
if (Buf)
for (line_iterator I(*Buf, false), E; I != E; ++I)
>From 64820bde80cce25ea26ba868d81a4a68c1890b63 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Wed, 15 Oct 2025 19:45:05 -0700
Subject: [PATCH 17/19] Proper sandbox
---
llvm/include/llvm/CodeGen/AsmPrinter.h | 5 -----
.../lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp | 14 +++++++-------
2 files changed, 7 insertions(+), 12 deletions(-)
diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index 0c73eddca3526..19ca44429af4d 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -16,7 +16,6 @@
#define LLVM_CODEGEN_ASMPRINTER_H
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
@@ -88,10 +87,6 @@ namespace remarks {
class RemarkStreamer;
}
-namespace vfs {
-class FileSystem;
-}
-
/// This class is intended to be used as a driving class for all asm writers.
class LLVM_ABI AsmPrinter : public MachineFunctionPass {
public:
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp
index 6b0fd456391e2..8c2467037b4cb 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterInlineAsm.cpp
@@ -34,6 +34,7 @@
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/IOSandbox.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/VirtualFileSystem.h"
@@ -98,13 +99,12 @@ void AsmPrinter::emitInlineAsm(StringRef Str, const MCSubtargetInfo &STI,
unsigned BufNum = addInlineAsmDiagBuffer(Str, LocMDNode);
SourceMgr &SrcMgr = *MMI->getContext().getInlineSourceManager();
- // FIXME(sandboxing): This is not executed in tests, but might be common.
- // Propagating vfs::FileSystem here is lots of work,
- // consider bypassing the sandbox.
- if (!MCOptions.IASSearchPaths.empty()) {
- SrcMgr.setIncludeDirs(MCOptions.IASSearchPaths);
- SrcMgr.setVirtualFileSystem(vfs::getRealFileSystem());
- }
+ SrcMgr.setIncludeDirs(MCOptions.IASSearchPaths);
+ SrcMgr.setVirtualFileSystem([] {
+ // FIXME(sandboxing): Propagating vfs::FileSystem here is lots of work.
+ [[maybe_unused]] auto BypassSandbox = sys::sandbox::scopedDisable();
+ return vfs::getRealFileSystem();
+ }());
std::unique_ptr<MCAsmParser> Parser(
createMCAsmParser(SrcMgr, OutContext, *OutStreamer, *MAI, BufNum));
>From 36094dcae296318a11d69f4e8f5877c24f539449 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Thu, 16 Oct 2025 09:11:58 -0700
Subject: [PATCH 18/19] Sanitizers
---
clang/lib/CodeGen/BackendUtil.cpp | 7 ++++---
.../llvm/Transforms/Instrumentation/SanitizerCoverage.h | 7 +++----
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 4a57dedb0e800..9985a0141f65f 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -716,9 +716,10 @@ static void addSanitizers(const Triple &TargetTriple,
ThinOrFullLTOPhase) {
if (CodeGenOpts.hasSanitizeCoverage()) {
auto SancovOpts = getSancovOptsFromCGOpts(CodeGenOpts);
- MPM.addPass(SanitizerCoveragePass(
- SancovOpts, CodeGenOpts.SanitizeCoverageAllowlistFiles,
- CodeGenOpts.SanitizeCoverageIgnorelistFiles));
+ MPM.addPass(
+ SanitizerCoveragePass(SancovOpts, PB.getVirtualFileSystemPtr(),
+ CodeGenOpts.SanitizeCoverageAllowlistFiles,
+ CodeGenOpts.SanitizeCoverageIgnorelistFiles));
}
if (CodeGenOpts.hasSanitizeBinaryMetadata()) {
diff --git a/llvm/include/llvm/Transforms/Instrumentation/SanitizerCoverage.h b/llvm/include/llvm/Transforms/Instrumentation/SanitizerCoverage.h
index f14f5b90a5cc9..f2676d1234222 100644
--- a/llvm/include/llvm/Transforms/Instrumentation/SanitizerCoverage.h
+++ b/llvm/include/llvm/Transforms/Instrumentation/SanitizerCoverage.h
@@ -32,17 +32,16 @@ class SanitizerCoveragePass : public PassInfoMixin<SanitizerCoveragePass> {
public:
explicit SanitizerCoveragePass(
SanitizerCoverageOptions Options = SanitizerCoverageOptions(),
+ IntrusiveRefCntPtr<vfs::FileSystem> VFS = vfs::getRealFileSystem(),
const std::vector<std::string> &AllowlistFiles =
std::vector<std::string>(),
const std::vector<std::string> &BlocklistFiles =
std::vector<std::string>())
: Options(Options) {
if (AllowlistFiles.size() > 0)
- Allowlist = SpecialCaseList::createOrDie(AllowlistFiles,
- *vfs::getRealFileSystem());
+ Allowlist = SpecialCaseList::createOrDie(AllowlistFiles, *VFS);
if (BlocklistFiles.size() > 0)
- Blocklist = SpecialCaseList::createOrDie(BlocklistFiles,
- *vfs::getRealFileSystem());
+ Blocklist = SpecialCaseList::createOrDie(BlocklistFiles, *VFS);
}
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
static bool isRequired() { return true; }
>From 4702b7e42108dbbfb1eee095607ea5fc27e973f5 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Thu, 16 Oct 2025 10:55:29 -0700
Subject: [PATCH 19/19] LockFileManager
---
llvm/lib/Support/LockFileManager.cpp | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/llvm/lib/Support/LockFileManager.cpp b/llvm/lib/Support/LockFileManager.cpp
index 586f4c98ae32c..215f2f1d2699d 100644
--- a/llvm/lib/Support/LockFileManager.cpp
+++ b/llvm/lib/Support/LockFileManager.cpp
@@ -167,6 +167,8 @@ Expected<bool> LockFileManager::tryLock() {
assert(std::holds_alternative<OwnerUnknown>(Owner) &&
"lock has already been attempted");
+ [[maybe_unused]] auto BypassSandbox = sys::sandbox::scopedDisable();
+
SmallString<128> AbsoluteFileName(FileName);
if (std::error_code EC = sys::fs::make_absolute(AbsoluteFileName))
return createStringError(EC, "failed to obtain absolute path for " +
@@ -264,6 +266,8 @@ LockFileManager::~LockFileManager() {
WaitForUnlockResult
LockFileManager::waitForUnlockFor(std::chrono::seconds MaxSeconds) {
+ [[maybe_unused]] auto BypassSandbox = sys::sandbox::scopedDisable();
+
auto *LockFileOwner = std::get_if<OwnedByAnother>(&Owner);
assert(LockFileOwner &&
"waiting for lock to be unlocked without knowing the owner");
@@ -293,5 +297,7 @@ LockFileManager::waitForUnlockFor(std::chrono::seconds MaxSeconds) {
}
std::error_code LockFileManager::unsafeMaybeUnlock() {
+ [[maybe_unused]] auto BypassSandbox = sys::sandbox::scopedDisable();
+
return sys::fs::remove(LockFileName);
}
More information about the cfe-commits
mailing list