wasi-sdk
wasi-sdk copied to clipboard
`std::cout` is not initialized when used in the constructor of a global static variable.
When compiling and running the followig code:
// global_ctor.cpp
#include <iostream>
struct S
{
S()
{
std::cout << "Go.\n";
}
};
static S s;
int main() {}
clang++ --target=wasm32-unknown-wasi --sysroot=/path/to/wasi/sysroot/ global_ctor.cpp -o global_ctor-wasi
wasmtime -- ./global_ctor-wasi
The following error occurs:
Error: failed to run main module `./global_ctor-wasi`
Caused by:
0: failed to invoke command default
1: wasm trap: out of bounds memory access
wasm backtrace:
0: 0x52e9 - <unknown>!std::__2::basic_ostream<char, std::__2::char_traits<char> >::sentry::sentry(std::__2::basic_ostream<char, std::__2::char_traits<char> >&)
1: 0xd40 - <unknown>!std::__2::basic_ostream<char, std::__2::char_traits<char> >& std::__2::__put_character_sequence<char, std::__2::char_traits<char> >(std::__2::basic_ostream<char, std::__2::char_traits<char> >&, char const*, unsigned long)
2: 0xc78 - <unknown>!std::__2::basic_ostream<char, std::__2::char_traits<char> >& std::__2::operator<<<std::__2::char_traits<char> >(std::__2::basic_ostream<char, std::__2::char_traits<char> >&, char const*)
3: 0xc08 - <unknown>!S::S()
4: 0xbbe - <unknown>!__cxx_global_var_init
5: 0x1f60 - <unknown>!_GLOBAL__sub_I_global_ctor.cpp
6: 0xb7c - <unknown>!__wasm_call_ctors
7: 0xb8a - <unknown>!_start
It seems that std::cout
is not initialized at the time it is used, when constructing static S s
.
According to the C++ standard, paragraph 3 of [iostream.objects.overview] (where "the objects" refers to std::cout
and co., emphasis of mine):
The objects are constructed and the associations are established at some time prior to or during the first time an object of class
ios_base::Init
is constructed, and in any case before the body of main begins execution. The objects are not destroyed during program execution. The results of including<iostream>
in a translation unit shall be as if<iostream>
defined an instance ofios_base::Init
with static storage duration.
And according to [basic.start.dynamic]
, objects with static storage duration in the same compilation unit should be initialized in the order they appear; thus ios_base::Init
before S s
.
A workaround is to explicitly declare an std::ios_base::Init
before using std::cout
:
S()
{
std::ios_base::Init init;
std::cout << "Go.\n";
}
Thanks for the report, this is indeed a bug! It appears that this is an instance of https://bugs.llvm.org/show_bug.cgi?id=28954 .
Another workaround is to add -lc++
to the command-line, before any of your own source/object files.
I also have a patch to upstream the fix we made in emscripten: https://reviews.llvm.org/D74885
@sbc100 Is there an update on the status of that patch?
No really, I guess we should push on it?
Looks like we are moving forward with https://reviews.llvm.org/D31413. I'm hoping we even get it into llvm 11 which is about to be released.
Awesome, thanks!
This issue should be fixed with https://reviews.llvm.org/D31413 (by commit https://github.com/llvm/llvm-project/commit/39faf428164a28f3652370958ce893d9200927c8). I'll see if we can cherry-pick to LLVM 11.
This issue is still present in wasi-sdk 14d7b78. Confirming the effectiveness of the @j-jorge's workaround.
@ldionne Do you know if https://reviews.llvm.org/D31413 was cherry-picked into LLVM 11?
Either way, https://github.com/WebAssembly/wasi-sdk/pull/178 updates wasi-sdk to LLVM 12, which will hopefully resolve this.
@sunfishcode The commit is:
commit 39faf428164a28f3652370958ce893d9200927c8
Author: Louis Dionne <[email protected]>
Date: Thu May 14 09:56:35 2020 -0400
[libc++] Ensure streams are initialized early
When statically linking libc++ on some systems, the streams are not
initialized early enough, which causes all kinds of issues. This was
reported e.g. in http://llvm.org/PR28954, but also in various open
source projects that use libc++.
Fixes http://llvm.org/PR28954.
Differential Revision: https://reviews.llvm.org/D31413
I think it was only included in LLVM 12.
Either way, #178 updates wasi-sdk to LLVM 12, which will hopefully resolve this.
I can confirm that it is resolved in LLVM v12.