Merge pull request #9737 from obsidiansystems/sys-error-split

Separate `SystemError` from `SysError`
This commit is contained in:
John Ericson 2024-01-12 12:41:36 -05:00 committed by GitHub
commit c58da62a06
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 59 additions and 27 deletions

View file

@ -254,7 +254,7 @@ void NixRepl::mainLoop()
rl_readline_name = "nix-repl"; rl_readline_name = "nix-repl";
try { try {
createDirs(dirOf(historyFile)); createDirs(dirOf(historyFile));
} catch (SysError & e) { } catch (SystemError & e) {
logWarning(e.info()); logWarning(e.info());
} }
#ifndef USE_READLINE #ifndef USE_READLINE

View file

@ -1495,7 +1495,7 @@ void LocalDerivationGoal::startDaemon()
daemon::processConnection(store, from, to, daemon::processConnection(store, from, to,
NotTrusted, daemon::Recursive); NotTrusted, daemon::Recursive);
debug("terminated daemon connection"); debug("terminated daemon connection");
} catch (SysError &) { } catch (SystemError &) {
ignoreException(); ignoreException();
} }
}); });
@ -1707,7 +1707,7 @@ void LocalDerivationGoal::runChild()
try { try {
if (drv->isBuiltin() && drv->builder == "builtin:fetchurl") if (drv->isBuiltin() && drv->builder == "builtin:fetchurl")
netrcData = readFile(settings.netrcFile); netrcData = readFile(settings.netrcFile);
} catch (SysError &) { } } catch (SystemError &) { }
#if __linux__ #if __linux__
if (useChroot) { if (useChroot) {

View file

@ -413,7 +413,7 @@ void LocalStore::findRuntimeRoots(Roots & roots, bool censor)
auto env_end = std::sregex_iterator{}; auto env_end = std::sregex_iterator{};
for (auto i = std::sregex_iterator{envString.begin(), envString.end(), storePathRegex}; i != env_end; ++i) for (auto i = std::sregex_iterator{envString.begin(), envString.end(), storePathRegex}; i != env_end; ++i)
unchecked[i->str()].emplace(envFile); unchecked[i->str()].emplace(envFile);
} catch (SysError & e) { } catch (SystemError & e) {
if (errno == ENOENT || errno == EACCES || errno == ESRCH) if (errno == ENOENT || errno == EACCES || errno == ESRCH)
continue; continue;
throw; throw;

View file

@ -118,7 +118,7 @@ void loadConfFile()
try { try {
std::string contents = readFile(path); std::string contents = readFile(path);
globalConfig.applyConfig(contents, path); globalConfig.applyConfig(contents, path);
} catch (SysError &) { } } catch (SystemError &) { }
}; };
applyConfigFile(settings.nixConfDir + "/nix.conf"); applyConfigFile(settings.nixConfDir + "/nix.conf");

View file

@ -19,7 +19,7 @@ PublicKeys getDefaultPublicKeys()
try { try {
SecretKey secretKey(readFile(secretKeyFile)); SecretKey secretKey(readFile(secretKeyFile));
publicKeys.emplace(secretKey.name, secretKey.toPublicKey()); publicKeys.emplace(secretKey.name, secretKey.toPublicKey());
} catch (SysError & e) { } catch (SystemError & e) {
/* Ignore unreadable key files. That's normal in a /* Ignore unreadable key files. That's normal in a
multi-user installation. */ multi-user installation. */
} }

View file

@ -276,7 +276,7 @@ LocalStore::LocalStore(const Params & params)
[[gnu::unused]] auto res2 = ftruncate(fd.get(), settings.reservedSize); [[gnu::unused]] auto res2 = ftruncate(fd.get(), settings.reservedSize);
} }
} }
} catch (SysError & e) { /* don't care about errors */ } catch (SystemError & e) { /* don't care about errors */
} }
/* Acquire the big fat lock in shared mode to make sure that no /* Acquire the big fat lock in shared mode to make sure that no

View file

@ -242,7 +242,7 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
/* Atomically replace the old file with the new hard link. */ /* Atomically replace the old file with the new hard link. */
try { try {
renameFile(tempLink, path); renameFile(tempLink, path);
} catch (SysError & e) { } catch (SystemError & e) {
if (unlink(tempLink.c_str()) == -1) if (unlink(tempLink.c_str()) == -1)
printError("unable to unlink '%1%'", tempLink); printError("unable to unlink '%1%'", tempLink);
if (errno == EMLINK) { if (errno == EMLINK) {

View file

@ -87,13 +87,13 @@ std::pair<ref<SourceAccessor>, CanonPath> RemoteFSAccessor::fetch(const CanonPat
nars.emplace(storePath.hashPart(), narAccessor); nars.emplace(storePath.hashPart(), narAccessor);
return {narAccessor, restPath}; return {narAccessor, restPath};
} catch (SysError &) { } } catch (SystemError &) { }
try { try {
auto narAccessor = makeNarAccessor(nix::readFile(cacheFile)); auto narAccessor = makeNarAccessor(nix::readFile(cacheFile));
nars.emplace(storePath.hashPart(), narAccessor); nars.emplace(storePath.hashPart(), narAccessor);
return {narAccessor, restPath}; return {narAccessor, restPath};
} catch (SysError &) { } } catch (SystemError &) { }
} }
StringSink sink; StringSink sink;

View file

@ -304,7 +304,7 @@ void RootArgs::parseCmdline(const Strings & _cmdline, bool allowShebang)
for (auto pos = savedArgs.begin(); pos != savedArgs.end();pos++) for (auto pos = savedArgs.begin(); pos != savedArgs.end();pos++)
cmdline.push_back(*pos); cmdline.push_back(*pos);
} }
} catch (SysError &) { } } catch (SystemError &) { }
} }
for (auto pos = cmdline.begin(); pos != cmdline.end(); ) { for (auto pos = cmdline.begin(); pos != cmdline.end(); ) {

View file

@ -95,7 +95,7 @@ static CgroupStats destroyCgroup(const Path & cgroup, bool returnStats)
using namespace std::string_literals; using namespace std::string_literals;
warn("killing stray builder process %d (%s)...", warn("killing stray builder process %d (%s)...",
pid, trim(replaceStrings(cmdline, "\0"s, " "))); pid, trim(replaceStrings(cmdline, "\0"s, " ")));
} catch (SysError &) { } catch (SystemError &) {
} }
} }
// FIXME: pid wraparound // FIXME: pid wraparound

View file

@ -124,7 +124,7 @@ static void applyConfigInner(const std::string & contents, const std::string & p
try { try {
std::string includedContents = readFile(path); std::string includedContents = readFile(path);
applyConfigInner(includedContents, p, parsedContents); applyConfigInner(includedContents, p, parsedContents);
} catch (SysError &) { } catch (SystemError &) {
// TODO: Do we actually want to ignore this? Or is it better to fail? // TODO: Do we actually want to ignore this? Or is it better to fail?
} }
} else if (!ignoreMissing) { } else if (!ignoreMissing) {

View file

@ -178,20 +178,50 @@ MakeError(Error, BaseError);
MakeError(UsageError, Error); MakeError(UsageError, Error);
MakeError(UnimplementedError, Error); MakeError(UnimplementedError, Error);
class SysError : public Error /**
* To use in catch-blocks.
*/
MakeError(SystemError, Error);
/**
* POSIX system error, created using `errno`, `strerror` friends.
*
* Throw this, but prefer not to catch this, and catch `SystemError`
* instead. This allows implementations to freely switch between this
* and `WinError` without breaking catch blocks.
*
* However, it is permissible to catch this and rethrow so long as
* certain conditions are not met (e.g. to catch only if `errNo =
* EFooBar`). In that case, try to also catch the equivalent `WinError`
* code.
*
* @todo Rename this to `PosixError` or similar. At this point Windows
* support is too WIP to justify the code churn, but if it is finished
* then a better identifier becomes moe worth it.
*/
class SysError : public SystemError
{ {
public: public:
int errNo; int errNo;
/**
* Construct using the explicitly-provided error number. `strerror`
* will be used to try to add additional information to the message.
*/
template<typename... Args> template<typename... Args>
SysError(int errNo_, const Args & ... args) SysError(int errNo, const Args & ... args)
: Error("") : SystemError(""), errNo(errNo)
{ {
errNo = errNo_;
auto hf = hintfmt(args...); auto hf = hintfmt(args...);
err.msg = hintfmt("%1%: %2%", normaltxt(hf.str()), strerror(errNo)); err.msg = hintfmt("%1%: %2%", normaltxt(hf.str()), strerror(errNo));
} }
/**
* Construct using the ambient `errno`.
*
* Be sure to not perform another `errno`-modifying operation before
* calling this constructor!
*/
template<typename... Args> template<typename... Args>
SysError(const Args & ... args) SysError(const Args & ... args)
: SysError(errno, args ...) : SysError(errno, args ...)
@ -199,7 +229,9 @@ public:
} }
}; };
/** Throw an exception for the purpose of checking that exception handling works; see 'initLibUtil()'. /**
* Throw an exception for the purpose of checking that exception
* handling works; see 'initLibUtil()'.
*/ */
void throwExceptionSelfCheck(); void throwExceptionSelfCheck();

View file

@ -231,7 +231,7 @@ void closeMostFDs(const std::set<int> & exceptions)
} }
} }
return; return;
} catch (SysError &) { } catch (SystemError &) {
} }
#endif #endif

View file

@ -116,7 +116,7 @@ void writeToStderr(std::string_view s)
{ {
try { try {
writeFull(STDERR_FILENO, s, false); writeFull(STDERR_FILENO, s, false);
} catch (SysError & e) { } catch (SystemError & e) {
/* Ignore failing writes to stderr. We need to ignore write /* Ignore failing writes to stderr. We need to ignore write
errors to ensure that cleanup code that logs to stderr runs errors to ensure that cleanup code that logs to stderr runs
to completion if the other side of stderr has been closed to completion if the other side of stderr has been closed

View file

@ -53,7 +53,7 @@ void FdSink::writeUnbuffered(std::string_view data)
written += data.size(); written += data.size();
try { try {
writeFull(fd, data); writeFull(fd, data);
} catch (SysError & e) { } catch (SystemError & e) {
_good = false; _good = false;
throw; throw;
} }

View file

@ -20,7 +20,7 @@ void initLibUtil() {
// When exception handling fails, the message tends to be printed by the // When exception handling fails, the message tends to be printed by the
// C++ runtime, followed by an abort. // C++ runtime, followed by an abort.
// For example on macOS we might see an error such as // For example on macOS we might see an error such as
// libc++abi: terminating with uncaught exception of type nix::SysError: error: C++ exception handling is broken. This would appear to be a problem with the way Nix was compiled and/or linked and/or loaded. // libc++abi: terminating with uncaught exception of type nix::SystemError: error: C++ exception handling is broken. This would appear to be a problem with the way Nix was compiled and/or linked and/or loaded.
bool caught = false; bool caught = false;
try { try {
throwExceptionSelfCheck(); throwExceptionSelfCheck();

View file

@ -148,7 +148,7 @@ static void main_nix_build(int argc, char * * argv)
args.push_back(word); args.push_back(word);
} }
} }
} catch (SysError &) { } } catch (SystemError &) { }
} }
struct MyArgs : LegacyArgs, MixEvalArgs struct MyArgs : LegacyArgs, MixEvalArgs

View file

@ -107,7 +107,7 @@ struct CmdConfigCheck : StoreCommand
if (profileDir.find("/profiles/") == std::string::npos) if (profileDir.find("/profiles/") == std::string::npos)
dirs.insert(dir); dirs.insert(dir);
} }
} catch (SysError &) {} } catch (SystemError &) {}
} }
if (!dirs.empty()) { if (!dirs.empty()) {

View file

@ -73,7 +73,7 @@ namespace nix {
} }
TEST(logEI, picksUpSysErrorExitCode) { TEST(logEI, picksUpSystemErrorExitCode) {
MakeError(TestError, Error); MakeError(TestError, Error);
ErrorInfo::programName = std::optional("error-unit-test"); ErrorInfo::programName = std::optional("error-unit-test");
@ -81,12 +81,12 @@ namespace nix {
try { try {
auto x = readFile(-1); auto x = readFile(-1);
} }
catch (SysError &e) { catch (SystemError &e) {
testing::internal::CaptureStderr(); testing::internal::CaptureStderr();
logError(e.info()); logError(e.info());
auto str = testing::internal::GetCapturedStderr(); auto str = testing::internal::GetCapturedStderr();
ASSERT_STREQ(str.c_str(), "\x1B[31;1merror:\x1B[0m\x1B[34;1m --- SysError --- error-unit-test\x1B[0m\nstatting file: \x1B[33;1mBad file descriptor\x1B[0m\n"); ASSERT_STREQ(str.c_str(), "\x1B[31;1merror:\x1B[0m\x1B[34;1m --- SystemError --- error-unit-test\x1B[0m\nstatting file: \x1B[33;1mBad file descriptor\x1B[0m\n");
} }
} }