Skip to content

Emscripten / Binaryen miscompilation #1263

@kumpera

Description

@kumpera

While trying to compile mono, emscripten + binaryen miscompiles the following function:

static inline void
sgen_dummy_use (gpointer v)
{
#if defined(__GNUC__)
	__asm__ volatile ("" : "=r"(v) : "r"(v));
#elif defined(_MSC_VER)
	static volatile gpointer ptr;
	ptr = v;
#else
#error "Implement sgen_dummy_use for your compiler"
#endif
}

I'm using emsdk with the following installed:

emscripten-1.37.22
clang-e1.37.22-64bit
node-4.1.1-64bit

I'm running the compiler this way:

$(EMCC) -g4 -Os -s WASM=1 -s ALLOW_MEMORY_GROWTH=1 -s BINARYEN=1 -s "BINARYEN_TRAP_MODE='clamp'" -s TOTAL_MEMORY=134217728 -s ALIASING_FUNCTION_POINTERS=0 --js-library library_mono.js driver.o $(TOP)/sdks/out/wasm-interp/lib/libmonosgen-2.0.a -o mono.js

It crashes when linking in asm2wasm with this assert:

$3
Assertion failed: (mappedGlobals.find(name) != mappedGlobals.end() ? true : (std::cerr << name.str << '\n', false)), function operator(), file /Users/kumpera/src/wasm/mono/sdks/builds/toolchains/emsdk/binaryen/master/src/asm2wasm.h, line 1544.

I dug into binaryen and this was the backtrace:

* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
    frame #0: 0x000000010c329246 asm2wasm`wasm::Asm2WasmBuilder::processFunction(this=0x00007fb0e7d2f028, ast=Ref @ 0x00007ffee3950418)::$_3::operator()(cashew::Ref) const at asm2wasm.h:1546
    frame #1: 0x000000010c328a68 asm2wasm`wasm::Expression* std::__1::__invoke_void_return_wrapper<wasm::Expression*>::__call<wasm::Asm2WasmBuilder::processFunction(cashew::Ref)::$_3&, cashew::Ref>(wasm::Asm2WasmBuilder::processFunction(cashew::Ref)::$_3&&&, cashew::Ref&&) [inlined] decltype(__f=0x00007fb0e7d2f028, __args=0x00007ffee3952430)::$_3&>(fp)(std::__1::forward<cashew::Ref>(fp0))) std::__1::__invoke<wasm::Asm2WasmBuilder::processFunction(cashew::Ref)::$_3&, cashew::Ref>(wasm::Asm2WasmBuilder::processFunction(cashew::Ref)::$_3&&&, cashew::Ref&&) at type_traits:4291
    frame #2: 0x000000010c328a40 asm2wasm`wasm::Expression* std::__1::__invoke_void_return_wrapper<wasm::Expression*>::__call<wasm::Asm2WasmBuilder::processFunction(__args=0x00007fb0e7d2f028, __args=0x00007ffee3952430)::$_3&, cashew::Ref>(wasm::Asm2WasmBuilder::processFunction(cashew::Ref)::$_3&&&, cashew::Ref&&) at __functional_base:328
    frame #3: 0x000000010c328909 asm2wasm`std::__1::__function::__func<wasm::Asm2WasmBuilder::processFunction(cashew::Ref)::$_3, std::__1::allocator<wasm::Asm2WasmBuilder::processFunction(cashew::Ref)::$_3>, wasm::Expression* (cashew::Ref)>::operator(this=0x00007fb0e7d2f020, __arg=0x00007ffee3952430)(cashew::Ref&&) at functional:1552
    frame #4: 0x000000010c33c0d9 asm2wasm`std::__1::function<wasm::Expression* (cashew::Ref)>::operator(this=0x00007fb0e7d2f020, __arg=Ref @ 0x00007ffee3952430)(cashew::Ref) const at functional:1911
    frame #5: 0x000000010c3304b5 asm2wasm`wasm::Asm2WasmBuilder::processFunction(this=0x00007fb0e7d2f028, ast=Ref @ 0x00007ffee3955d08)::$_3::operator()(cashew::Ref) const at asm2wasm.h:1945
    frame #6: 0x000000010c328a68 asm2wasm`wasm::Expression* std::__1::__invoke_void_return_wrapper<wasm::Expression*>::__call<wasm::Asm2WasmBuilder::processFunction(cashew::Ref)::$_3&, cashew::Ref>(wasm::Asm2WasmBuilder::processFunction(cashew::Ref)::$_3&&&, cashew::Ref&&) [inlined] decltype(__f=0x00007fb0e7d2f028, __args=0x00007ffee3957d20)::$_3&>(fp)(std::__1::forward<cashew::Ref>(fp0))) std::__1::__invoke<wasm::Asm2WasmBuilder::processFunction(cashew::Ref)::$_3&, cashew::Ref>(wasm::Asm2WasmBuilder::processFunction(cashew::Ref)::$_3&&&, cashew::Ref&&) at type_traits:4291
    frame #7: 0x000000010c328a40 asm2wasm`wasm::Expression* std::__1::__invoke_void_return_wrapper<wasm::Expression*>::__call<wasm::Asm2WasmBuilder::processFunction(__args=0x00007fb0e7d2f028, __args=0x00007ffee3957d20)::$_3&, cashew::Ref>(wasm::Asm2WasmBuilder::processFunction(cashew::Ref)::$_3&&&, cashew::Ref&&) at __functional_base:328
    frame #8: 0x000000010c328909 asm2wasm`std::__1::__function::__func<wasm::Asm2WasmBuilder::processFunction(cashew::Ref)::$_3, std::__1::allocator<wasm::Asm2WasmBuilder::processFunction(cashew::Ref)::$_3>, wasm::Expression* (cashew::Ref)>::operator(this=0x00007fb0e7d2f020, __arg=0x00007ffee3957d20)(cashew::Ref&&) at functional:1552
    frame #9: 0x000000010c33c0d9 asm2wasm`std::__1::function<wasm::Expression* (cashew::Ref)>::operator(this=0x00007fb0e7d2f020, __arg=Ref @ 0x00007ffee3957d20)(cashew::Ref) const at functional:1911
    frame #10: 0x000000010c3518e8 asm2wasm`wasm::Asm2WasmBuilder::processFunction(this=0x00007ffee3959508, ast=Ref @ 0x00007ffee3957da0, from=2)::$_5::operator()(cashew::Ref, unsigned int) const at asm2wasm.h:2612
    frame #11: 0x000000010c3517ca asm2wasm`wasm::Expression* std::__1::__invoke_void_return_wrapper<wasm::Expression*>::__call<wasm::Asm2WasmBuilder::processFunction(cashew::Ref)::$_5&, cashew::Ref, unsigned int>(wasm::Asm2WasmBuilder::processFunction(cashew::Ref)::$_5&&&, cashew::Ref&&, unsigned int&&) [inlined] decltype(__f=0x00007ffee3959508, __args=0x00007ffee3957ec8, __args=0x00007ffee3957ebc)::$_5&>(fp)(std::__1::forward<cashew::Ref, unsigned int>(fp0))) std::__1::__invoke<wasm::Asm2WasmBuilder::processFunction(cashew::Ref)::$_5&, cashew::Ref, unsigned int>(wasm::Asm2WasmBuilder::processFunction(cashew::Ref)::$_5&&&, cashew::Ref&&, unsigned int&&) at type_traits:4291
    frame #12: 0x000000010c351794 asm2wasm`wasm::Expression* std::__1::__invoke_void_return_wrapper<wasm::Expression*>::__call<wasm::Asm2WasmBuilder::processFunction(__args=0x00007ffee3959508, __args=0x00007ffee3957ec8, __args=0x00007ffee3957ebc)::$_5&, cashew::Ref, unsigned int>(wasm::Asm2WasmBuilder::processFunction(cashew::Ref)::$_5&&&, cashew::Ref&&, unsigned int&&) at __functional_base:328
    frame #13: 0x000000010c351699 asm2wasm`std::__1::__function::__func<wasm::Asm2WasmBuilder::processFunction(cashew::Ref)::$_5, std::__1::allocator<wasm::Asm2WasmBuilder::processFunction(cashew::Ref)::$_5>, wasm::Expression* (cashew::Ref, unsigned int)>::operator(this=0x00007ffee3959500, __arg=0x00007ffee3957ec8, __arg=0x00007ffee3957ebc)(cashew::Ref&&, unsigned int&&) at functional:1552
    frame #14: 0x000000010c2b07e8 asm2wasm`std::__1::function<wasm::Expression* (cashew::Ref, unsigned int)>::operator(this=0x00007ffee3959500, __arg=Ref @ 0x00007ffee3957ec8, __arg=2)(cashew::Ref, unsigned int) const at functional:1911
  * frame #15: 0x000000010c2adae7 asm2wasm`wasm::Asm2WasmBuilder::processFunction(this=0x00007ffee395bb20, ast=Ref @ 0x00007ffee39585d8) at asm2wasm.h:2618
    frame #16: 0x000000010c2a4aaa asm2wasm`wasm::Asm2WasmBuilder::processAsm(this=0x00007ffee395bb20, ast=Ref @ 0x00007ffee395a1a0) at asm2wasm.h:1032
    frame #17: 0x000000010c2b55af asm2wasm`main(argc=12, argv=0x00007ffee395e5b0) at asm2wasm.cpp:164

I inspected the bottom processFunction frame, which is how I found out what was the offending function and took the change to call dump on the body. I got this:

foo: [
  ["$0", [
    "binary",
    "|",
    "$0",
    0
  ]],
  [
    "var",
    [
      [
        "$1",
        0
      ],
      [
        "$2",
        0
      ],
      [
        "label",
        0
      ],
      [
        "sp",
        0
      ]
    ]
  ],
  ["sp", "STACKTOP"],
  ["STACKTOP", [
    "binary",
    "|",
    [
      "binary",
      "+",
      "STACKTOP",
      16
    ],
    0
  ]],
  ["$1", "sp"],
  [
    "call",
    "store4",
    [
      "$1",
      "$0"
    ]
  ],
  ["$2", [
    "call",
    "load4",
    [
      "$1"
    ]
  ]],
  [
    "call",
    "emscripten_debuginfo",
    [
      88,
      1142
    ]
  ],
  [
    "call",
    "emscripten_debuginfo",
    [
      88,
      1142
    ]
  ],
  [
    "call",
    "store4",
    [
      "$1",
      "$3"
    ]
  ],
  [
    "call",
    "emscripten_debuginfo",
    [
      88,
      1142
    ]
  ],
  ["STACKTOP", "sp"],
  [
    "return",
    null
  ],
  [
    "call",
    "emscripten_debuginfo",
    [
      88,
      1149
    ]
  ]
]

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