jemalloc, ptmalloc, nedmalloc, … are all using per thread memory pools, while musl uses a global lock
Most high-end general-purpose memory allocators use a per-thread cache, object allocated from which can later be migrated to the global heap. (This was the primary innovation of jemalloc; finding a good compromise between the resistance to fragmentation provided by a single global allocator and the speed of a full per-thread heap. It was built upon by tcmalloc—lit. ‘thread caching malloc’—and others, and I expect recent versions of ptmalloc2 have similar optimizations as well.)
Development practises
musl’s development is pretty old school: a mailing list for bug tracker, a cgit repository, no continuous builds nor integrations with static analysers like coverity or LGTM, … meh
And this matters why?
Generally better than glibc
I’m not sure how they arrived at this conclusion. From the feature lists they quoted, it sounds to me like glibc wins. Particularly because of the atexit/longjmp hardening.
Nowadays, the only reasonable usage of the %n specifier in printf and its friends is to mount format-string attacks. But since musl aims at being as compliant as possible, this specifier is unfortunately implemented and available.
A good compromise would be to have an run- or build-time toggle to enable it, and default to leaving it off.
Is there any good reason not to run a few static analysers regularly these days? I would be surprised if they produce too many false positives to no the useful.
On %n, I would expect most compilers to warn about its usage these days, in the little C I’ve written lately the compiler was very keen to correct my format strings.
Support for %n
Nowadays, the only reasonable usage of the %n specifier in printf and its friends is to mount format-string attacks. But since musl aims at being as compliant as possible, this specifier is unfortunately implemented and available.
Because the %n format is inherently insecure, it is disabled by default. If %n is encountered in a format string, the invalid parameter handler is invoked, as described in Parameter Validation. To enable %n support, see _set_printf_count_output.
A few applications that require %n add an #ifdef and everyone else has one fewer vulnerability to worry about.
I have actually used %n in real code 20+ years ago. It was used in a tokenizer for a little language and inside sscanf we used it to track how far into the input we’d been able to tokenize.
MSVC doesn’t even support it; they implement a pre-specification version of it, and they refuse to update their implementation due to backwards compatibility.
That said, however, though annex K is maligned, memset_s has seen wider adoption and interest. There have been talks in WG14 to standardize (but not the rest of annex k); or to standardize another function with equivalent behaviour. FreeBSD implements memset_s, but none of the other annex K functions.
Most high-end general-purpose memory allocators use a per-thread cache, object allocated from which can later be migrated to the global heap. (This was the primary innovation of jemalloc; finding a good compromise between the resistance to fragmentation provided by a single global allocator and the speed of a full per-thread heap. It was built upon by tcmalloc—lit. ‘thread caching malloc’—and others, and I expect recent versions of ptmalloc2 have similar optimizations as well.)
And this matters why?
I’m not sure how they arrived at this conclusion. From the feature lists they quoted, it sounds to me like glibc wins. Particularly because of the atexit/longjmp hardening.
A good compromise would be to have an run- or build-time toggle to enable it, and default to leaving it off.
Is there any good reason not to run a few static analysers regularly these days? I would be surprised if they produce too many false positives to no the useful.
On %n, I would expect most compilers to warn about its usage these days, in the little C I’ve written lately the compiler was very keen to correct my format strings.
I can’t find any evidence that the musl project is fuzzing, either. That’s concerning from a security perspective.
What would you fuzz in a libc?
Yes, however they also use multiple arenas rather than a single global heap. Even glibc malloc does so.
So “per thread memory pools” still isn’t 100% correct, but multiple memory pools are used in addition to per-thread and/or per-CPU caches.
Another answer is to not support %n by default like Visual Studio.
A few applications that require %n add an #ifdef and everyone else has one fewer vulnerability to worry about.
Edited to fix link per child post post.
I have actually used
%n
in real code 20+ years ago. It was used in a tokenizer for a little language and insidesscanf
we used it to track how far into the input we’d been able to tokenize.I didn’t say it was good code…
Note that
memset_s
isn’t just an “other libc” thing, it’s part of the C11 standard.To be clear, it is part of the optional Annex K, which has a number of problems and MSVC is the only major implementation to support it: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1967.htm#impementations
So I think it’s fair to call it an “other libc” thing.
MSVC doesn’t even support it; they implement a pre-specification version of it, and they refuse to update their implementation due to backwards compatibility.
That said, however, though annex K is maligned,
memset_s
has seen wider adoption and interest. There have been talks in WG14 to standardize (but not the rest of annex k); or to standardize another function with equivalent behaviour. FreeBSD implementsmemset_s
, but none of the other annex K functions.I’d be very happy to see that. For anyone interested, it looks like the most recent document is http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2599.htm