
Banned C standard library functions in Git source code - susam
https://github.com/git/git/blob/master/banned.h
======
alister
I'm glad to see that setjmp() and longjmp() are still allowed.

I'm just kidding by the way. For those C programmers who haven't encountered
these before, it is a powerful way to do a "goto" in C. Powerful in the sense
that you can jump anywhere, not limited to the same function. If it's used at
all these days, it's used for exception handling.

More info:
[https://en.wikipedia.org/wiki/Setjmp.h](https://en.wikipedia.org/wiki/Setjmp.h)

~~~
slovenlyrobot
These are used /everywhere/ in PostgreSQL, exactly for exception handling. The
result isn't bad at all, but indeed, too powerful a tool for 99% of developers

~~~
crankylinuxuser
And that's the perfect usage for goto. Error catching and jump to fail
block...

~~~
johannes1234321
Goto requires the fail block to be in the same frame. It can be a working
error strategy for failing critical errors in such a way from a failing
module. You have to be aware that lots of stuff is prone to leak (which can be
avoided by i.e. using some memory arena) and locks/mutexes/... might be in
unclear state, so code has to be aware of that.

~~~
userbinator
The destination of the goto is usually the clean-up code.

~~~
johannes1234321
That's nice for the single frame.

Let's take the example of PostgreSQL, which was mentioned in this thread: A
potential implementation (I have no knowledge of pgsql internals) might be
that for a single user session all memory is from a single arena, all locks
and other handles are tied to the session handle, then it can be an efficient
strategy to longjmp out on a _critical_ error (i.e. IO error) and clean the
arena as well as things tied to the session. instead of bubbling this up
through all frames.

------
peff
I see a lot of comments to the effect of "shouldn't XYZ also be banned". The
answer is that we're not necessarily trying to be exhaustive. The point is to
flag common errors before we even hit review, so we add new functions mostly
when somebody tries to misuse them. I don't recall anybody trying to abuse
longjmp() in Git's codebase yet (and no, that's not a challenge).

~~~
Cogito
Peff, for the people asking in the thread, is there a place where correct
alternatives are suggested or demonstrated?

I know there are a few different places that talk about how to use git's
internal machinery, but not sure if any are specific to these banned
functions.

~~~
masklinn
The original commits mentions git's strbuf API[0] and its xsnprintf, a variant
of snprintf which asserts that the destination buffer was big enough[1]
(rather than just return truncation information).

For other codebases, snprintf is the usual recommendation, and careful
straight buffer manipulation (mem*) iff performances are a concern.

