Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Line buffering issue with stdout #102

Closed
MarkMcCaskey opened this issue Oct 2, 2019 · 2 comments
Closed

Line buffering issue with stdout #102

MarkMcCaskey opened this issue Oct 2, 2019 · 2 comments

Comments

@MarkMcCaskey
Copy link

MarkMcCaskey commented Oct 2, 2019

Hello!

I have some C code that I'm compiling with clang 8.0 and a sysroot compiled from master.

int print_random_number_of_length(int size)
{
        //setbuf(stdout, NULL);
        char* before = "before";
        host_print(before, strlen(before));

        puts("ABC\n ");
        printf("FOUND SIZE %d\n", size);
        printf("FOUND SIZE %d\n", size);
        printf("defg\n");
        while (size > 0) {
                int digit = random() % 10;
                putchar(digit + '0');
                --size;
        }

        printf("\n");
        //fflush(stdout);
        char* after = "after";
        host_print(after, strlen(after));
        return 0;
}

And here's a trace:

PRINTING FROM THE HOST: "before"
PRINTING FROM THE HOST: "after"
<call to wasi::fd_write: fd=1>
ABC
 
FOUND SIZE 2
FOUND SIZE 2
defg
75

There are a number of things going on here:

  • The host call, host_print prints the string using printf with a terminating new line.
  • clang changes calls to printf with a static string into calls to puts
  • wasi::fd_write is only called once; this is not a buffering issue in the runtime
  • writes to stdout are buffered despite new lines: notice that the host calls come before the other prints. Additionally, I've verified that it hasn't reordered the print statements in the generated Wasm.
  • stdout seems to be correctly set to be line buffered: https://github.com/CraneStation/wasi-libc/blob/master/libc-top-half/musl/src/stdio/stdout.c#L11

The following things make it work correctly:

  • uncommenting the fflush(stdout)
  • uncommenting setbuf(stdout, NULL);
  • passing in an argument large enough that about 1000 bytes are written

I spent some time looking into this, but ran into some issues and didn't want to spend too much time on this before asking for help.

I'm happy to fix this and submit a patch, but I got a bit lost in the code and print statements weren't working in all the places I'd like them to to quickly debug the issue. I'd really appreciate any pointers in the right direction you all can give!

edit:

I'm using clang source.c -Os -o wasi_example.wasm --target=wasm32-wasi -Wl,--allow-undefined -Wl,--export-all to compile in case that helps.

@mikevoronov
Copy link
Contributor

mikevoronov commented Oct 21, 2019

I am just guessing, but as far as I know, in musl line-buffered (lbf = '\n') or non-buffered mode (lbf = -1) is completely depend on a type of the stdout device. So, for terminals it is enabled by default, but for other it is implementation specific and musl mainteiners recommend to explicitly set it. Then it seems that in WASI it is determined by __isatty function (here and here).

In its turn, __isatty uses __wasi_fd_fdstat_get to check that file has __WASI_FILETYPE_CHARACTER_DEVICE type. But Wasmer doesn't return this type of device. So probably the issue could be in this fact. But it is just my guess and it is difficult to answer without full source code. You can check it by debugging __wasi_fd_fdstat_get in Wasmer.

@MarkMcCaskey
Copy link
Author

@michaelvoronov Thank you! That's extremely helpful! It looks like this probably isn't a bug in wasi-libc then, sorry about the noise!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants