Skip to content

Tolk: CTFE folds null as T? to raw TVM null, losing required nullable/union transitions (crash / wrong value) #2050

@Gusarich

Description

@Gusarich

Constant folding of the as operator can drop the target type when casting null to a nullable/union type (null as T?). The CTFE path embeds a raw TVM null without applying the type-directed runtime transition that the non-const path performs. This can:

  • crash the compiler for wide nullable unions (stack-width mismatch), and
  • miscompile nullable empty types by producing TVM null instead of the tagged 0 representation.

Reproduction 1: compiler crash (null as (int,int)?)

Create /tmp/tolk_ctfe_null_as_wide_union_crash.tolk:

tolk 1.0

const X: (int, int)? = (null as (int, int)?);

fun onInternalMessage(msgCell: cell, msgBody: slice) {}

Compile:

./artifacts/tolk /tmp/tolk_ctfe_null_as_wide_union_crash.tolk > /tmp/out.fif

Observed:

fatal: Assertion failed at tolk/pipe-ast-to-legacy.cpp:1212:
static_cast<int>(ir_init.size()) == const_ref->init_value->inferred_type->get_width_on_stack()

Reproduction 2: wrong runtime representation (null as Empty?)

Create /tmp/tolk_ctfe_null_as_empty_nullable_shape.tolk:

tolk 1.0

struct Empty {}

const X: Empty? = (null as Empty?);

fun onInternalMessage(msgCell: cell, msgBody: slice) {}

@method_id(100)
fun get_const_x(): Empty? {
    return X;
}

@method_id(101)
fun get_runtime_x(): Empty? {
    var y: Empty? = (null as Empty?);
    return y;
}

Compile:

./artifacts/tolk /tmp/tolk_ctfe_null_as_empty_nullable_shape.tolk > /tmp/tolk_ctfe_null_as_empty_nullable_shape.fif

Create /tmp/tolk_ctfe_null_as_empty_nullable_shape_runner.fif:

"/tmp/tolk_ctfe_null_as_empty_nullable_shape.fif" include <s constant code
100 code 1 runvmx abort"exitcode is not 0" .s cr { drop } depth 1- times
101 code 1 runvmx abort"exitcode is not 0" .s cr { drop } depth 1- times

Run:

./artifacts/fift -I artifacts/lib /tmp/tolk_ctfe_null_as_empty_nullable_shape_runner.fif

Observed output:

(null)   // get_const_x()
0        // get_runtime_x()

Expected behavior

Const folding of null as T? should preserve the same type-directed runtime representation as the non-const path and must not crash the compiler.

Metadata

Metadata

Assignees

No one assigned

    Labels

    TolkRelated to Tolk Language / compiler / toolingllm-fuzzing

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions