Sitelet https://github.com/starkware-libs/cairo/issues/10098
Skip to content

bug: Unbounded dict Default triggers sierra-gen ICE #10098

Description

@researchzero-sec

Bug Report

Cairo version: 6a3c423

Current behavior:

Felt252DictDefault<T> (corelib/src/dict.cairo:208) is declared impl Felt252DictDefault<T> of Default<Felt252Dict<T>> with no trait bounds on T, and its body calls the unbounded extern felt252_dict_new<T>(). As a result, a function returning Felt252Dict<NonDictValue> via Default::default() passes the semantic layer even when the value type has no Felt252DictValue impl. The resulting dict is unusable — every other method requires +Felt252DictValue<T> (insert/get at lines 103–148, Destruct at line 224 which also requires +Drop<T>, and Index), so any actual use fires E2311 at the use site, but the construction itself type-checks.

Worse, cairo-compile panics (ICE) at crates/cairo-lang-sierra-generator/src/db.rs:370 when lowering the phantom function:

thread 'main' (837) panicked at crates/cairo-lang-sierra-generator/src/db.rs:370:9:
Got failure while specializing type `Felt252Dict<core::integer::u256>`:
Could not specialize type

This is a bound-asymmetry on the same type (Default = no bounds, insert/get = +Felt252DictValue, Destruct = +Drop +Felt252DictValue, Index = +DictTrait +Copy +Destruct<Entry>) combined with a sierra-gen panic on user-reachable code.

Expected behavior:

Felt252DictDefault<T> should carry the same +Felt252DictValue<T> bound that the rest of the Felt252Dict API enforces, so that Default::default() for Felt252Dict<T> is rejected at the construction site for value types that do not implement Felt252DictValue. The compiler should never ICE at sierra-gen on such code — it should report a normal type error instead of panicking with "Could not specialize type".

Steps to reproduce:

  1. Place the code below in a file (e.g. repro.cairo).
  2. Run cairo-test on it — it passes green: the phantom functions are dead code, so sierra-gen never lowers them and the semantic layer accepts the unbounded Default::default().
  3. Run cairo-compile --single-file repro.cairo /dev/null — it compiles everything in the file, reaches the unspecializable Felt252Dict<u256> type, and panics at db.rs:370.

Related code:

use core::dict::Felt252Dict;

fn make_phantom_dict_u256() -> Felt252Dict<u256> {
    Default::default()           // OK — Felt252DictDefault has no bounds
}

#[derive(Drop)]
struct NotDictValue { pub x: felt252 }

fn make_phantom_dict_user() -> Felt252Dict<NotDictValue> {
    Default::default()           // OK — same reason
}

#[test]
fn test_E93fe73() { assert!(1_u32 + 1_u32 == 2_u32); }

Other information:

  • Source of the missing bound: corelib/src/dict.cairo:208 (impl Felt252DictDefault<T> of Default<Felt252Dict<T>>, no bounds on T), whose body calls the unbounded extern felt252_dict_new<T>() at line 68. By contrast, Destruct at corelib/src/dict.cairo:224 is impl Felt252DictDestruct<T, +Drop<T>, +Felt252DictValue<T>>, and insert/get at lines 103–148 require +Felt252DictValue<T>.
  • Panic site: crates/cairo-lang-sierra-generator/src/db.rs:370.
  • The Cairo Book (ch03-02, https://www.starknet.io/cairo-book/ch03-02-dictionaries.html) states that Felt252Dict<T> only accepts the 8 Felt252DictValue types (u8/u16/u32/u64/u128/bool/felt252/Nullable), but does not note that Default::default() imposes no such bound at the construction site — the restriction is enforced only by Destruct and insert/get.
  • Suggested fix: add +Felt252DictValue<T> to Felt252DictDefault<T> so the bound is consistent across the dict API.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions