Skip to content

Reflected Array.filter rereads source values after the predicate changes them #224

Closed

Description

@dimensionscape

Calling Array.filter through reflection can produce different elements from a direct call when the predicate replaces the current source element. The reflected native path reads the source slot again after the predicate returns instead of retaining the value that was passed to it.

Regression coverage first: test/regression/ArrayFilterMutation, using Main.hx/build.hxml/stdout.txt. Start with [1,2,3]. The predicate replaces values[value - 1] with value * 10 and returns true. Run once as values.filter(predicate) and once through Reflect.field(values, "filter"). Verify that both result arrays contain the original predicate inputs [1,2,3], while both source arrays become [10,20,30].

Confirmed on Linux x86_64 with Haxe 4.3.3:

source: 10,20,30
filtered: 1,2,3
reflected source: 10,20,30
reflected filtered: 10,20,30

Haxe Eval returns reflected filtered: 1,2,3 for the same program. The direct cpp call also returns that result, so this is a disagreement between call paths on the native target itself.

Array_obj<ELEM_>::filter in include/Array.h calls inFunc(__unsafe_get(i)), then calls result->push(__unsafe_get(i)) if the predicate accepts. A callback can change the slot between those two reads. Cache the original element before invoking the callback and append that accepted value. Ensure GC visibility for cached pointer-bearing values if the predicate allocates or collects.

Extend coverage to object elements, Dynamic arrays and source resizing during callbacks. The regression above only replaces slots and does not depend on unspecified behavior from appending indefinitely or removing future elements.

No runtime implementation changes are included.

Activity

  1. added a commit that references this issue on Oct 20, 2026
    7792a9c
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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions