This makes it harder to miss that an error occurred and avoids spamming
output. There should never be a single error, so it doesn't make sense
to gather as many errors as possible when a single error is already a
serious issue that would need to be fixed.
This is a no-op on a toolchain compiled with the basic mitigations
enabled by default, so this is generally a no-op anywhere this project
is likely to be deployed. SSP has a very low performance cost so there's
little reason to avoid it, even though it also has zero value for this
code in practice. It would be great if one of the more modern approaches
was widely adopted, but unfortunately SSP is as good as it gets for
portable options. It doesn't provide any protection against external
writes to the stack data which is all that's really needed here.
ShadowCallStack is a great option for arm64, but it's substantially more
difficult to protect return addresses well on x86_64 due to the design of
the ISA and ABI.
This avoids unnecessarily copying the canary when doing a realloc from a
small size to a large size. It also avoids trying to copy a non-existent
canary out of a zero-size allocation, which are memory protected.
This avoids making a huge number of getrandom system calls during
initialization. The init CSPRNG is unmapped before initialization
finishes and these are still reseeded from the OS. The purpose of the
independent CSPRNGs is simply to avoid the massive performance hit of
synchronization and there's no harm in doing it this way.
Keeping around the init CSPRNG and reseeding from it would defeat the
purpose of reseeding, and it isn't a measurable performance issue since
it can just be tuned to reseed less often.