Skip to content

Emscripten / Binaryen miscompilation #1263

Closed
@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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions