Skip to content

BEAM process crashes when enumerating keys of a nested empty map proxy #7

@andr-ec

Description

@andr-ec

Accessing a nested empty map from JavaScript via Object.keys or for...in crashes the entire BEAM process with a C assertion failure.

Reproduction

{:ok, rt} = QuickBEAM.start()
QuickBEAM.load_module(rt, "t", "globalThis.t = function(obj) { return Object.keys(obj.x).length; };")
QuickBEAM.call(rt, "t", [%{x: %{}}])  # crashes BEAM
beam.smp: quickjs.c:1626: void *js_malloc_rt(JSRuntime *, size_t): Assertion `size != 0' failed.
Aborted (core dumped)

Note: top-level empty maps work fine (QuickBEAM.call(rt, "t", [%{}])). The crash only occurs when the empty map is accessed as a nested property of another BEAM proxy object.

Root cause

beam_proxy.get_own_property_names in beam_proxy.zig:103-105 computes byte_size = total * @sizeOf(JSPropertyEnum) where total = map_size + override_count. For an empty map with no overrides, byte_size = 0, and js_malloc(ctx, 0) hits assert(size != 0) in QuickJS.

Top-level empty maps don't crash because QuickJS's JS_GetOwnPropertyNamesInternal uses max_int(atom_count, 1) before allocating. But when the BEAM proxy's exotic get_own_property_names handler is invoked through a nested property access path, it bypasses that guard.

Impact

This crashes any application using QuickBEAM for Vue SSR (via live_vue) when components receive empty maps as props — a common case (e.g. empty unread counts, empty reactions).

Environment

  • QuickBEAM 0.10.3
  • OTP 28.3.2
  • Elixir 1.19.5

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions