CodeSampleX

Пример

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

Контракт

  1. get_or_try_init leaves the OnceCell uninitialized upon receiving Err, enabling subsequent initialization attempts to retry and succeed without cell poisoning
  2. sync::OnceCell coordinates concurrent fallible initializers such that a failing thread unblocks waiting threads to retry and initialize the value
  3. unsync::OnceCell safely returns None for get() during initialization but panics with reentrant init when get_or_init or set is called reentrantly
  4. unsync::OnceCell cleanly resets its state upon panic unwind, allowing subsequent get_or_init invocations to initialize the cell
  5. 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

Скачать артефакт с исходным кодом (tar.gz)

Исходный код

Cargo.lock
# 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",
]
Cargo.toml
[package]
name = "sample-once-cell"
version = "0.1.0"
edition = "2021"

[dependencies]
once_cell = "=1.21.4"
NOTES.md
# 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.
csx.json
{"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"}
src/lib.rs
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));
    }
}

Исходный сидер

csx-seed