Skip to content

Challenge 26: verify Rc/Weak safety in alloc::rc with Kani - #582

Open
v3risec wants to merge 33 commits into
model-checking:mainfrom
v3risec:challenge-26-rc
Open

v3risec wants to merge 33 commits into
model-checking:mainfrom
v3risec:challenge-26-rc

Conversation

@v3risec

@v3risec v3risec commented Apr 2, 2026

Copy link
Copy Markdown

Summary

This PR adds Kani-based verification artifacts for Rc/Weak safety in library/alloc/src/rc.rs for Challenge 26.

The change introduces:

  • proof harness modules under #[cfg(kani)] for all 12 required unsafe functions and all 54 listed safe functions;
  • contracts for unsafe pointer and reference-count operations;
  • semantic result assertions for safe functions, followed by kani::cover properties to demonstrate that the checked paths are reachable;
  • shared helper-based construction for nondeterministic unsized slice inputs, so Rc<[T]>/Weak<[T]> paths can be exercised in a reusable way.

No non-verification runtime behavior is changed in normal builds.

Verification Coverage Report

Unsafe functions (required by Challenge 26)

Coverage: 12 / 12 (100%)

Verified set includes:

  • Rc<mem::MaybeUninit<T>,A>::assume_init
  • Rc<[mem::MaybeUninit<T>],A>::assume_init
  • Rc<T:?Sized>::from_raw
  • Rc<T:?Sized>::increment_strong_count
  • Rc<T:?Sized>::decrement_strong_count
  • Rc<T:?Sized,A:Allocator>::from_raw_in
  • Rc<T:?Sized,A:Allocator>::increment_strong_count_in
  • Rc<T:?Sized,A:Allocator>::decrement_strong_count_in
  • Rc<T:?Sized,A:Allocator>::get_mut_unchecked
  • Rc<dyn Any,A:Allocator>::downcast_unchecked
  • Weak<T:?Sized>::from_raw
  • Weak<T:?Sized,A:Allocator>::from_raw_in

Safe functions (Challenge 26 list)

Coverage: 54 / 54 (100%)

This exceeds the challenge threshold (>= 75%).

Covered safe functions (54/54), grouped by API category:

Allocation

  • Rc<T>::new
  • Rc<T>::new_uninit
  • Rc<T>::new_zeroed
  • Rc<T>::try_new
  • Rc<T>::try_new_uninit
  • Rc<T>::try_new_zeroed
  • Rc<T>::pin
  • Rc<T,A:Allocator>::new_uninit_in
  • Rc<T,A:Allocator>::new_zeroed_in
  • Rc<T,A:Allocator>::new_cyclic_in
  • Rc<T,A:Allocator>::try_new_in
  • Rc<T,A:Allocator>::try_new_uninit_in
  • Rc<T,A:Allocator>::try_new_zeroed_in
  • Rc<T,A:Allocator>::pin_in

Slice

  • Rc<[T]>::new_uninit_slice
  • Rc<[T]>::new_zeroed_slice
  • Rc<[T]>::into_array
  • Rc<[T],A:Allocator>::new_uninit_slice_in
  • Rc<[T],A:Allocator>::new_zeroed_slice_in
  • RcFromSlice<T: Copy>::from_slice
  • RcFromSlice<T: Clone>::from_slice
  • ToRcSlice<T, I>::to_rc_slice

Conversion and pointer

  • Rc<T:?Sized, A:Allocator>::inner
  • Rc<T:?Sized, A:Allocator>::into_inner_with_allocator
  • Rc<T,A:Allocator>::try_unwrap
  • Rc<T:?Sized,A:Allocator>::into_raw_with_allocator
  • Rc<T:?Sized,A:Allocator>::as_ptr
  • Rc<T:?Sized,A:Allocator>::get_mut
  • Rc<T:?Sized+CloneToUninit, A:Allocator+Clone>::make_mut
  • Rc<T:?Sized,A:Allocator>::from_box_in
  • Rc<dyn Any,A:Allocator>::downcast

Trait implementations (Rc)

  • Clone<T: ?Sized, A:Allocator>::clone for Rc
  • Drop<T: ?Sized, A:Allocator>::drop for Rc
  • Default<T:Default>::default
  • Default<str>::default
  • From<&str>::from
  • From<Vec<T,A:Allocator>>::from
  • From<Rc<str>>::from
  • TryFrom<Rc<[T],A:Allocator>>::try_from

Weak and traits

  • Weak<T:?Sized,A:Allocator>::as_ptr
  • Weak<T:?Sized,A:Allocator>::into_raw_with_allocator
  • Weak<T:?Sized,A:Allocator>::upgrade
  • Weak<T:?Sized,A:Allocator>::inner
  • Drop<T:?Sized, A:Allocator>::drop for Weak

UniqueRc and traits

  • UniqueRc<T:?Sized,A:Allocator>::into_rc
  • UniqueRc<T:?Sized,A:Allocator+Clone>::downgrade
  • Deref<T:?Sized,A:Allocator>::deref
  • DerefMut<T:?Sized,A:Allocator>::deref_mut
  • Drop<T:?Sized, A:Allocator>::drop for UniqueRc
  • UniqueRcUninit<T:?Sized, A:Allocator>::new
  • UniqueRcUninit<T:?Sized, A:Allocator>::data_ptr
  • Drop<T:?Sized, A:Allocator>::drop for UniqueRcUninit

Refcount internals

  • RcInnerPtr::inc_strong
  • RcInnerPtr::inc_weak

Note

  • Verify the default RcFromSlice<T: Clone>::from_slice implementation with a manually implemented non-trivial Clone type, ensuring that the harness does not dispatch to the TrivialClone specialization.
  • Verify ToRcSlice<T, I>::to_rc_slice through the FromIterator and exact-size TrustedLen path.
  • Both harnesses execute the real Rc::from_iter_exact implementation and its original element-writing loop. The target implementation is not replaced with a cfg(kani)-specific loop.
  • These two harnesses use symbolic inputs bounded to at most four elements and unwind the real loop. This is a verification tractability bound: current Kani loop contracts cannot soundly and tractably summarize the iterator's private pointer state, pointer provenance, and yielded values.

Three Criteria Met (Challenge 26)

  • Required unsafe functions covered: All 12/12 required unsafe functions in Challenge 26 are annotated with contracts and verified.
  • Safe-function threshold met: 54/54 safe functions are covered (100%), which exceeds the Challenge 26 requirement of at least 75%.
  • Challenge scope allowances respected: Generic T is instantiated with allowed representative concrete types, and allocator-focused proofs are limited to standard-library allocator scope (Global).

Approach

The verification strategy combines contracts for unsafe entry points with executable proof harnesses:

  1. Contract for unsafe functions
  • Attach requires preconditions for pointer validity, alignment soundness, same-allocation checks, and refcount well-formedness.
  • Attach postconditions where appropriate (ensures) and mutation footprints (kani::modifies) for refcount-changing operations.
  1. Harness-backed behavioral checks
  • Use #[kani::proof_for_contract(...)] harnesses for all required unsafe functions, and regular #[kani::proof] harnesses for the covered safe functions.
  • Check safe functions' results including ownership changes, reference counts, pointer identity, slice length, and initialized payload.
  • Place kani::cover properties after the corresponding assertions to show that the verified paths are not vacuous.
  1. Helper-based unbounded input generalization
  • Introduce shared helper functions for nondeterministic and unbounded vector/slice setup and reuse them across harnesses that target ?Sized slice-based functions.
  • Use the helpers to exercise unsized slice cases through Rc<[T]>/Weak<[T]> constructions without duplicating per-harness setup logic.
  1. Challenge alignment
  • Keep all verification code under cfg(kani) so normal std behavior is unchanged.
  • Target Challenge 26 success criteria directly: full required unsafe coverage + safe coverage above threshold.

Scope assumptions (per challenge allowance)

  • Harnesses instantiate representative concrete types, including signed/unsigned widths (i8..i128, u8..u128), bool, (), arrays, vectors, slices, str, and trait objects (dyn Any).
  • Allocator coverage is limited to Global (both explicit Rc<_, Global> / Weak<_, Global> and default Rc/Weak aliases).

Verification

All harnesses in this PR pass locally with Kani.

Platform-specific CI tractability note

The shared nondeterministic vector helper now bounds the symbolic length to <= 100 for CI resource stability. This is only a verification-time tractability bound for shared CI runners; it is not a safety condition or a function-behavior assumption.

Resolves #382

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.

@v3risec
v3risec requested a review from a team as a code owner April 2, 2026 18:17
@feliperodri

Copy link
Copy Markdown
Member

You should use macros to reduce code duplication. It'll also make review easier.

@feliperodri feliperodri added the Challenge Used to tag a challenge label Apr 2, 2026
@feliperodri
feliperodri requested a review from Copilot April 2, 2026 19:16

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review any files in this pull request.

@feliperodri
feliperodri requested a review from Copilot April 9, 2026 03:17

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review any files in this pull request.

@v3risec
v3risec marked this pull request as draft April 9, 2026 06:22
@v3risec
v3risec marked this pull request as ready for review April 13, 2026 19:20
@feliperodri
feliperodri requested a review from Copilot April 14, 2026 05:48

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 3 changed files in this pull request and generated 5 comments.

Comment thread library/alloc/src/rc.rs Outdated
Comment thread library/alloc/src/rc.rs
Comment thread library/alloc/src/rc.rs Outdated
Comment thread library/alloc/src/rc.rs
Comment thread library/alloc/src/rc.rs Outdated
v3risec added 2 commits April 14, 2026 23:40
- fix verify_4533 slice harness generation
- rename duplicate UniqueRcUninit drop macro
- add unstable(kani) annotations to verify modules
- keep production from_iter_exact loop under non-Kani builds
- make nondet Vec helper initialize elements soundly
@v3risec

v3risec commented Apr 20, 2026

Copy link
Copy Markdown
Author

Thanks for the thoughtful review. We have addressed all 5 comments and pushed 3 follow-up commits with the requested changes. The PR should now be ready for another round of CI and review. Could you please re-run the CI checks when possible?

@v3risec

v3risec commented Apr 21, 2026

Copy link
Copy Markdown
Author

Hi, I would like to report what appears to be a CI resource / environment issue rather than a reproducible proof failure.
In my latest commit f6716a99a6b05a4f298cc83f62aff10ab8c3fad3, I observed two CBMC out-of-memory failures in CI:

  1. In Kani / Verify std library (partition 1) (pull_request),
    rc::verify_3051::harness_from_vec_i32 failed with:
    CBMC appears to have run out of memory.
1e1eb596e56a443071d43ac8f53391e1
  1. In Kani / Verify std library using autoharness (macos-latest) (pull_request),
    rc::verify_1650::harness_rc_from_raw_in_vec_u64 failed with:
    CBMC appears to have run out of memory.
5942664e3042a246f50bcbc6636b3770

What I want to emphasize is that both of these harnesses verify successfully in my local environment, and I do not see any CBMC appears to have run out of memory failure locally.
f6607edaf87e9c81fb512c2fe3defe2f
e11c48db33e27c6c8459772e06a5219a

They also succeeded in the earlier commit e189a7d8a8b06cee7eb6a33c32ea024639702ebe. The harness definitions themselves were unchanged between the two commits, although shared helper code used by them did change (ptr::write_bytes added), so I cannot claim the proof inputs were fully identical across revisions. Still, the local-vs-CI discrepancy suggests that these proofs may be close to the CI resource boundary.

For reference, my local verification environment is:

  • CPU: 2 x Intel(R) Xeon(R) Gold 6230R CPU @ 2.10GHz
  • Cores / threads: 52 physical cores / 104 logical CPUs
  • Memory: 125 GiB RAM
  • OS: Ubuntu 24.04.1-based system
  • Kernel: Linux 6.11.0-26-generic
  • Kani: repo-pinned version from tool_config/kani-version.toml, commit 415ca503aea80fd4c4c4819ad4770b744f1bc3a1
  • CBMC: 6.8.0 (cbmc-6.8.0)
  • Rust: rustc 1.92.0-nightly (b6f0945e4 2025-10-08)
  • Host: x86_64-unknown-linux-gnu
  • LLVM: 21.1.2

So these do not appear to be stable. Given that these harnesses pass locally without any CBMC out-of-memory issue, would it make sense to investigate whether the CI runners are hitting memory limits, and if so, whether the memory budget or other CI resource constraints for these Kani jobs should be adjusted?

@v3risec

v3risec commented May 13, 2026

Copy link
Copy Markdown
Author

Update on the CI resource issue:

The recent changes add a macOS-only bound to the nondeterministic slice/vector length used by the shared Rc<[T]> / Weak<[T]> helper code. This was added because some of these harnesses were hitting CBMC resource limits in GitHub Actions, while the same harnesses verified successfully in my local Ubuntu environment.

The bound is guarded by #[cfg(target_os = "macos")], so it only applies to the macOS CI configuration. Ubuntu/Linux verification keeps the original unbounded path with respect to this additional platform-specific assumption.

The intent is to keep the macOS CI jobs within their time/memory budget, not to change normal std behavior or the Linux verification setup.

@v3risec
v3risec requested a review from feliperodri August 24, 2026 09:55
@v3risec
v3risec requested a review from a team as a code owner August 25, 2026 02:38
@v3risec

v3risec commented Aug 27, 2026

Copy link
Copy Markdown
Author

@feliperodri All CI checks are green now, and I’ve addressed the non-blocking issues. This should be ready for another look. Thanks!

Add semantic assertions and matching kani::cover properties.

Check reference-count invariants, pointer identity, slice metadata, and weak-pointer ownership states across Rc-related harnesses.

No production Rc implementation logic was changed.
@v3risec

v3risec commented Sep 2, 2026

Copy link
Copy Markdown
Author

Strengthen the Challenge 26 Kani safe functions' harnesses for Rc and related Weak, UniqueRc, and UniqueRcUninit paths.

The safe functions' harnesses now:

  • add semantic result assertions with matching kani::cover properties;
  • check strong and weak reference-count invariants across construction, cloning, conversion, raw-pointer roundtrips, and destruction;
  • cover live, expired, and dangling weak-pointer states;
  • exercise relevant ownership transitions, including unique, shared, and weak-present states;

Add bounded harnesses for RcFromSlice<T: Clone>::from_slice and ToRcSlice::to_rc_slice. Remove the Kani-specific loop contract and rewritten loop so the harnesses directly verify the real from_iter_exact implementation.
@v3risec

v3risec commented Sep 3, 2026

Copy link
Copy Markdown
Author

Added standalone verification coverage for the two previously uncovered safe functions:

  • RcFromSlice<T: Clone>::from_slice
  • ToRcSlice<T, I>::to_rc_slice

The RcFromSlice harness uses a type with a manual, non-trivial Clone implementation, which forces dispatch through the default clone-per-element implementation rather than the TrivialClone specialization.

The ToRcSlice harness exercises the exact-size TrustedLen path through FromIterator. Both harnesses call the real Rc::from_iter_exact implementation and unwind its original element-writing loop.

These two harnesses use nondeterministic inputs bounded to at most four elements with #[kani::unwind(6)]. The bound is needed because current Kani loop contracts cannot soundly and tractably summarize the iterator's private pointer state, pointer provenance, and yielded values.

With these additions, the PR now provides standalone coverage for all 54/54 safe functions listed in Challenge 26.

Add post-call kani::cover witnesses to all Rc and Weak proof_for_contract harnesses.

@feliperodri feliperodri left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving — leading solution for Challenge 26

Thanks @v3risec. After reviewing both open Challenge 26 (Rc/Weak) solutions with our vacuity tooling and local Kani (pinned 0.67.0 / CBMC 6.8.0), this is complete and sound. Prioritizing it.

Coverage against Ch26 criteria:

  • A: 12/12 unsafe pub fns with real #[requires]/#[ensures]/kani::modifies contracts backed by matching #[kani::proof_for_contract] harnesses, monomorphized across primitive T (i8..i128, u8..u128, bool, unit, [u8;4]) and unsized [T] as challenge-allowed.
  • B: ~54/54 safe abstractions with unsafe (~100%, ≥ 75%). Complete coverage across new(_uninit/_zeroed/in), try*, pin/pin_in, into_array, get_mut/make_mut (with 3-state coverage), downcast (Ok+Err), from_box_in, RcFromSlice / ToRcSlice, Drop/Clone/Default, all From/TryFrom variants, Weak::{as_ptr,into_raw_with_allocator,upgrade,inner} (multi-path), inc_strong/inc_weak (+ should_panic overflow), UniqueRc + UniqueRcUninit.

Soundness (all clean):

  • T1: no cfg body swaps — grep for cfg(not(kani)) in the diff returns 0 hits; harnesses run the real bodies.
  • T2: no trivial invariants, no loop_invariant(true).
  • T7: all 12 unsafe fns have explicit proof_for_contract; .github/workflows/kani.yml autoharness allowlist unchanged — no silent autoharness dependency.
  • Not assume-the-conclusion — the only kani::assume(can_dereference(...)) is Vec::set_len's own precondition inside a helper, not the fn under proof.
  • Inputs symbolic (kani::any::<T>()); slice length bounded ≤100 (documented CI-tractability budget); iterator loops unwind(6) for 4-element input (documented Kani loop-contract limitation).
  • No runtime std logic changed.

Local Kani sample (CBMC 6.8.0): 4/4 VERIFICATION SUCCESSFUL — harness_rc_assume_init_i8 (proof_for_contract), harness_rc_downcast_unchecked_i8 (proof_for_contract), harness_inc_strong_overflow_should_panic, harness_rc_default_str.

Minor weaknesses to note for the record (non-blocking):

  1. verifier_nondet_vec uses ptr::write_bytes(..., kani::any::<u8>(), size_of::<T>() * sz) — one symbolic byte pattern replicated across all elements, so a run over Rc<[u32]> only covers [0x00000000; n], [0x01010101; n], … Symbolic but coverage-limited for multi-byte T.
  2. Rc::from_raw, Rc::increment_strong_count, and Weak::from_raw (non-_in variants) read (*ptr).get() inside unsafe without an explicit kani::mem::can_dereference in the requires, unlike the _in variants which do. Harmless for the roundtrip harnesses (pointers are always valid), but the exported contract is weaker than the _in variant for arbitrary callers — consider adding can_dereference to match.
  3. Rc::get_mut_unchecked contract only requires can_write(value); the documented safety property (no other Rc/Weak may reference the inner value) is not encoded — the harness proves UB-freedom of the body but under-specifies the caller obligation.
  4. Roundtrip-narrowed inputs (from_raw/increment/decrement use ptr obtained via into_raw) narrow the input universe vs a fully symbolic pointer meeting the precondition.

These are contract-strength refinements, not soundness bugs; they can be addressed in a followup. Challenge 26 explicitly permits bounded + primitive-mono.

@feliperodri

feliperodri commented Sep 13, 2026

Copy link
Copy Markdown
Member

@lucasccordeiro @rajath-mk @patricklam @HuStmpHrrr could you review this propose solution for challenge 26?

@feliperodri feliperodri added the Accepted Solution Tag used to mark the solution accepted for a given challenge label Sep 13, 2026
@HuStmpHrrr

Copy link
Copy Markdown

checking now

Comment thread library/alloc/src/rc.rs Outdated
let offset = unsafe { data_offset(ptr) };
let strong_ptr = unsafe { ptr.byte_sub(offset) as *const Cell<usize> };
unsafe { &raw const *strong_ptr }
}))]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we not want to assert then increment of the count?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. The contract now snapshots the strong count with old(...) and specifies that, on normal return, the resulting strong count is exactly the previous count plus one:

strong_before.checked_add(1) == Some(strong_after).

The modifies clause is also restricted to the strong-count cell.

Comment thread library/alloc/src/rc.rs Outdated
let offset = unsafe { data_offset(ptr) };
let strong_ptr = unsafe { ptr.byte_sub(offset) as *const Cell<usize> };
unsafe { &raw const *strong_ptr }
}))]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same; not capturing decrement

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. The contract now snapshots the pre-state and specifies the exact decrement:

strong_before.checked_sub(1) == Some(strong_after).

The strong_before == 1 case is intentionally handled separately in the postcondition. A final decrement may drop T and deallocate the backing allocation, so it is not sound to dereference the old strong-count pointer afterward.

Comment thread library/alloc/src/rc.rs Outdated
@@ -1629,6 +1697,26 @@ impl<T: ?Sized, A: Allocator> Rc<T, A> {
/// }
/// ```
#[unstable(feature = "allocator_api", issue = "32838")]
#[requires({
let offset = unsafe { data_offset(ptr) };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this block seems repetitive; do we have a way to modularize it?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored. The repeated raw-pointer reconstruction, layout, and reference-count checks are now factored into shared Kani-only helpers such as rc_raw_parts, rc_raw_layout_valid, rc_raw_valid, weak_raw_layout_valid, weak_raw_valid, and weak_raw_count_snapshot.

This also lets Weak::from_raw and Weak::from_raw_in share the same validity model instead of duplicating slightly different checks.

Comment thread library/alloc/src/rc.rs Outdated
@@ -3214,6 +3350,42 @@ impl<T: ?Sized> Weak<T> {
/// [`new`]: Weak::new
#[inline]
#[stable(feature = "weak_into_raw", since = "1.45.0")]
#[requires({
let is_sentinel = is_dangling(ptr);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it semantically sound to permit dangling pointer? what is the motivation?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The allowed dangling case is not an arbitrary dangling allocation pointer. It is specifically the usize::MAX sentinel representation used by Weak::new / Weak::new_in.

That sentinel has no backing RcInner, and Weak::from_raw{,_in} explicitly supports raw pointers produced from an empty Weak. The contract now makes this distinction explicit: weak_raw_valid accepts the sentinel directly, while every non-sentinel pointer must satisfy the normal allocation/layout/reference-count checks.

@v3risec

v3risec commented Sep 15, 2026

Copy link
Copy Markdown
Author

@feliperodri @HuStmpHrrr Thanks for the detailed review. I went through the comments and updated the contracts and harnesses accordingly.

The main changes are:

  • Strengthened the strong-count contracts so increment_strong_count records the pre-state and specifies the +1 transition, while decrement_strong_count specifies the -1 transition.
  • Refactored the repeated raw-pointer/layout/refcount checks into shared Kani-only helpers.
  • Unified the raw-pointer validity checks used by the non-_in and _in variants, including explicit dereferenceability checks for the reference-count storage.
  • Clarified that the dangling case accepted by Weak::from_raw{,_in} is the exact usize::MAX sentinel used by Weak::new[_in], not an arbitrary dangling pointer.
  • Made the Weak raw-pointer contracts sentinel-safe and added dedicated proof_for_contract harnesses for the sentinel paths of both Weak::from_raw and Weak::from_raw_in.
  • Changed verifier_nondet_vec so each byte is independently symbolic instead of repeating one symbolic byte across the whole buffer.
  • Documented the remaining modeling limitation of Rc::get_mut_unchecked: can_write captures writable storage, but the temporal aliasing/active-borrow/exact-inner-type obligation from the API safety documentation is not fully expressible by this contract.
  • I kept the raw-pointer contract harnesses based on structurally valid pointers rather than arbitrary pointer bits. Evaluating the raw-layout predicates itself performs provenance-sensitive pointer reconstruction, so starting from an arbitrary address and attempting to filter it afterward would not be a sound replacement.

I also noticed that the Kani CI jobs are currently failing while setting up Kani/CBMC, before reaching the verification itself. The failure comes from Homebrew rejecting the diffblue/cbmc tap as untrusted:

Refusing to load formula diffblue/cbmc/... from untrusted tap diffblue/cbmc.
Error: Cannot tap diffblue/cbmc: invalid syntax in tap!

Is this a known CI/infrastructure issue at the moment, or is there anything I should change on my side?

I'm happy to make any further changes or refinements if needed. Thanks again for the review!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Accepted Solution Tag used to mark the solution accepted for a given challenge Challenge Used to tag a challenge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Challenge 26: Verify reference-counted Cell implementation

5 participants