Trouble mixing printf and MEMFS

120 views
Skip to first unread message

Dominic Mazzoni

unread,
Aug 1, 2017, 12:09:19 AM8/1/17
to emscripten-discuss
Hi - I'm having trouble mixing calls to printf (for logging/debugging) with reading and writing files from the built-in MEMFS. Hopefully I'm just doing something stupid - perhaps postRun is the wrong place to insert a function call?

I'm on Mac OS X 10.12.5, and I compiled emsdk from source according to the instructions at webassembly.org.

For my minimal repro, make a copy of emscripten/incoming/src/shell_minimal.html and modify the postRun line to be:

postRun: [function() { Module.ccall('wasm_init', null, []); }],

Then create a file hello.c like this:

#include <stdio.h>
#include <emscripten/emscripten.h>

int main(int argc, char ** argv) {
  printf("printf main\n");
  EM_ASM(Module.print("Module.print main"));
}

#ifdef __cplusplus
extern "C" {
#endif

int EMSCRIPTEN_KEEPALIVE wasm_init() {
  FILE* fp = fopen("test.txt", "w");
  printf("printf wasm_init\n");
  EM_ASM(Module.print("Module.print wasm_init"));
  return 0;
}

#ifdef __cplusplus
}
#endif

And compile it like this:

emcc hello.c -s WASM=1 -o hello.html --shell-file shell.html

What I get:

printf main
Module.print main
Module.print wasm_init

What I expect to get:

printf main
Module.print main
printf wasm_init
Module.print wasm_init

Important note: if I comment out the fopen line, it succeeds (the second printf works). If I use other mechanisms to log and debug, I can confirm that the fopen is succeeding - just somehow once I call fopen just once I can't use printf to write to Module.print anymore.

Thanks!

Jacob Gravelle

unread,
Aug 1, 2017, 2:41:20 PM8/1/17
to emscripten-discuss
I'm assuming you don't want to use postRun for a function named wasm_init? Of those hooks, you'd probably want to use preRun, which when I try it doesn't work with "Assertion failed: invalid handle for stdin (1)".

My understanding of why printf doesn't work there is because postRun is ran after main returns, so the wasm runtime doesn't flush the written buffer, and preRun is called before the runtime is initialized.
Looking at the timings in the run function (that calls Module['_main']) here: https://github.com/kripken/emscripten/blob/incoming/src/postamble.js#L222 , we want to run static initializers (that can print, at least) before we call main, but after the runtime is initialized. It looks like preMain is the right timing, but how to put callbacks there?
We have a function, addOnPreMain, that does the trick: https://github.com/kripken/emscripten/blob/incoming/src/preamble.js#L1693 . So to do that, we create a post-script file, shell_post.js, with the contents:
addOnPreMain(function() { Module.ccall('wasm_init', null, []); });

Then we compile with
emcc hello.c -s WASM=1 -o hello.html --shell-file shell.html --post-js shell_post.js

And our output is:
printf wasm_init
Module.print wasm_init
printf main
Module.print main

--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-disc...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Alon Zakai

unread,
Aug 1, 2017, 2:44:10 PM8/1/17
to emscripten-discuss
Yeah, I think the problem here is that the runtime is shut down (libc io streams are flushed and closed, etc.) after main() exits. If you build with -s NO_EXIT_RUNTIME=1 then it does print that out.

We have assertions on calling into the runtime after it was shut down, and those aren't being hit here, sadly - they should have shown an error message with how to fix things. Looks like the bug is that wasm async compilation goes around those assertions, which we should fix. I'll look into it.



On Tue, Aug 1, 2017 at 11:41 AM, 'Jacob Gravelle' via emscripten-discuss <emscripte...@googlegroups.com> wrote:
I'm assuming you don't want to use postRun for a function named wasm_init? Of those hooks, you'd probably want to use preRun, which when I try it doesn't work with "Assertion failed: invalid handle for stdin (1)".

My understanding of why printf doesn't work there is because postRun is ran after main returns, so the wasm runtime doesn't flush the written buffer, and preRun is called before the runtime is initialized.
Looking at the timings in the run function (that calls Module['_main']) here: https://github.com/kripken/emscripten/blob/incoming/src/postamble.js#L222 , we want to run static initializers (that can print, at least) before we call main, but after the runtime is initialized. It looks like preMain is the right timing, but how to put callbacks there?
We have a function, addOnPreMain, that does the trick: https://github.com/kripken/emscripten/blob/incoming/src/preamble.js#L1693 . So to do that, we create a post-script file, shell_post.js, with the contents:
addOnPreMain(function() { Module.ccall('wasm_init', null, []); });

Then we compile with
emcc hello.c -s WASM=1 -o hello.html --shell-file shell.html --post-js shell_post.js

And our output is:
printf wasm_init
Module.print wasm_init
printf main
Module.print main
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsub...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsub...@googlegroups.com.

Alon Zakai

unread,
Aug 1, 2017, 6:18:21 PM8/1/17
to emscripten-discuss

To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsubscribe@googlegroups.com.

Dominic Mazzoni

unread,
Aug 1, 2017, 6:39:10 PM8/1/17
to emscripten-discuss
Thanks, that makes sense! I definitely needed NO_EXIT_RUNTIME.

I misunderstood what postRun was for. Where should I add some JavaScript code that should run after main(), but before the runtime is shut down?


On Tue, Aug 1, 2017 at 3:18 PM Alon Zakai <alon...@gmail.com> wrote:
On Tue, Aug 1, 2017 at 11:44 AM, Alon Zakai <alon...@gmail.com> wrote:
Yeah, I think the problem here is that the runtime is shut down (libc io streams are flushed and closed, etc.) after main() exits. If you build with -s NO_EXIT_RUNTIME=1 then it does print that out.

We have assertions on calling into the runtime after it was shut down, and those aren't being hit here, sadly - they should have shown an error message with how to fix things. Looks like the bug is that wasm async compilation goes around those assertions, which we should fix. I'll look into it.


On Tue, Aug 1, 2017 at 11:41 AM, 'Jacob Gravelle' via emscripten-discuss <emscripte...@googlegroups.com> wrote:
I'm assuming you don't want to use postRun for a function named wasm_init? Of those hooks, you'd probably want to use preRun, which when I try it doesn't work with "Assertion failed: invalid handle for stdin (1)".

My understanding of why printf doesn't work there is because postRun is ran after main returns, so the wasm runtime doesn't flush the written buffer, and preRun is called before the runtime is initialized.
Looking at the timings in the run function (that calls Module['_main']) here: https://github.com/kripken/emscripten/blob/incoming/src/postamble.js#L222 , we want to run static initializers (that can print, at least) before we call main, but after the runtime is initialized. It looks like preMain is the right timing, but how to put callbacks there?
We have a function, addOnPreMain, that does the trick: https://github.com/kripken/emscripten/blob/incoming/src/preamble.js#L1693 . So to do that, we create a post-script file, shell_post.js, with the contents:
addOnPreMain(function() { Module.ccall('wasm_init', null, []); });

Then we compile with
emcc hello.c -s WASM=1 -o hello.html --shell-file shell.html --post-js shell_post.js

And our output is:
printf wasm_init
Module.print wasm_init
printf main
Module.print main
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-disc...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-disc...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-disc...@googlegroups.com.

Dominic Mazzoni

unread,
Aug 1, 2017, 6:45:17 PM8/1/17
to emscripten-discuss
Actually, I just found this section of the FAQ, which answers my question: How can I tell when the page is fully loaded and it is safe to call compiled functions?

Thanks again for the help. I'll post again if I'm still stuck on anything related to this.

Reply all
Reply to author
Forward
0 new messages