4 ms·
Let's look at the source: https://git.musl-libc.org/cgit/musl/tree/src/stdio/vsscanf.c https://git.musl-libc.org/cgit/musl/tree/src/stdio/vsscanf.c It fills in
by Jasper_ 6y ago
Let's look at the source: https://git.musl-libc.org/cgit/musl/tree/src/stdio/vsscanf.c https://git.musl-libc.org/cgit/musl/tree/src/stdio/vsscanf.c
It fills in a buf with a string_read callback, but if we look at what vfscanf does, it uses shgetc, which eventually calls into __uflow, which is where the read is performed:
https://git.musl-libc.org/cgit/musl/tree/src/stdio/vfscanf.c https://git.musl-libc.org/cgit/musl/tree/src/stdio/vfscanf.c
https://git.musl-libc.org/cgit/musl/tree/src/internal/shgetc.c https://git.musl-libc.org/cgit/musl/tree/src/internal/shgetc...
https://git.musl-libc.org/cgit/musl/tree/src/stdio/__uflow.c https://git.musl-libc.org/cgit/musl/tree/src/stdio/__uflow.c
This will call into the string_read callback with a buf size of 1. The string_read will internally do a memchr(buf, 0, len+256);, so, OK, it's memchr-ing at most 257 bytes, sorry. The read data then gets stored in a stdio-internal buffer (the rpos/rlen below), so this code path will actually be skipped on future reads.
If it then needs to unparse a character, it will use ungetc to put it back in a stdio-internal buffer. Reading this code isn't that hard, I don't know why you keep insisting it does something else.
- JdeBP 6y agoYou haven't read the code properly. The memcpy() copies one character. After shgetc() reads that and possibly a few more characters, the entire FILE object goes away and the next call to sscanf() sets up an entirely fresh nonce FILE object and does the initial fill all over again, including scanning the stuff that it has already scanned for NUL, a few characters further on. As I just explained.
- Jasper_ 6y agoYes, but it's not scanning the entire string, it's scanning at most 256 bytes. In MSVC, the number of bytes scanned is `M*N` where M is the number of calls to scanf and N is the size of the file. In musl, N is now 257, no matter the size of the file. Compared to ~10MB of data, that's basically free. Sure, it's scanning a bit more than maybe it needs to, but it's much closer to a non-scanning libc in the amount of data it's consuming.
- JdeBP 6y agoAnd this will be the third time that I've written the phrase "not entirely free of this behaviour", in comparison with the implementations that are entirely free of this behaviour.
- wnoise 6y agoIt's not entirely free of overhead. The overhead is constant per invocation though, so it's entirely free of _quadratic_ behavior. Which is what's being discussed.
- JdeBP 6y agoNo, that was not what was being discussed, neither here nor in that discussion. See https://news.ycombinator.com/item?id=26297612 https://news.ycombinator.com/item?id=26297612 . None of us mentioned quadratic behaviour. We are talking about sscanf() calling strlen(), and in the original discussion why.
- wnoise 6y agoSure, the quadratic behavior is attached to the "calling sscanf in a loop". The point is linear behavior for a call to sscanf. Which isn't the case for musl. Nor does musl call strlen, or even effectively call it. It will bizarrely scan for a NUL in up to 256 bytes ahead of where in the string it is currently. But that's not actually the same behavior as calling strlen or having other linear behavior.
- jka 6y agoThis isn't solely directed towards you, but as a general comment: if you're keen to illustrate a point about code behaviour (as we often are!) then it can potentially save time and ambiguity to include commit references and line ranges. It still doesn't guarantee that the behaviour is stable (because dependencies within the linked range may change before a reader gets to it) but it can help support your message (and hopefully your argument) both at time-of-authorship and in future. (and yep, it's a tradeoff of your own time -- and response time -- against future readers' time; often tricky to handle. I think code browsers could do a lot more to make it easier)