diff --git a/src/support/file.cpp b/src/support/file.cpp index 08b9e31af91..be06980d591 100644 --- a/src/support/file.cpp +++ b/src/support/file.cpp @@ -135,3 +135,23 @@ size_t wasm::file_size(std::string filename) { std::ifstream::ate | std::ifstream::binary); return infile.tellg(); } + +void wasm::flush_and_quick_exit(int code) { + // We expect C++ files to be flushed by their destructors already. Flush the + // standard streams manually. + std::cout << std::flush; + std::cerr << std::flush; + + // To be safe, also flush at the C level. + fflush(NULL); + +#if __has_feature(address_sanitizer) || __has_feature(thread_sanitizer) || \ + __has_feature(memory_sanitizer) || __has_feature(leak_sanitizer) || \ + __has_feature(undefined_behavior_sanitizer) + // Avoid quick_exit when using sanitizers, so that leak checks and other + // things can run during shutdown normally. + std::exit(code); +#else + std::quick_exit(code); +#endif +} diff --git a/src/support/file.h b/src/support/file.h index ae91831c98f..0726417285f 100644 --- a/src/support/file.h +++ b/src/support/file.h @@ -72,9 +72,15 @@ class Output { // Copies a file to another file void copy_file(std::string input, std::string output); -// Retusn the size of a file +// Return the size of a file size_t file_size(std::string filename); +// Flush stdout and stderr, and quickly exit. This assumes that all files that +// need flushing have been flushed, that is, no global ctors or RAII in main's +// top level are depended on (using quick_exit then avoids running global dtors, +// which saves otherwise wasted time). +[[noreturn]] void flush_and_quick_exit(int code); + } // namespace wasm #endif // wasm_support_file_h diff --git a/src/tools/wasm-as.cpp b/src/tools/wasm-as.cpp index 8d0dbd6495b..3eabdef3120 100644 --- a/src/tools/wasm-as.cpp +++ b/src/tools/wasm-as.cpp @@ -131,19 +131,25 @@ int main(int argc, const char* argv[]) { if (options.debug) { std::cerr << "writing..." << std::endl; } - ModuleWriter writer(options.passOptions); - writer.setBinary(true); - writer.setDebugInfo(debugInfo); - if (sourceMapFilename.size()) { - writer.setSourceMapFilename(sourceMapFilename); - writer.setSourceMapUrl(sourceMapUrl); - } - if (symbolMap.size() > 0) { - writer.setSymbolMap(symbolMap); + + // Ensure the destructor of ModuleWriter runs before quick_exit. + { + ModuleWriter writer(options.passOptions); + writer.setBinary(true); + writer.setDebugInfo(debugInfo); + if (sourceMapFilename.size()) { + writer.setSourceMapFilename(sourceMapFilename); + writer.setSourceMapUrl(sourceMapUrl); + } + if (symbolMap.size() > 0) { + writer.setSymbolMap(symbolMap); + } + writer.write(wasm, options.extra["output"]); } - writer.write(wasm, options.extra["output"]); if (options.debug) { std::cerr << "Done." << std::endl; } + + flush_and_quick_exit(0); } diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 1407682faf9..fae516d8f6a 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -1618,4 +1618,6 @@ int main(int argc, const char* argv[]) { writer.setDebugInfo(debugInfo); writer.write(wasm, options.extra["output"]); } + + flush_and_quick_exit(0); } diff --git a/src/tools/wasm-dis.cpp b/src/tools/wasm-dis.cpp index be3e7bd10d9..d69cc1f96cc 100644 --- a/src/tools/wasm-dis.cpp +++ b/src/tools/wasm-dis.cpp @@ -98,10 +98,16 @@ int main(int argc, const char* argv[]) { if (options.debug) { std::cerr << "Printing..." << std::endl; } - Output output(options.extra["output"], Flags::Text); - output.getStream() << wasm << '\n'; + + // Ensure the destructor of Output runs before quick_exit. + { + Output output(options.extra["output"], Flags::Text); + output.getStream() << wasm << '\n'; + } if (options.debug) { std::cerr << "Done." << std::endl; } + + flush_and_quick_exit(0); } diff --git a/src/tools/wasm-emscripten-finalize.cpp b/src/tools/wasm-emscripten-finalize.cpp index 53e3be196dc..7ab7fd55cff 100644 --- a/src/tools/wasm-emscripten-finalize.cpp +++ b/src/tools/wasm-emscripten-finalize.cpp @@ -289,5 +289,6 @@ int main(int argc, const char* argv[]) { } writer.write(wasm, output); } - return 0; + + flush_and_quick_exit(0); } diff --git a/src/tools/wasm-merge.cpp b/src/tools/wasm-merge.cpp index d9a991a58cc..3c354f745bf 100644 --- a/src/tools/wasm-merge.cpp +++ b/src/tools/wasm-merge.cpp @@ -832,4 +832,6 @@ Input source maps can be specified by adding an -ism option right after the modu } writer.write(merged, options.extra["output"]); } + + flush_and_quick_exit(0); } diff --git a/src/tools/wasm-metadce.cpp b/src/tools/wasm-metadce.cpp index b677e575abf..299cb2f63c9 100644 --- a/src/tools/wasm-metadce.cpp +++ b/src/tools/wasm-metadce.cpp @@ -674,4 +674,6 @@ int main(int argc, const char* argv[]) { // Clean up free(copy); + + flush_and_quick_exit(0); } diff --git a/src/tools/wasm-opt.cpp b/src/tools/wasm-opt.cpp index 310544c9451..d3ba797a674 100644 --- a/src/tools/wasm-opt.cpp +++ b/src/tools/wasm-opt.cpp @@ -476,18 +476,23 @@ For more on how to optimize effectively, see std::cerr << "warning: no output file specified, not emitting output\n"; } } + + flush_and_quick_exit(0); return 0; } - BYN_TRACE("writing...\n"); - ModuleWriter writer(options.passOptions); - writer.setBinary(emitBinary); - writer.setDebugInfo(options.passOptions.debugInfo); - if (outputSourceMapFilename.size()) { - writer.setSourceMapFilename(outputSourceMapFilename); - writer.setSourceMapUrl(outputSourceMapUrl); + // Ensure the destructor of ModuleWriter runs before quick_exit. + { + BYN_TRACE("writing...\n"); + ModuleWriter writer(options.passOptions); + writer.setBinary(emitBinary); + writer.setDebugInfo(options.passOptions.debugInfo); + if (outputSourceMapFilename.size()) { + writer.setSourceMapFilename(outputSourceMapFilename); + writer.setSourceMapUrl(outputSourceMapUrl); + } + writer.write(wasm, options.extra["output"]); } - writer.write(wasm, options.extra["output"]); if (extraFuzzCommand.size() > 0) { auto secondOutput = runCommand(extraFuzzCommand); @@ -496,5 +501,6 @@ For more on how to optimize effectively, see Fatal() << "extra fuzz command output differs\n"; } } - return 0; + + flush_and_quick_exit(0); } diff --git a/src/tools/wasm-shell.cpp b/src/tools/wasm-shell.cpp index 046bb33cecd..2750f9d0b1e 100644 --- a/src/tools/wasm-shell.cpp +++ b/src/tools/wasm-shell.cpp @@ -603,4 +603,6 @@ int main(int argc, const char* argv[]) { Colors::bold(std::cerr); std::cerr << "all checks passed.\n"; Colors::normal(std::cerr); + + flush_and_quick_exit(0); } diff --git a/src/tools/wasm2js.cpp b/src/tools/wasm2js.cpp index c6277c6c30f..94faf43c821 100644 --- a/src/tools/wasm2js.cpp +++ b/src/tools/wasm2js.cpp @@ -993,14 +993,20 @@ int main(int argc, const char* argv[]) { if (options.debug) { std::cerr << "j-printing..." << std::endl; } - Output output(options.extra["output"], Flags::Text); - if (script && options.extra["asserts"] == "1") { - AssertionEmitter(*script, output, flags, options).emit(); - } else { - emitWasm(*wasm, output, flags, options.passOptions, "asmFunc"); + + // Ensure the destructor of Output runs before quick_exit. + { + Output output(options.extra["output"], Flags::Text); + if (script && options.extra["asserts"] == "1") { + AssertionEmitter(*script, output, flags, options).emit(); + } else { + emitWasm(*wasm, output, flags, options.passOptions, "asmFunc"); + } } if (options.debug) { std::cerr << "done." << std::endl; } + + flush_and_quick_exit(0); }