diff --git a/doc/manual/conf-file.xml b/doc/manual/conf-file.xml index c37a2da474..c832108fed 100644 --- a/doc/manual/conf-file.xml +++ b/doc/manual/conf-file.xml @@ -148,6 +148,7 @@ flag, e.g. --option gc-keep-outputs false. + build-timeout @@ -168,6 +169,20 @@ flag, e.g. --option gc-keep-outputs false. + build-max-log-size + + + + This option defines the maximum number of bytes that a + builder can write to its stdout/stderr. If the builder exceeds + this limit, it’s killed. A value of 0 (the + default) means that there is no limit. + + + + + + build-users-group This options specifies the Unix group containing diff --git a/src/libstore/build.cc b/src/libstore/build.cc index b5d064e8c6..25bf848ca6 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -813,6 +813,9 @@ private: BZFILE * bzLogFile; AutoCloseFD fdLogFile; + /* Number of bytes received from the builder's stdout/stderr. */ + unsigned long logSize; + /* Pipe for the builder's standard output/error. */ Pipe builderOut; @@ -2403,6 +2406,8 @@ string drvsLogDir = "drvs"; Path DerivationGoal::openLogFile() { + logSize = 0; + if (!settings.keepLog) return ""; string baseName = baseNameOf(drvPath); @@ -2478,6 +2483,14 @@ void DerivationGoal::handleChildOutput(int fd, const string & data) if ((hook && fd == hook->builderOut.readSide) || (!hook && fd == builderOut.readSide)) { + logSize += data.size(); + if (settings.maxLogSize && logSize > settings.maxLogSize) { + printMsg(lvlError, + format("%1% killed after writing more than %2% bytes of log output") + % getName() % settings.maxLogSize); + cancel(true); // not really a timeout, but close enough + return; + } if (verbosity >= settings.buildVerbosity) writeToStderr(data); if (bzLogFile) { diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc index d17bd947d3..aeb52e1a86 100644 --- a/src/libstore/globals.cc +++ b/src/libstore/globals.cc @@ -46,6 +46,7 @@ Settings::Settings() impersonateLinux26 = false; keepLog = true; compressLog = true; + maxLogSize = 0; cacheFailure = false; pollInterval = 5; checkRootReachability = false; @@ -140,6 +141,7 @@ void Settings::update() get(impersonateLinux26, "build-impersonate-linux-26"); get(keepLog, "build-keep-log"); get(compressLog, "build-compress-log"); + get(maxLogSize, "build-max-log-size"); get(cacheFailure, "build-cache-failure"); get(pollInterval, "build-poll-interval"); get(checkRootReachability, "gc-check-reachability"); diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh index f129d9a11e..50b61725c7 100644 --- a/src/libstore/globals.hh +++ b/src/libstore/globals.hh @@ -153,6 +153,10 @@ struct Settings { /* Whether to compress logs. */ bool compressLog; + /* Maximum number of bytes a builder can write to stdout/stderr + before being killed (0 means no limit). */ + unsigned long maxLogSize; + /* Whether to cache build failures. */ bool cacheFailure;