Пример
once_cell 1.21.4: Prove once_cell fallible initialization retry semantics, non-poisoning error recovery, unsync reentrancy panic behavior, and cell lifecycle reset
Проверенный пример — cargo once_cell 1.21.4: Prove once_cell fallible initialization retry semantics, non-poisoning error recovery, unsync reentrancy panic…
sha256:e0afb4151238134f23cb7f9babe65162ab344625d8c386e357c4dafa43f92775
Эта сеть предлагает одно: образец, который собирается. Она запустила его в песочнице и сохранила подписанную квитанцию. Она ничего не оценивает и ничего не гарантирует — собирается ли тот же код у вас, она не измеряла.
Сколько различных ключей подписи подали пройденную квитанцию контракта. Один — только автор; больше одного — значит, кто-то ещё тоже собрал. Ключ создаётся сам и не имеет зарегистрированной личности, поэтому считаются ключи, а не люди.
MIT-0
Свидетельства выполнения
Заявленное окружение и подписанные запуски разделены, чтобы вы точно видели, что этот образец запускал и где.
- Основа свидетельства
- Подписанный контракт пройден
- Квитанции проверки
- 3
- Ключи подписи, собравшие его
- 3
Заявленная среда
rust linux x64 rust rust cargo
Среды запусков проверки
| Окружение | Контракт | Этапы | Запуск |
|---|---|---|---|
| rust 1 · linux alpine/x64 · docker ed25519:d91480838ac982c9 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · cargo@1 |
2026-08-17 |
| rust 1 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · cargo@1 |
2026-08-18 |
| rust 1 · linux alpine/x64 · docker ed25519:c1973797be207ac4 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · cargo@1rust:1-alpine@sha256:a10e64dd139b… |
2026-09-08 |
Кейс
HOW- Цель
- Prove once_cell fallible initialization retry semantics, non-poisoning error recovery, unsync reentrancy panic behavior, and cell lifecycle reset
- Пакеты
- Символы
-
- once_cell::sync::OnceCell::get_or_try_init
- once_cell::sync::OnceCell
- once_cell::unsync::OnceCell
- once_cell::sync::OnceCell::take
- Окружение
- rust
- Создан
- 2026-08-17T20:42:35Z
Контракт
- get_or_try_init leaves the OnceCell uninitialized upon receiving Err, enabling subsequent initialization attempts to retry and succeed without cell poisoning
- sync::OnceCell coordinates concurrent fallible initializers such that a failing thread unblocks waiting threads to retry and initialize the value
- unsync::OnceCell safely returns None for get() during initialization but panics with reentrant init when get_or_init or set is called reentrantly
- unsync::OnceCell cleanly resets its state upon panic unwind, allowing subsequent get_or_init invocations to initialize the cell
- OnceCell structural equality evaluates uninitialized cells as equal and take resets an initialized cell back to empty state for re-initialization
Файлы
- Cargo.lock
- Cargo.toml
- NOTES.md
- csx.json
- src/lib.rs
Исходный код
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "once_cell"
version = "1.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
[[package]]
name = "sample-once-cell"
version = "0.1.0"
dependencies = [
"once_cell",
]
[package]
name = "sample-once-cell"
version = "0.1.0"
edition = "2021"
[dependencies]
once_cell = "=1.21.4"
# once_cell 1.21.4 Observed Behavior
## Prior Knowledge Search
A search across known solutions found the following related samples:
- `sha256:bf34c4b96e5d2e5c6749e27e05216e4f465933461e70adea2f1b2170b3c1b021`: Focused on `race::OnceBox` non-blocking initialization vs `sync::OnceCell` blocking execution.
- `sha256:606853390ed4aa0c8d86a36f2445430ec301faa64e65777b8f5770fd50e5ec46`: Focused on `try_insert` error tuple shape and `Lazy::into_value` uninitialized return.
- `sha256:2540d92a67fbf6a1022bea9ae03def3fce5c135fae138bc0e6af3be8d4884445`: Focused on `race` vs `sync` feature flag differences with `default-features = false`.
This sample focuses on fallible initialization retry semantics (`get_or_try_init`), concurrent thread unblocking on error, `unsync::OnceCell` reentrancy panic behavior vs safe `get()` inspection, panic unwind recovery, and structural equality / mutable reset lifecycle (`take`).
## Pinned Release
- `once_cell` version: `1.21.4` (resolved and locked via `Cargo.lock`).
## Observed Behaviors and Traps
### 1. Fallible Initialization Retry (`get_or_try_init`)
When `sync::OnceCell::get_or_try_init` (or `unsync::OnceCell::get_or_try_init`) receives a closure returning `Err(E)`:
- The cell remains uninitialized (`cell.get()` evaluates to `None`).
- The error `Err(E)` is returned directly to the caller.
- The cell is not poisoned: subsequent calls to `get_or_try_init` (or `get_or_init`) can retry initialization and succeed with `Ok(&T)`.
- Once successfully initialized, subsequent `get_or_try_init` calls return the cached `Ok(&T)` reference immediately without evaluating the closure.
- In multi-threaded environments, if a thread attempting initialization fails with `Err`, waiting threads are unblocked and allowed to attempt initialization rather than failing permanently.
### 2. Single-Threaded Reentrancy Traps (`unsync::OnceCell`)
In single-threaded contexts (`unsync::OnceCell`):
- Calling `cell.get()` inside an active initializer closure safely returns `None`.
- Re-entrantly calling `cell.get_or_init()` or `cell.set()` on the same cell from within its own initializer closure panics loudly with `"reentrant init"`.
- If an initializer closure panics (including from reentrancy), the unwinding destructor resets the cell's internal initializing state back to uninitialized, enabling subsequent `get_or_init` calls to execute and initialize the cell cleanly.
### 3. Structural Equality and Reset Lifecycle
- Two uninitialized `OnceCell` instances evaluate as equal (`cell_a == cell_b`).
- An initialized cell and an uninitialized cell are not equal.
- Calling `cell.take()` on `&mut OnceCell<T>` extracts `Some(T)` and resets the cell back to uninitialized (`None`), allowing the cell to be re-initialized.
{"case":{"believed":"A common belief is that OnceCell initialization failure permanently poisons the cell preventing subsequent retry, or that unsync::OnceCell allows recursive initialization without panicking.","caseId":"case:sha256:461dc09e1504a0c517ee3a986d11ab8bd742211814bee25e3a0ead1e630f36a3","contract":["get_or_try_init leaves the OnceCell uninitialized upon receiving Err, enabling subsequent initialization attempts to retry and succeed without cell poisoning","sync::OnceCell coordinates concurrent fallible initializers such that a failing thread unblocks waiting threads to retry and initialize the value","unsync::OnceCell safely returns None for get() during initialization but panics with reentrant init when get_or_init or set is called reentrantly","unsync::OnceCell cleanly resets its state upon panic unwind, allowing subsequent get_or_init invocations to initialize the cell","OnceCell structural equality evaluates uninitialized cells as equal and take resets an initialized cell back to empty state for re-initialization"],"goal":"Prove once_cell fallible initialization retry semantics, non-poisoning error recovery, unsync reentrancy panic behavior, and cell lifecycle reset","kind":"HOW","packages":["pkg:cargo/once_cell@1.21.4"],"schemaVersion":1,"symbols":["once_cell::sync::OnceCell::get_or_try_init","once_cell::sync::OnceCell","once_cell::unsync::OnceCell","once_cell::sync::OnceCell::take"]},"contractCommand":["cargo","test","--offline"],"environment":{"arch":"x64","ecosystem":"cargo","executionContext":"rust","language":"rust","os":"linux","packageManager":"cargo","runtime":"rust","schemaVersion":1},"license":"MIT-0","packages":["pkg:cargo/once_cell@1.21.4"],"schemaVersion":1,"symbols":["once_cell::sync::OnceCell::get_or_try_init","once_cell::sync::OnceCell","once_cell::unsync::OnceCell","once_cell::sync::OnceCell::take"],"verifierAdapter":"cargo@1"}
use std::panic::{self, AssertUnwindSafe};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;
pub use once_cell::sync::OnceCell as SyncOnceCell;
pub use once_cell::unsync::OnceCell as UnsyncOnceCell;
/// Contract 1: get_or_try_init leaves OnceCell uninitialized upon Err,
/// enabling subsequent initialization attempts to retry and succeed without poisoning.
pub fn sync_fallible_init_retry() -> (bool, i32, usize) {
let cell = SyncOnceCell::new();
let attempts = AtomicUsize::new(0);
// Initial attempt returning Err does not initialize the cell
let res1 = cell.get_or_try_init(|| {
attempts.fetch_add(1, Ordering::SeqCst);
Err::<i32, &'static str>("transient error")
});
assert_eq!(res1, Err("transient error"));
assert!(cell.get().is_none());
// Subsequent attempt returning Ok succeeds and initializes the cell
let res2 = cell.get_or_try_init(|| {
attempts.fetch_add(1, Ordering::SeqCst);
Ok::<i32, &'static str>(42)
});
assert_eq!(res2, Ok(&42));
assert_eq!(cell.get(), Some(&42));
// Further attempts return the cached reference without invoking the closure
let res3 = cell.get_or_try_init(|| {
attempts.fetch_add(1, Ordering::SeqCst);
Err::<i32, &'static str>("closure should not be executed")
});
assert_eq!(res3, Ok(&42));
(cell.get().is_some(), *cell.get().unwrap(), attempts.load(Ordering::SeqCst))
}
/// Contract 2: sync::OnceCell coordinates concurrent fallible initializers
/// such that a failing thread unblocks waiting threads to retry and initialize.
pub fn sync_concurrent_fallible_retry() -> (i32, usize) {
let cell = Arc::new(SyncOnceCell::new());
let attempts = Arc::new(AtomicUsize::new(0));
let cell1 = Arc::clone(&cell);
let attempts1 = Arc::clone(&attempts);
let handle1 = thread::spawn(move || {
cell1
.get_or_try_init(|| {
attempts1.fetch_add(1, Ordering::SeqCst);
Err::<i32, &'static str>("thread 1 initial failure")
})
.map(|v| *v)
});
let res1 = handle1.join().expect("thread 1 failed");
assert_eq!(res1, Err("thread 1 initial failure"));
let cell2 = Arc::clone(&cell);
let attempts2 = Arc::clone(&attempts);
let handle2 = thread::spawn(move || {
cell2
.get_or_try_init(|| {
attempts2.fetch_add(1, Ordering::SeqCst);
Ok::<i32, &'static str>(100)
})
.map(|v| *v)
});
let res2 = handle2.join().expect("thread 2 failed");
assert_eq!(res2, Ok(100));
(*cell.get().unwrap(), attempts.load(Ordering::SeqCst))
}
/// Contract 3: unsync::OnceCell safely returns None for get() during initialization
/// but panics with "reentrant init" when get_or_init or set is called reentrantly.
pub fn unsync_reentrancy_traps() -> (bool, bool) {
let cell = UnsyncOnceCell::new();
// Reentrant get_or_init panics
let reentrant_get_or_init_panic = panic::catch_unwind(AssertUnwindSafe(|| {
cell.get_or_init(|| {
assert!(cell.get().is_none(), "get() during init must return None");
let _ = cell.get_or_init(|| 99);
42
});
}));
let cell2 = UnsyncOnceCell::new();
// Reentrant set panics
let reentrant_set_panic = panic::catch_unwind(AssertUnwindSafe(|| {
cell2.get_or_init(|| {
let _ = cell2.set(999);
42
});
}));
(reentrant_get_or_init_panic.is_err(), reentrant_set_panic.is_err())
}
/// Contract 4: unsync::OnceCell cleanly resets its state upon panic unwind,
/// allowing subsequent get_or_init invocations to initialize the cell.
pub fn unsync_panic_unwind_recovery() -> (bool, i32) {
let cell = UnsyncOnceCell::new();
let panic_result = panic::catch_unwind(AssertUnwindSafe(|| {
cell.get_or_init(|| {
panic!("aborted initialization");
});
}));
assert!(panic_result.is_err());
assert!(cell.get().is_none());
// Second initialization attempt succeeds cleanly after previous panic unwind
let init_result = cell.get_or_init(|| 256);
(cell.get().is_some(), *init_result)
}
/// Contract 5: OnceCell structural equality evaluates uninitialized cells as equal,
/// and take resets an initialized cell back to empty state for re-initialization.
pub fn cell_lifecycle_and_equality() -> (bool, bool, Option<i32>, Option<i32>) {
let mut cell_a = SyncOnceCell::new();
let cell_b = SyncOnceCell::new();
// Two uninitialized cells are equal
let empty_equal = cell_a == cell_b;
// Initializing cell_a makes them unequal
cell_a.set(55).expect("set failed");
let uninit_vs_init_unequal = cell_a != cell_b;
// Mutably taking value resets cell_a back to None
let taken = cell_a.take();
assert_eq!(taken, Some(55));
assert!(cell_a.get().is_none());
// Once taken, cell_a can be reinitialized
cell_a.set(77).expect("re-set failed");
let reinitialized = cell_a.into_inner();
(empty_equal, uninit_vs_init_unequal, taken, reinitialized)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sync_fallible_init_retry() {
let (is_init, val, attempts) = sync_fallible_init_retry();
assert!(is_init);
assert_eq!(val, 42);
assert_eq!(attempts, 2);
}
#[test]
fn test_sync_concurrent_fallible_retry() {
let (val, attempts) = sync_concurrent_fallible_retry();
assert_eq!(val, 100);
assert_eq!(attempts, 2);
}
#[test]
fn test_unsync_reentrancy_traps() {
let (get_or_init_panicked, set_panicked) = unsync_reentrancy_traps();
assert!(get_or_init_panicked, "Reentrant get_or_init must panic");
assert!(set_panicked, "Reentrant set must panic");
}
#[test]
fn test_unsync_panic_unwind_recovery() {
let (is_init, val) = unsync_panic_unwind_recovery();
assert!(is_init);
assert_eq!(val, 256);
}
#[test]
fn test_cell_lifecycle_and_equality() {
let (empty_eq, uninit_neq, taken, reinit) = cell_lifecycle_and_equality();
assert!(empty_eq);
assert!(uninit_neq);
assert_eq!(taken, Some(55));
assert_eq!(reinit, Some(77));
}
}