about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--doc/manual/command-ref/nix-channel.xml8
-rw-r--r--misc/launchd/org.nixos.nix-daemon.plist.in2
-rw-r--r--release.nix2
-rw-r--r--src/build-remote/build-remote.cc2
-rw-r--r--src/buildenv/buildenv.cc4
-rw-r--r--src/libexpr/eval.cc2
-rw-r--r--src/libexpr/nixexpr.hh22
-rw-r--r--src/libexpr/primops.cc19
-rw-r--r--src/libexpr/primops/fetchGit.cc4
-rw-r--r--src/libstore/build.cc4
-rw-r--r--src/libstore/gc.cc2
-rw-r--r--src/libstore/local-store.cc2
-rw-r--r--src/libstore/optimise-store.cc2
-rw-r--r--src/libstore/remote-store.hh3
-rw-r--r--src/libstore/ssh-store.cc10
-rw-r--r--src/libutil/logging.cc8
-rw-r--r--src/libutil/logging.hh3
-rw-r--r--src/libutil/lru-cache.hh8
-rw-r--r--src/libutil/serialise.cc3
-rw-r--r--src/libutil/util.cc7
-rw-r--r--src/libutil/util.hh3
-rw-r--r--src/nix-store/nix-store.cc2
-rw-r--r--src/nix/dump-path.cc1
-rw-r--r--src/nix/run.cc4
-rw-r--r--src/nix/search.cc12
-rw-r--r--tests/export.sh5
-rw-r--r--tests/lang/eval-okay-replacestrings.exp2
-rw-r--r--tests/lang/eval-okay-replacestrings.nix3
-rw-r--r--tests/nar-access.sh6
29 files changed, 106 insertions, 49 deletions
diff --git a/doc/manual/command-ref/nix-channel.xml b/doc/manual/command-ref/nix-channel.xml
index 9acf44e52984..ff4021a765e0 100644
--- a/doc/manual/command-ref/nix-channel.xml
+++ b/doc/manual/command-ref/nix-channel.xml
@@ -31,7 +31,7 @@
 
 <refsection><title>Description</title>
 
-<para>A Nix channel is mechanism that allows you to automatically stay
+<para>A Nix channel is a mechanism that allows you to automatically stay
 up-to-date with a set of pre-built Nix expressions.  A Nix channel is
 just a URL that points to a place containing both a set of Nix
 expressions and a pointer to a binary cache.  <phrase
@@ -165,8 +165,8 @@ following files:</para>
   <varlistentry><term><filename>nixexprs.tar.xz</filename></term>
 
     <listitem><para>A tarball containing Nix expressions and files
-    referenced by them (such as build scripts and patches). At
-    top-level, the tarball should contain a single directory. That
+    referenced by them (such as build scripts and patches). At the
+    top level, the tarball should contain a single directory. That
     directory must contain a file <filename>default.nix</filename>
     that serves as the channel’s “entry point”.</para></listitem>
 
@@ -175,7 +175,7 @@ following files:</para>
   <varlistentry><term><filename>binary-cache-url</filename></term>
 
     <listitem><para>A file containing the URL to a binary cache (such
-    as <uri>https://cache.nixos.org</uri>. Nix will automatically
+    as <uri>https://cache.nixos.org</uri>). Nix will automatically
     check this cache for pre-built binaries, if the user has
     sufficient rights to add binary caches. For instance, in a
     multi-user Nix setup, the binary caches provided by the channels
diff --git a/misc/launchd/org.nixos.nix-daemon.plist.in b/misc/launchd/org.nixos.nix-daemon.plist.in
index 66fcd155ee9b..549619a57d56 100644
--- a/misc/launchd/org.nixos.nix-daemon.plist.in
+++ b/misc/launchd/org.nixos.nix-daemon.plist.in
@@ -4,6 +4,8 @@
   <dict>
     <key>Label</key>
     <string>org.nixos.nix-daemon</string>
+    <key>KeepAlive</key>
+    <true/>
     <key>RunAtLoad</key>
     <true/>
     <key>Program</key>
diff --git a/release.nix b/release.nix
index 3f8d5da4721e..0bbd966fabd7 100644
--- a/release.nix
+++ b/release.nix
@@ -1,5 +1,5 @@
 { nix ? builtins.fetchGit ./.
-, nixpkgs ? builtins.fetchGit { url = https://github.com/NixOS/nixpkgs.git; ref = "nix-2.0"; }
+, nixpkgs ? builtins.fetchGit https://github.com/NixOS/nixpkgs.git
 , officialRelease ? false
 , systems ? [ "x86_64-linux" "i686-linux" "x86_64-darwin" "aarch64-linux" ]
 }:
diff --git a/src/build-remote/build-remote.cc b/src/build-remote/build-remote.cc
index dbf8fe1b8f8a..6b294a4d2c2c 100644
--- a/src/build-remote/build-remote.cc
+++ b/src/build-remote/build-remote.cc
@@ -244,7 +244,7 @@ connected:
         if (!missing.empty()) {
             Activity act(*logger, lvlTalkative, actUnknown, fmt("copying outputs from '%s'", storeUri));
             store->locksHeld.insert(missing.begin(), missing.end()); /* FIXME: ugly */
-            copyPaths(ref<Store>(sshStore), store, missing, NoRepair, NoCheckSigs, substitute);
+            copyPaths(ref<Store>(sshStore), store, missing, NoRepair, NoCheckSigs, NoSubstitute);
         }
 
         return;
diff --git a/src/buildenv/buildenv.cc b/src/buildenv/buildenv.cc
index eddb9fdaa8d2..2afad913ac6b 100644
--- a/src/buildenv/buildenv.cc
+++ b/src/buildenv/buildenv.cc
@@ -74,10 +74,10 @@ static void createLinks(const Path & srcDir, const Path & dstDir, int priority)
                     auto prevPriority = priorities[dstFile];
                     if (prevPriority == priority)
                         throw Error(format(
-                                "Packages '%1%' and '%2%' have the same priority '%3%'"
+                                "packages '%1%' and '%2%' have the same priority %3%; "
                                 "use 'nix-env --set-flag priority NUMBER INSTALLED_PKGNAME' "
                                 "to change the priority of one of the conflicting packages"
-                                " ('0' being the highest priority)"
+                                " (0 being the highest priority)"
                                 ) % srcFile % target % priority);
                     if (prevPriority < priority)
                         continue;
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 63afccbec188..f94c23ea72bb 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -313,7 +313,7 @@ EvalState::EvalState(const Strings & _searchPath, ref<Store> store)
         for (auto & i : _searchPath) addToSearchPath(i);
         for (auto & i : paths) addToSearchPath(i);
     }
-    addToSearchPath("nix=" + canonPath(settings.nixDataDir + "/nix/corepkgs"));
+    addToSearchPath("nix=" + canonPath(settings.nixDataDir + "/nix/corepkgs", true));
 
     if (settings.restrictEval || settings.pureEval) {
         allowedPaths = PathSet();
diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh
index 30be79bb57a6..eb9fac25c010 100644
--- a/src/libexpr/nixexpr.hh
+++ b/src/libexpr/nixexpr.hh
@@ -283,12 +283,12 @@ struct ExprOpNot : Expr
 };
 
 #define MakeBinOp(name, s) \
-    struct Expr##name : Expr \
+    struct name : Expr \
     { \
         Pos pos; \
         Expr * e1, * e2; \
-        Expr##name(Expr * e1, Expr * e2) : e1(e1), e2(e2) { }; \
-        Expr##name(const Pos & pos, Expr * e1, Expr * e2) : pos(pos), e1(e1), e2(e2) { }; \
+        name(Expr * e1, Expr * e2) : e1(e1), e2(e2) { }; \
+        name(const Pos & pos, Expr * e1, Expr * e2) : pos(pos), e1(e1), e2(e2) { }; \
         void show(std::ostream & str) \
         { \
             str << "(" << *e1 << " " s " " << *e2 << ")";   \
@@ -300,14 +300,14 @@ struct ExprOpNot : Expr
         void eval(EvalState & state, Env & env, Value & v); \
     };
 
-MakeBinOp(App, "")
-MakeBinOp(OpEq, "==")
-MakeBinOp(OpNEq, "!=")
-MakeBinOp(OpAnd, "&&")
-MakeBinOp(OpOr, "||")
-MakeBinOp(OpImpl, "->")
-MakeBinOp(OpUpdate, "//")
-MakeBinOp(OpConcatLists, "++")
+MakeBinOp(ExprApp, "")
+MakeBinOp(ExprOpEq, "==")
+MakeBinOp(ExprOpNEq, "!=")
+MakeBinOp(ExprOpAnd, "&&")
+MakeBinOp(ExprOpOr, "||")
+MakeBinOp(ExprOpImpl, "->")
+MakeBinOp(ExprOpUpdate, "//")
+MakeBinOp(ExprOpConcatLists, "++")
 
 struct ExprConcatStrings : Expr
 {
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index a800d24290ae..6778023f506d 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -1913,21 +1913,32 @@ static void prim_replaceStrings(EvalState & state, const Pos & pos, Value * * ar
     auto s = state.forceString(*args[2], context, pos);
 
     string res;
-    for (size_t p = 0; p < s.size(); ) {
+    // Loops one past last character to handle the case where 'from' contains an empty string.
+    for (size_t p = 0; p <= s.size(); ) {
         bool found = false;
         auto i = from.begin();
         auto j = to.begin();
         for (; i != from.end(); ++i, ++j)
             if (s.compare(p, i->size(), *i) == 0) {
                 found = true;
-                p += i->size();
                 res += j->first;
+                if (i->empty()) {
+                    if (p < s.size())
+                        res += s[p];
+                    p++;
+                } else {
+                    p += i->size();
+                }
                 for (auto& path : j->second)
                     context.insert(path);
                 j->second.clear();
                 break;
             }
-        if (!found) res += s[p++];
+        if (!found) {
+            if (p < s.size())
+                res += s[p];
+            p++;
+        }
     }
 
     mkString(v, res, context);
@@ -2225,7 +2236,7 @@ void EvalState::createBaseEnv()
 
     /* Add a wrapper around the derivation primop that computes the
        `drvPath' and `outPath' attributes lazily. */
-    string path = settings.nixDataDir + "/nix/corepkgs/derivation.nix";
+    string path = canonPath(settings.nixDataDir + "/nix/corepkgs/derivation.nix", true);
     sDerivationNix = symbols.create(path);
     evalFile(path, v);
     addConstant("derivation", v);
diff --git a/src/libexpr/primops/fetchGit.cc b/src/libexpr/primops/fetchGit.cc
index 2e3e2634db8f..fd536c6a5e46 100644
--- a/src/libexpr/primops/fetchGit.cc
+++ b/src/libexpr/primops/fetchGit.cc
@@ -79,7 +79,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,
         ref = "HEAD"s;
     }
 
-    if (!ref) ref = "master"s;
+    if (!ref) ref = "HEAD"s;
 
     if (rev != "" && !std::regex_match(rev, revRegex))
         throw Error("invalid Git revision '%s'", rev);
@@ -138,7 +138,7 @@ GitInfo exportGit(ref<Store> store, const std::string & uri,
     gitInfo.rev = rev != "" ? rev : chomp(readFile(localRefFile));
     gitInfo.shortRev = std::string(gitInfo.rev, 0, 7);
 
-    printTalkative("using revision %s of repo '%s'", uri, gitInfo.rev);
+    printTalkative("using revision %s of repo '%s'", gitInfo.rev, uri);
 
     std::string storeLinkName = hashString(htSHA512, name + std::string("\0"s) + gitInfo.rev).to_string(Base32, false);
     Path storeLink = cacheDir + "/" + storeLinkName + ".link";
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index 1d611ffbaba5..e162e81aab5c 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -1189,7 +1189,7 @@ void DerivationGoal::outputsSubstituted()
     for (auto & i : drv->inputSrcs) {
         if (worker.store.isValidPath(i)) continue;
         if (!settings.useSubstitutes)
-            throw Error(format("dependency of '%1%' of '%2%' does not exist, and substitution is disabled")
+            throw Error(format("dependency '%1%' of '%2%' does not exist, and substitution is disabled")
                 % i % drvPath);
         addWaitee(worker.makeSubstitutionGoal(i));
     }
@@ -1458,7 +1458,7 @@ void replaceValidPath(const Path & storePath, const Path tmpPath)
        tmpPath (the replacement), so we have to move it out of the
        way first.  We'd better not be interrupted here, because if
        we're repairing (say) Glibc, we end up with a broken system. */
-    Path oldPath = (format("%1%.old-%2%-%3%") % storePath % getpid() % rand()).str();
+    Path oldPath = (format("%1%.old-%2%-%3%") % storePath % getpid() % random()).str();
     if (pathExists(storePath))
         rename(storePath.c_str(), oldPath.c_str());
     if (rename(tmpPath.c_str(), storePath.c_str()) == -1)
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index 943b16c28fa3..ba49749d830a 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -59,7 +59,7 @@ static void makeSymlink(const Path & link, const Path & target)
 
     /* Create the new symlink. */
     Path tempLink = (format("%1%.tmp-%2%-%3%")
-        % link % getpid() % rand()).str();
+        % link % getpid() % random()).str();
     createSymlink(target, tempLink);
 
     /* Atomically replace the old one. */
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index 4afe51ea91ec..3441b2472fcf 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -1215,7 +1215,7 @@ bool LocalStore::verifyStore(bool checkContents, RepairFlag repair)
 
                 /* Check the content hash (optionally - slow). */
                 printMsg(lvlTalkative, format("checking contents of '%1%'") % i);
-                HashResult current = hashPath(info->narHash.type, i);
+                HashResult current = hashPath(info->narHash.type, toRealPath(i));
 
                 if (info->narHash != nullHash && info->narHash != current.first) {
                     printError(format("path '%1%' was modified! "
diff --git a/src/libstore/optimise-store.cc b/src/libstore/optimise-store.cc
index 891540ae4c1d..7840167d7772 100644
--- a/src/libstore/optimise-store.cc
+++ b/src/libstore/optimise-store.cc
@@ -213,7 +213,7 @@ void LocalStore::optimisePath_(Activity * act, OptimiseStats & stats,
     MakeReadOnly makeReadOnly(mustToggle ? dirOf(path) : "");
 
     Path tempLink = (format("%1%/.tmp-link-%2%-%3%")
-        % realStoreDir % getpid() % rand()).str();
+        % realStoreDir % getpid() % random()).str();
 
     if (link(linkPath.c_str(), tempLink.c_str()) == -1) {
         if (errno == EMLINK) {
diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh
index 7f36e206416b..0cc20bf94194 100644
--- a/src/libstore/remote-store.hh
+++ b/src/libstore/remote-store.hh
@@ -122,11 +122,12 @@ protected:
 
     ref<Pool<Connection>> connections;
 
+    virtual void setOptions(Connection & conn);
+
 private:
 
     std::atomic_bool failed{false};
 
-    void setOptions(Connection & conn);
 };
 
 class UDSRemoteStore : public LocalFSStore, public RemoteStore
diff --git a/src/libstore/ssh-store.cc b/src/libstore/ssh-store.cc
index 107c6e1ecb4d..398408ea8d78 100644
--- a/src/libstore/ssh-store.cc
+++ b/src/libstore/ssh-store.cc
@@ -51,6 +51,16 @@ private:
     std::string host;
 
     SSHMaster master;
+
+    void setOptions(RemoteStore::Connection & conn) override
+    {
+        /* TODO Add a way to explicitly ask for some options to be
+           forwarded. One option: A way to query the daemon for its
+           settings, and then a series of params to SSHStore like
+           forward-cores or forward-overridden-cores that only
+           override the requested settings.
+        */
+    };
 };
 
 
diff --git a/src/libutil/logging.cc b/src/libutil/logging.cc
index 27a631a37d10..c1cff5cf9061 100644
--- a/src/libutil/logging.cc
+++ b/src/libutil/logging.cc
@@ -221,4 +221,12 @@ bool handleJSONLogMessage(const std::string & msg,
     return true;
 }
 
+Activity::~Activity() {
+    try {
+        logger.stopActivity(id);
+    } catch (...) {
+        ignoreException();
+    }
+}
+
 }
diff --git a/src/libutil/logging.hh b/src/libutil/logging.hh
index 677aa4daec4d..ca768d555add 100644
--- a/src/libutil/logging.hh
+++ b/src/libutil/logging.hh
@@ -94,8 +94,7 @@ struct Activity
 
     Activity(const Activity & act) = delete;
 
-    ~Activity()
-    { logger.stopActivity(id); }
+    ~Activity();
 
     void progress(uint64_t done = 0, uint64_t expected = 0, uint64_t running = 0, uint64_t failed = 0) const
     { result(resProgress, done, expected, running, failed); }
diff --git a/src/libutil/lru-cache.hh b/src/libutil/lru-cache.hh
index 3cb5d50889d9..9b8290e634c9 100644
--- a/src/libutil/lru-cache.hh
+++ b/src/libutil/lru-cache.hh
@@ -2,6 +2,7 @@
 
 #include <map>
 #include <list>
+#include <experimental/optional>
 
 namespace nix {
 
@@ -63,18 +64,17 @@ public:
 
     /* Look up an item in the cache. If it exists, it becomes the most
        recently used item. */
-    // FIXME: use boost::optional?
-    Value * get(const Key & key)
+    std::experimental::optional<Value> get(const Key & key)
     {
         auto i = data.find(key);
-        if (i == data.end()) return 0;
+        if (i == data.end()) return {};
 
         /* Move this item to the back of the LRU list. */
         lru.erase(i->second.first.it);
         auto j = lru.insert(lru.end(), i);
         i->second.first.it = j;
 
-        return &i->second.second;
+        return i->second.second;
     }
 
     size_t size()
diff --git a/src/libutil/serialise.cc b/src/libutil/serialise.cc
index 950e6362a245..9e2a502afaf8 100644
--- a/src/libutil/serialise.cc
+++ b/src/libutil/serialise.cc
@@ -67,7 +67,8 @@ void FdSink::write(const unsigned char * data, size_t len)
     try {
         writeFull(fd, data, len);
     } catch (SysError & e) {
-        _good = true;
+        _good = false;
+        throw;
     }
 }
 
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 341dedfdf038..2391e14a94bd 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -73,6 +73,13 @@ std::map<std::string, std::string> getEnv()
 }
 
 
+void clearEnv()
+{
+    for (auto & name : getEnv())
+        unsetenv(name.first.c_str());
+}
+
+
 Path absPath(Path path, Path dir)
 {
     if (path[0] != '/') {
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 47e02bc898a6..c5c537ee63d8 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -32,6 +32,9 @@ string getEnv(const string & key, const string & def = "");
 /* Get the entire environment. */
 std::map<std::string, std::string> getEnv();
 
+/* Clear the environment. */
+void clearEnv();
+
 /* Return an absolutized path, resolving paths relative to the
    specified directory, or the current directory otherwise.  The path
    is also canonicalised. */
diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc
index efef7f15c094..e1e27ceef94d 100644
--- a/src/nix-store/nix-store.cc
+++ b/src/nix-store/nix-store.cc
@@ -631,6 +631,7 @@ static void opDump(Strings opFlags, Strings opArgs)
     FdSink sink(STDOUT_FILENO);
     string path = *opArgs.begin();
     dumpPath(path, sink);
+    sink.flush();
 }
 
 
@@ -656,6 +657,7 @@ static void opExport(Strings opFlags, Strings opArgs)
 
     FdSink sink(STDOUT_FILENO);
     store->exportPaths(opArgs, sink);
+    sink.flush();
 }
 
 
diff --git a/src/nix/dump-path.cc b/src/nix/dump-path.cc
index 1a1866437b07..f411c0cb7c89 100644
--- a/src/nix/dump-path.cc
+++ b/src/nix/dump-path.cc
@@ -29,6 +29,7 @@ struct CmdDumpPath : StorePathCommand
     {
         FdSink sink(STDOUT_FILENO);
         store->narFromPath(storePath, sink);
+        sink.flush();
     }
 };
 
diff --git a/src/nix/run.cc b/src/nix/run.cc
index 822654daf488..d04e106e037b 100644
--- a/src/nix/run.cc
+++ b/src/nix/run.cc
@@ -16,8 +16,6 @@ using namespace nix;
 
 std::string chrootHelperName = "__run_in_chroot";
 
-extern char * * environ;
-
 struct CmdRun : InstallablesCommand
 {
     std::vector<std::string> command = { "bash" };
@@ -109,7 +107,7 @@ struct CmdRun : InstallablesCommand
                 if (s) kept[var] = s;
             }
 
-            environ = nullptr;
+            clearEnv();
 
             for (auto & var : kept)
                 setenv(var.first.c_str(), var.second.c_str(), 1);
diff --git a/src/nix/search.cc b/src/nix/search.cc
index 009dfae9cf40..5ccf1b7cf529 100644
--- a/src/nix/search.cc
+++ b/src/nix/search.cc
@@ -87,8 +87,6 @@ struct CmdSearch : SourceExprCommand, MixJSON
 
         auto state = getEvalState();
 
-        bool first = true;
-
         auto jsonOut = json ? std::make_unique<JSONObject>(std::cout) : nullptr;
 
         auto sToplevel = state->symbols.create("_toplevel");
@@ -96,6 +94,8 @@ struct CmdSearch : SourceExprCommand, MixJSON
 
         bool fromCache = false;
 
+        std::map<std::string, std::string> results;
+
         std::function<void(Value *, std::string, bool, JSONObject *)> doExpr;
 
         doExpr = [&](Value * v, std::string attrPath, bool toplevel, JSONObject * cache) {
@@ -143,10 +143,7 @@ struct CmdSearch : SourceExprCommand, MixJSON
                             jsonElem.attr("description", description);
 
                         } else {
-                            if (!first) std::cout << "\n";
-                            first = false;
-
-                            std::cout << fmt(
+                            results[attrPath] = fmt(
                                 "Attribute name: %s\n"
                                 "Package name: %s\n"
                                 "Version: %s\n"
@@ -245,6 +242,9 @@ struct CmdSearch : SourceExprCommand, MixJSON
             if (writeCache && rename(tmpFile.c_str(), jsonCacheFileName.c_str()) == -1)
                 throw SysError("cannot rename '%s' to '%s'", tmpFile, jsonCacheFileName);
         }
+
+        for (auto el : results) std::cout << el.second << "\n";
+
     }
 };
 
diff --git a/tests/export.sh b/tests/export.sh
index ec7560f19728..2238539bcca9 100644
--- a/tests/export.sh
+++ b/tests/export.sh
@@ -8,6 +8,11 @@ nix-store --export $outPath > $TEST_ROOT/exp
 
 nix-store --export $(nix-store -qR $outPath) > $TEST_ROOT/exp_all
 
+if nix-store --export $outPath >/dev/full ; then
+    echo "exporting to a bad file descriptor should fail"
+    exit 1
+fi
+
 
 clearStore
 
diff --git a/tests/lang/eval-okay-replacestrings.exp b/tests/lang/eval-okay-replacestrings.exp
index a2add1b7b140..72e8274d8c58 100644
--- a/tests/lang/eval-okay-replacestrings.exp
+++ b/tests/lang/eval-okay-replacestrings.exp
@@ -1 +1 @@
-[ "faabar" "fbar" "fubar" "faboor" "fubar" ]
+[ "faabar" "fbar" "fubar" "faboor" "fubar" "XaXbXcX" "X" "a_b" ]
diff --git a/tests/lang/eval-okay-replacestrings.nix b/tests/lang/eval-okay-replacestrings.nix
index 6284a0e660ae..bd8031fc004e 100644
--- a/tests/lang/eval-okay-replacestrings.nix
+++ b/tests/lang/eval-okay-replacestrings.nix
@@ -5,4 +5,7 @@ with builtins;
   (replaceStrings ["oo"] ["u"] "foobar")
   (replaceStrings ["oo" "a"] ["a" "oo"] "foobar")
   (replaceStrings ["oo" "oo"] ["u" "i"] "foobar")
+  (replaceStrings [""] ["X"] "abc")
+  (replaceStrings [""] ["X"] "")
+  (replaceStrings ["-"] ["_"] "a-b")
 ]
diff --git a/tests/nar-access.sh b/tests/nar-access.sh
index bd849cbfab1d..553d6ca89d7d 100644
--- a/tests/nar-access.sh
+++ b/tests/nar-access.sh
@@ -36,3 +36,9 @@ diff -u baz.cat-nar $storePath/foo/baz
 # Test missing files.
 nix ls-store --json -R $storePath/xyzzy 2>&1 | grep 'does not exist in NAR'
 nix ls-store $storePath/xyzzy 2>&1 | grep 'does not exist'
+
+# Test failure to dump.
+if nix-store --dump $storePath >/dev/full ; then
+    echo "dumping to /dev/full should fail"
+    exit -1
+fi