Skip to content

[Bug] Heap corruption when host calls execute at AssemblyScript module-init time #6559

@nkuba

Description

@nkuba

Bug report

Summary

When a subgraph's AssemblyScript code invokes graph-ts host-call helpers (e.g. Address.fromString, Bytes.fromHexString) at module-initialization time via top-level const declarations, the graph-node wasm runtime ends up in a corrupted heap state. The corruption is silent until some unrelated handler later in the same subgraph.yaml reads an AscString, at which point graph-node throws:

Attempted to read past end of string content bytes chunk

(thrown from runtime/wasm/src/asc_abi/v0_0_5.rs#L234)

After retries this also surfaces as the related cascade error in InputSchema::entity_type with an empty/garbled name (internal error: unknown name when looking up entity type), because subsequent host calls receive corrupted AscString pointers.

Reproducer

Minimal handler module:

import { Address, Bytes } from "@graphprotocol/graph-ts"
import { Pool } from "../generated/schema"                                                                                                                
  
// These two top-level consts trigger the corruption.                                                                                                     
export const ADDR = Address.fromString("0xd97576d5fed11c7c31095d4fd0af612dc736679b")
export const TOPIC = Bytes.fromHexString("0xaa2dd386ed08047486db39ea1a9e5461b6a95c8bb3ca845cce27a537799a4672")                                            
                                                                                                                                                          
export function handleAnything(/* … */): void {                                                                                                           
  // Any handler that does store.get / store.set later traps with the AscString error,                                                                    
  // even with hardcoded literal arguments:                          
  Pool.load("0x525f049a4494da0a6c87e3c4df55f9929765dc3e")                                                                                                 
}

Workaround

Wrap the host calls in functions and invoke them lazily inside handlers:

function addr(): Address {                                                                                                                                
  return Address.fromString("0xd97576d5fed11c7c31095d4fd0af612dc736679b")
}                                                                                                                                                         
function topic(): Bytes {
  return Bytes.fromHexString("0xaa2dd386ed08047486db39ea1a9e5461b6a95c8bb3ca845cce27a537799a4672")                                                        
}                                                                                                                                                         

Once these are not evaluated at module load, all handlers run cleanly.

Environment

  • graph-node: graphprotocol/graph-node:latest (pulled 2026-05-05; also reproduced on a Goldsky-hosted deployment)
  • graph-cli: tested both 0.96.0 and 0.98.1 (both reproduce)
  • graph-ts: 0.37.0
  • apiVersion: 0.0.9
  • specVersion: 1.3.0
  • Chain: Mezo testnet (EVM). Reproducer transaction: 0xf06b7d247d24a43f86c1f2fc32c7627c1d484e950870465daeca714b37e3fa2d at block 5561094.

Why I believe this is graph-node, not the mapping

  • The wasm only imports store.get, store.set, ethereum.call, log.log, and typeConversion.* (verified via wasm-objdump).
  • All entity-type strings passed to store.get are hardcoded by the graph-cli codegen — they cannot be empty.
  • The trap message comes from graph-node's AscString::from_asc_bytes walking UTF-16LE byte pairs, implying the AscPtr<AscString> it reads has an
    odd byte length — i.e. the AS heap is in a state graph-node doesn't expect.
  • The bug disappears with no other code change when the offending host calls are deferred out of module-init.

Relevant log output

IPFS hash

No response

Subgraph name or link to explorer

No response

Some information to help us out

  • Tick this box if this bug is caused by a regression found in the latest release.
  • Tick this box if this bug is specific to the hosted service.
  • I have searched the issue tracker to make sure this issue is not a duplicate.

OS information

None

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