libstore: make Pool::get fully cancel-safe

cancelling a get() promise could leave the pool with allegedly in use
resource handles that do not actually exist. this would cause asserts
in ~Pool to fire (and crash the entire program due to bad accounting)

probably fixes #1041

Change-Id: Ic61ab9b658f02f71e8be7577b8a1115600846f86
This commit is contained in:
eldritch horrors
2026-01-18 17:22:41 +00:00
parent 48d5e9f07d
commit 8b114520a2
2 changed files with 59 additions and 17 deletions
+32
View File
@@ -1,5 +1,6 @@
#include "lix/libutil/pool.hh"
#include "lix/libutil/result.hh"
#include <exception>
#include <gtest/gtest.h>
#include <kj/async.h>
@@ -132,4 +133,35 @@ namespace nix {
ASSERT_NE(h->num, counter);
}
}
TEST_F(PoolTest, factoryCancel)
{
// resource factories failing must not crash if a promise is cancelled.
// c.f. https://git.lix.systems/lix-project/lix/issues/1041
{
Pool<TestResource> pool(1);
(void) pool.get();
}
{
auto createResource = []() -> kj::Promise<Result<ref<TestResource>>> {
return {result::failure(std::make_exception_ptr(Error("failure")))};
};
Pool<TestResource> pool(1, createResource);
(void) pool.get();
}
}
TEST_F(PoolTest, factoryFailureNormal)
{
auto createResource = []() -> kj::Promise<Result<ref<TestResource>>> {
return {result::failure(std::make_exception_ptr(Error("failure")))};
};
Pool<TestResource> pool(1, createResource);
ASSERT_THROW(pool.get().wait(ws).value(), Error);
}
}