[0] [https://schacon.github.io/git/technical/api-
strbuf.html](https://schacon.github.io/git/technical/api-strbuf.html)

[1]
[https://code.forksand.com/linux/git_git/commit/7b03c89ebd103...](https://code.forksand.com/linux/git_git/commit/7b03c89ebd10396ac7569f0c8c4fa0b4efd4f7ed)

------
stiff
Looks like Git has its own string type:

[https://github.com/git/git/blob/master/strbuf.h](https://github.com/git/git/blob/master/strbuf.h)

[https://github.com/git/git/blob/master/strbuf.c](https://github.com/git/git/blob/master/strbuf.c)

See this for the story of why strncpy/strncat are insecure:

[https://en.wikipedia.org/wiki/C_string_handling#Replacements](https://en.wikipedia.org/wiki/C_string_handling#Replacements)

~~~
adamnemecek
Like essentially all C programs.

~~~
zsrxx
What's a good library for this kind of boilerplate? A lightweight one if
possible, i.e. not fucking glib

~~~
vmsp
Salvatore Sanfilippo, from Redis fame, has a nice one
[https://github.com/antirez/sds](https://github.com/antirez/sds).

~~~
chucksmash
Thanks for linking this, it's always good to see how very strong engineers
solve problems. Never in a million years would this approach have occurred to
me. For the interested, the README in the linked repo is done well and clearly
explains the approach itself as well as pros and cons. This also reminded me
that I've been meaning to watch antirez' "Writing System Software"[0] videos
on YouTube for quite a while now, so thanks for that too.

[0]:
[https://www.youtube.com/playlist?list=PLrEMgOSrS_3fghr8ez63x...](https://www.youtube.com/playlist?list=PLrEMgOSrS_3fghr8ez63xKFNF-
BA6Pz13)

------
dblock
Windows programmers are familiar with StrSafe.h,
[https://en.wikipedia.org/wiki/Strsafe.h](https://en.wikipedia.org/wiki/Strsafe.h)
and
[https://github.com/dotnet/coreclr/blob/master/src/pal/inc/st...](https://github.com/dotnet/coreclr/blob/master/src/pal/inc/strsafe.h)
which go a lot further.

Also found
[https://github.com/mubix/netview/blob/master/banned.h](https://github.com/mubix/netview/blob/master/banned.h)
on Github with a better list.

~~~
pjmlp
Additionally we get to enjoy bounds checked arrays(std::...), and iterators on
debug builds, with possibility to selectively enable them in release mode.

While Windows by all means still has its security issues, the toolchain is
much more security oriented than most FOSS alternatives thanks to the Windows
XP wake up call.

Android and ChromeOS are probably the mostly locked down alternatives on the
FOSS space.

~~~
uncletaco
Tangential but the fact that I had to open up the machine and remove a screw
to completely replace ChromeOS with linux bothers the fuck out of me.

~~~
floatboth
That's how secure boot should work. Replacing the root of trust should require
serious physical access that can be tamper-evident. And yeah, out of the box,
the trust is with the vendor — who else would be trusted in a device that
doesn't have an owner yet?

~~~
uncletaco
I never thought of that. And it makes a lot more sense in that context.

------
slovenlyrobot
That's a surprisingly small list, missing e.g. sscanf / gets / strtok / all
the other "usual suspects" at least

~~~
asveikau
I don't see a huge problem with strtok as long as it isn't a multi threaded
program. It is not in gets territory which is literally impossible to use
correctly.

~~~
bhk
Synchronous reentry is a problem. Say some loop using strtok calls a
function... how do you know that _that_ function doesn't use strtok (or call
another function that does...).

Any use of non-const static variables in general has this problem, and strtok
is just one example.

~~~
derefr
> Say some loop using strtok calls a function... how do you know that that
> function doesn't use strtok (or call another function that does...).

I’m constantly surprised that C isn’t specified in such a way that lack-of-
reentrancy can be determined at compile time. You’d “just” need a symbol
table, sort of like the debug symbol table, in each compiled object, holding
for each visible symbol the set of function calls marked `__no_reenter` that
are predominated by that symbol in control flow. (Yes, some functions do
computed jumps, like with longjmp. Just implicitly label those functions
__no_reenter unless the programmer explicitly labels them __reenter!)

~~~
asveikau
The problem isn't exactly reentry. It's that the function, having already
exited, has modified global state, and it needs the same state to be there on
the next call. If another call is interleaved (another callee with its own
strtok loop) then the state is overwritten with the inner loop, and your own
next call won't have its expected contents.

Whereas with a term like reentry I think of two strtok frames on the stack at
the same time, which is not possible.

I think it's a bit easier to conceptualize with a function that produces a
simple return value in a static buffer. Take getpwnam(). It fills a global
structure with info about a given user. So you may keep a pointer to that on
your stack. Then you call some other function foo(). foo looks up another
user. Suddenly you can't rely on that other call to getpwnam() not having
overwritten the data in the result you got back the first time.

~~~
bhk
Ah, yes. What I described wasn't reentry. A reentrant function using strtok
could exhibit this problem, but it applies more widely than that.

------
jcl
Looks like the second vsprintf definition should be "BANNED(vsprintf)", not
"BANNED(sprintf)". Not that it matters much, as it only affects the error
message.

~~~
gus_massa
Nice catch! You can send a "PR", but note that they have their own custom "PR"
procedure, not the standard "PR" procedure in GitHub.

> _Git Source Code Mirror - This is a publish-only repository and all pull
> requests are ignored. Please
> follow[https://github.com/git/git/blob/master/Documentation/Submitt...](https://github.com/git/git/blob/master/Documentation/SubmittingPatches)
> procedure for any of your improvements._

~~~
saagarjha
Aside: GitHub’s refusal to provide a feature to close pull requests for
mirrors is utterly ridiculous since it requires that people (or bots) go
around and disable pull requests and point people to the patch submission
process.

~~~
OJFord
What's weirdest to me is that it differs from the policy on Issues, which can
be turned off in settings.

I sort of get not allowing it, except that it's inconsistent.

------
bigtrakzapzap
These shouldn't be used either (_s are available in C11, _l tend to be locale-
parameter thread-safety, and _r have sizes/state for bounds/thread-safety):

\- strtok -> strtok_r / strtok_s

\- asctime -> strtok_r / strtok_s

\- gmtime -> gmtime_r / gmtime_s

\- localtime -> localtime_r / localtime_s

\- ctime -> ctime_r / ctime_s

\- dirname -> dirname_r

\- basename -> basename_r

\- devname -> devname_r

\- readdir -> readdir_r

\- ttyname -> ttyname_r

\- gamma -> gamma_r

\- lgamma -> lgamma_r

\- lgammaf -> lgammaf_r

\- lgammal -> lgammal_r

\- atoi -> atoi_l

\- atof -> atof_l

\- atol -> atol_l

\- atoll -> atoll_l

\- gets -> gets_s

\- scanf -> scanf_l / scanf_s

\- fscanf -> fscanf_l / fscanf_s

\- sscanf -> sscanf_l / sscanf_s

\- tmpfile -> tmpfile_s

\- fopen -> fopen_s

\- getenv -> getenv_s

\- strdup -> strndup

\- strcmp -> strncmp

\- strlen -> strnlen

\- (Multibyte/wide conversion functions without mbstate_t parameter)

\- wcslen / wscnlen -> wcsnlen_s

\- wcsncasecmp / wcscasecmp_l / wcsncasecmp -> wcsncasecmp_l

\- strcasecmp / strcasecmp_l / strncasecmp -> strncasecmp_l

\- bzero (use explicit_bzero, in some cases)

\- calloc, realloc -> reallocarray (for arrays of non-byte items)

\- memmove -> memmove_s

\- strncat -> strncat_s

\- strncpy -> strncpy_s

\- srand / rand -> rand_r

There are others that are platform-specific. Thread-safety, internal mutable
state (not thread-safe), and buffer-overflows are the primary concerns that
aren't necessarily applicable in all situations.

~~~
masklinn
Annex K was never very popular, is still very easy to misuse[0] and has pretty
much been deprecated and slated for removal.

[0] [http://www.open-
std.org/jtc1/sc22/wg14/www/docs/n1967.htm#mi...](http://www.open-
std.org/jtc1/sc22/wg14/www/docs/n1967.htm#mistakes)

~~~
damien_brooklyn
Back in my individual contributor days I got into serious trouble because of
this. Where can I find it has officially been deprecated? I tried and I can
still use it without getting any warnings?

------
imrehg
Interesting to see the starting commit for that file, there's quite a bit of
discussion and rationale too:
[https://github.com/git/git/commit/c8af66ab8ad7cd78557f0f9f5e...](https://github.com/git/git/commit/c8af66ab8ad7cd78557f0f9f5ef6a52fd46ee6dd)

------
codedokode
What surprises me in C developers is that C exists for probably 40 years but
they still don't have proper strings (not just pointers). In many cases there
is no large performance penalty for storing string length, and checking it,
but they still use pointers or a separate pair of variables for pointer and
buffer size instead of single object.

~~~
zxcvbn4038
There are countless libraries that add higher level string functions and no
end to higher level languages. C fills the niche where you want something
higher level then assembly but lower level then Perl, ruby, python, etc.
Sometimes you want or need to manage your own memory. Arduino is a good
contemporary example.

~~~
stjohnswarts
Exactly. C philosophy is to use libraries and not put things like a better
string library in the core functions of the language. It keeps the language
relatively clean and easy to understand, unlike c++

~~~
unscaled
So the C philosophy is to provide a bad standard string library that is not
thread-safe and makes it impossible to write programs without remote code
execution vulnerabilities, rather than have a better library with exactly the
same functionality but with more security and safety "bloat"?

/snark

Yes, C used have a cavalier approach towards security in the past. But if
you're asking why the standard library is not fixed yet, I think that instead
of pinning it to some lofty philosophy, it's safer to say that good C
developers realized long ago that the original C strings are a mistake. Most
big C projects define their own string functions and often their own length-
prefixed string types. The C standard committee just gave up on fixing this
issue in the standard library, but this is not due to philosophy, but because
of the impracticality to force a standard solution on this stage.

------
MuffinFlavored
For anybody else:

Why is strncpy insecure?

[https://stackoverflow.com/questions/869883/why-is-strncpy-
in...](https://stackoverflow.com/questions/869883/why-is-strncpy-insecure)

> strncpy() doesn't require NUL termination, and is therefore susceptible to a
> variety of exploits.

~~~
vagab0nd
Yes. Also as mentioned in the post, strlcpy (when it's available) is safer.

~~~
jandrese
But still not safe, thanks to the return value. Imagine the case where you are
using strlcpy because you can't be sure if the source buffer is properly null
terminated.

~~~
dezgeg
If your buffer isn't a NUL-terminated, then don't call a function that is only
defined for NUL-terminated buffers. It's as simple as that.

I'm baffled by how some people claim strlcpy() is 'broken' or 'not safe'
because it doesn't handle non-NUL-terminated inputs; the exact same thing
applies to just about any function in the C standard library that takes
strings as input. Are functions like strchr(), fopen(), printf(), strstr(),
setenv() 'broken' as well?

~~~
begriffs
> If your buffer isn't a NUL-terminated, then don't call a function that is
> only defined for NUL-terminated buffers.

It's not that people want to pass strncpy source buffers that lack NUL
termination, it's that strncpy in certain situations will not NUL terminate
its results.

[https://begriffs.com/posts/2019-01-19-inside-c-standard-
lib....](https://begriffs.com/posts/2019-01-19-inside-c-standard-
lib.html#string.h-strncpy)

> some people claim strlcpy() is 'broken'

Speaking of strlcpy, it thankfully doesn't have the problem that strncpy does.
However strlcpy is not in the C standard or in POSIX, so can't be used
portably. In C99 snprintf is a better choice.

~~~
dezgeg
Yes, strncpy() not NUL-terminating it's output is nasty and well-known. But
the comment I was responding to was claiming strlcpy() being unsafe.

------
fserb
This file could be made much better by having comments pointing to reasonable
alternatives to the banned functions.

------
noname120
Why is there no brief explanations in this code why each function is banned?

~~~
asveikau
A C programmer reading this list knows exactly why they are there. It is not
at all a controversial list.

Edit: I guess some down voter doesn't believe me but it continues to be true.
They are all string functions. Most of them do not take an output buffer size,
so a source string exceeding the destination buffer will overflow. Others,
like strncpy, take an output buffer size but will not null terminate when
exceeded, so the buffer size must be reduced by 1 by the caller and
potentially manually terminates, which is too easy to not consider. But any C
programmer with significant experience already knows these pitfalls. So it's
not controversial.

~~~
bhk
If every C programmer knew, then there would be no need to ban them

~~~
Dylan16807
That's not true. People don't staunchly avoid situations that have pointless
sharp edges. Putting up caution tape, despite everyone being aware of the
danger, is very often a useful activity.

------
b55c63a4
For context, this header file was introduced during the period of Microsoft's
acquisition of GitHub.

Git's banned.h roughly approximates the banned functions according to
Microsoft's Security Development Lifecycle: [https://docs.microsoft.com/en-
us/previous-versions/bb288454(...](https://docs.microsoft.com/en-us/previous-
versions/bb288454\(v=msdn.10\))

It seems Microsoft once published their own banned.h, but this file is not
readily available from the MSDN anymore.

~~~
brianpgordon
What are you saying is the connection between GitHub's acquisition and this
header? This code is from git, not GitHub.

~~~
OJFord
I'm also confused reading that comment, but I suppose the intended link is
that GitHub employees are significant git contributors?

~~~
philwelch
Yes, I've seen other instances of Microsoft/GitHub making substantial Git
contributions: [https://devblogs.microsoft.com/devops/supercharging-the-
git-...](https://devblogs.microsoft.com/devops/supercharging-the-git-commit-
graph-iii-generations/)

Microsoft seemed to have been adopting Git already, so it may be that
acquiring Github was merely part of a broader Git strategy that Microsoft has
adopted.

------
westurner
FWIW, here's awesome-static-analysis > Programming Languages > C/C++:
[https://github.com/mre/awesome-static-
analysis/blob/master/R...](https://github.com/mre/awesome-static-
analysis/blob/master/README.md#cc)

These tools have lists of functions not to use. Most of them — at least the
security-focused ones — likely also include: strcpy, strcat, strncpy, strncat,
sprints, and vsprintf just like banned.h

------
forrestthewoods
Neat macro. I like the idea.

Suggestion: the macro should recommend a replacement.

“Sorry_sprintf_is_banned__use_FOO_instead”.

------
tails4e
Delighted to see strncat there, it's a buffer overflow waiting to happen,
especially as the name sounds like it's the 'safer version' where it takes a
size argument, except it's not the size of the destination buffer, it's the
remaining size, so unless you know this, it's wrong for every non empty
buffer. strlcat (not standard) operates how you expect.

~~~
WalterBright
Whenever I review code and see strncat there, it's almost guaranteed to be a
bug. This is for the simple reason that nobody remembers exactly what strncat
does, and so misuse it.

------
saagarjha
What does Git use instead for copying strings? snprintf?

Edit: also interesting is a search for alloca:
[https://github.com/git/git/search?utf8=&q=alloca&type=](https://github.com/git/git/search?utf8=&q=alloca&type=)

~~~
LukeShu
Git has an internal "strbuf" library
[https://github.com/git/git/blob/master/strbuf.h](https://github.com/git/git/blob/master/strbuf.h)

~~~
masklinn
Alternatively it also uses snprintf, though as a small internal variant
(xsnprintf) which literally kills the program if the destination buffer is too
small:
[https://github.com/git/git/blob/master/wrapper.c#L636-L650](https://github.com/git/git/blob/master/wrapper.c#L636-L650)

------
kazinator
If that header is ever accidentally included before any standard header, it's
undefined behavior. :)

~~~
anfilt
How? The preprocessor is ran before every thing else? It will overwrite the
defintions in the header just like in the source file? You still would get a
linking error. The only reason I couldn think is if the the stdlib headers
also called undef for those functions. Moreover this is all during build not
runtime.

~~~
nybble41
According to C99, section 7.1.3:

    
    
        If the program declares or defines an identifier in a context in
        which it is reserved (other than as allowed by 7.1.4), or defines
        a reserved identifier as a macro name, the behavior is undefined.
    

It doesn't matter what the macro would expand to; simply defining the reserved
identifier as a macro triggers undefined behavior. That doesn't mean it won't
_work_ , for some specific combination of standard headers, compiler, and
program source code. It just isn't a strictly conforming program. A conforming
implementation is allowed to flag this as an error, ignore the definition, or
simply generate nonsense output.

------
userbinator
Good to see the list is short and relatively sane compared to other "banned
function" lists. Unfortunately, "too easy to misuse" is a slippery slope, and
gets(), which is probably _the_ best example of a function which is really
broken by design, isn't on that list.

I'm surprised that "complicate audits" is given as a reason, because isn't
this something static analysers (and I mean ones that actually analyse
data/code flow, not dumb pattern-matchers) can easily detect? It's really just
asking the question "how long is this/can this be" and following the data back
to its origin(s).

~~~
rkangel
C aliasing rules can very quickly make "following the data back to its origin"
very difficult.

~~~
userbinator
Theoretically it's equivalent to the Halting Problem, but in practice I've not
seen such difficulty; if aliasing does become a problem to the extent that
following dataflow is difficult, I suspect there are already far deeper design
flaws in the codebase.

------
jasonhansel
If I had time, I'd make a library (perhaps musl-based?) that implements "libc
but without all the parts you're not actually supposed to use."

~~~
Gibbon1
That make me wonder how hard it would be to just strip the bad functions out
of the library.

~~~
anfilt
Well your std c library is generally just a collection of .o, .a, .lib files.
So you could use gnu bin tools to remove symbols of your choosing. However
good luck getting your system to build software because that would modify the
stdlib for all things compiled on your system. You could also tell gcc or
clang not to link to the std library and providr your own with just a few
switches on invocation of the compiler

~~~
Gibbon1
Other thought would be to put the dlls with unsafe functions in different
location than the safer ones and throw up a warning when an application loads
them.

------
kbumsik
Because of possible string buffer overflow?

~~~
opticfluorine
Yes, and interestingly, because even when used correctly they "complicate
audits". This is an interesting use of preprocessor macros, I'm strongly
debating introducing something like this at work.

~~~
kbumsik
I'm not an expert in C, but then what's the issue with strncpy() or any "n"
functions? It prevents overflow AFAIK. Also what is the alternative (memcpy?)
and why?

~~~
susam
strncpy() does not guarantee that the copied string would be terminated with a
null byte ('\0'). For a call that looks like strncpy(dst, src, n), if there is
no null byte in the first n bytes of src, the string copied to dst would also
not contain a null byte.

Here is an example code to demonstrate the problem:

    
    
      #include <stdio.h>
      #include <string.h>
    
      int main()
      {
          char a[] = "01234567";
          strncpy(a, "foobar", 4);
          printf("%.8s\n", a);
          return 0;
      }
    

Here is the output:

    
    
      $ cc -std=c89 -Wall -Wextra -pedantic foo.c && ./a.out
      foob4567
    

A C89-conforming alternative I use is a macro like this that guarantees
'\0'-termination as the first thing:

    
    
      #define strcp(a, b, c) (a[0] = '\0', strncat(a, b, c - 1))
    

An example from my code:
[https://github.com/susam/uncap/blob/master/uncap.c#L78-L87](https://github.com/susam/uncap/blob/master/uncap.c#L78-L87)

Here is how to use it:

    
    
      #include <stdio.h>
      #include <string.h>
    
      #define strcp(a, b, c) (a[0] = '\0', strncat(a, b, c - 1))
    
      int main()
      {
          char a[] = "01234567";
          strcp(a, "foobar", 4);
          printf("%.8s\n", a);
          return 0;
      }
    

Here is the output:

    
    
      $ cc -std=c89 -Wall -Wextra -pedantic foo.c && ./a.out
      foo

~~~
saagarjha
Your macro refers to a twice; it might be better as a function.

~~~
foo101
What has referring to a variable twice got to do with whether it should be a
macro or function?

~~~
jfk13
If the strcp() macro is used with a function as the first argument (or an
expression that has side-effects), it's not obvious at the call site (or,
probably, intended by the programmer) that the argument will be evaluated
twice.

E.g. suppose we write something like

    
    
        char* buf = strcp(((char*)malloc(4)), "foobar", 4);
    

expecting this to copy the beginning of the string "foobar" into a newly-
allocated 4-byte buffer. Oops... this will actually call malloc twice (leaking
the first buffer), and it won't have written the intended '\0' into the buffer
that actually ends up getting used, so all bets are off...

If strcp were a function, its first argument would be evaluated just once, and
it would work as intended.

------
whydoyoucare
It is also important to teach newbies on the pitfalls of certain libc
functions. Too much spoon feeding creates a bigger mess in the long run.

------
miyeahu
Huh, I literally just read through this file a few minutes before this was
posted because I was randomly browsing the git source code.

------
jepler
I guess they care too much about portability to use "pragma GCC poison"?

~~~
zsrxx
Wanting code to compile on something other than gcc is not "caring too much",
it's being responsible

~~~
The_rationalist
Responsible? What an hyperbolic statement. Could you enlighten me on what
would be the significant negative consequences? I hope that your mental
equation take into account the missed usefulness of GCC only attributes, flags
and extensions by being clang compatible.

~~~
zsrxx
I don't know what to tell you. Do you think all compilers should implement all
GCC proprietary extensions, basically creating a parallel C standard?

And that's not saying that GCC extensions are not useful, but they should not
be considered the norm

~~~
klez
Agreed. But I wonder if we already have a sort of parallel C standard already
with POSIX (of course the parts about C, not about OS facilities).

------
Koshkin
> strcpy ... BANNED

But they cannot ban while (* p++ = * q++); now can they.

~~~
rat9988
Truly curious as I don't code in C, or any other low level language. What is
the problem with it? That there might not be enough memory allocated at *q?

~~~
microtherion
Not enough memory at *p. The loop performs the exact same function that strcpy
does, and some people just write it out by hand.

------
badrabbit
Puts(),gets() would make a good addition?

~~~
hawski
What's wrong with puts? GCC for example will even change a naive printf to
puts when applicable.

~~~
badrabbit
You're right about puts. I guess I am just used to avoiding both.

------
Koshkin
K&R is turning in its grave.

~~~
kgwgk
You made me check that K is still alive!

~~~
basementcat
Koshkin wrote K&R and not K|R.

------
clX111
There are persons working on git who abuse strcpy()? This sounds a bit like
activism and not based on reality.

------
winter_blue
musl libc (an alternative libc) provides implementations of these functions
that are memory-safe. (It only works on Linux though.)

~~~
anilakar
Using musl as your standard library causes other problems, namely horrible
Python performance and incompatibility with Valgrind.

~~~
megous
What's slow in particular and on what arch?

~~~
anilakar
Alpine. Slow in particular? I don't have the resources to profile everything
in our codebase and find the root issue, but others have already benchmarked
it: [https://superuser.com/questions/1219609/why-is-the-alpine-
do...](https://superuser.com/questions/1219609/why-is-the-alpine-docker-image-
over-50-slower-than-the-ubuntu-image)

