This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: Implement C11 annex K?
- From: Rich Felker <dalias at libc dot org>
- To: "David A. Wheeler" <dwheeler at dwheeler dot com>
- Cc: libc-alpha at sourceware dot org
- Date: Tue, 12 Aug 2014 18:08:11 -0400
- Subject: Re: Implement C11 annex K?
- Authentication-results: sourceware.org; auth=none
- References: <E1XGDcM-0004tT-8P at rmm6prod02 dot runbox dot com> <53E724B6 dot 3000608 at suse dot com> <53E789C0 dot 4000109 at linux dot vnet dot ibm dot com> <20140812042324 dot GA1674 at brightrain dot aerifal dot cx> <3565dfa0-060c-46b9-b08c-6edc4eaa1179 at email dot android dot com> <20140812205959 dot GB12888 at brightrain dot aerifal dot cx> <d4ae8119-f629-4235-8981-dd2ccc220fea at email dot android dot com>
On Tue, Aug 12, 2014 at 05:46:01PM -0400, David A. Wheeler wrote:
> Annex K is extremely useful. Many people want to prevent easy buffer
> overflows and other similar problems.
>
> E.g., the strcpy function does not check buffer lengths at all,
> while strncpy is badly broken because it zeros out the entire
> destination. None of the standard functions provide a simple "copy a
> string, always terminate, don't go beyond the buffer, and do not do
> unnecessary copues". This is a basic omission in the library, one
> that keeps getting recreated. The current library is missing several
> really basic functionalities. Time to fix it.
Annex K has plenty of fundamental flaws that make it essentially
useless for this purpose. The main problem is the way "runtime
constraint handling" is done. I'll first quote the relevant text:
K.3.1.4 Runtime-constraint violations
"Implementations shall verify that the runtime-constraints for a
function are not violated by the program. If a runtime-constraint is
violated, the implementation shall call the currently registered
runtime-constraint handler (see set_constraint_handler_s in
<stdlib.h>). Multiple runtime-constraint violations in the same call
to a library function result in only one call to the
runtime-constraint handler. It is unspecified which one of the
multiple runtime-constraint violations cause the handler to be
called."
...
"The runtime-constraint handler might not return. If the handler does
return, the library function whose runtime-constraint was violated
shall return some indication of failure as given by the returns
section in the function's specification."
K.3.6.1.1 The set_constraint_handler_s function
"The implementation has a default constraint handler that is used if
no calls to the set_constraint_handler_s function have been made. The
behavior of the default handler is implementation-defined, and it may
cause the program to exit or abort."
The important things to take away from this are:
1. Since the default constraint handler is implementation-defined,
portable code cannot rely on the default handler to catch dangerous
conditions, nor can it rely on the default handler to return an
error status to the caller in a way that the caller can handle.
2. The constraint handler is global state, so it cannot be set on a
per-caller basis. This means, in my terminology, any code using the
Annex K functions is non-library-safe: it's forced either to modify
global state in a way that can't safely cooperate with a caller (or
other library code, much less other threads) that uses the same
state, or to risk crashing the calling program (via a potential
default handler that does so).
Basically, this is a backwards, global-state-driven design from the
80s or early 90s that can't be used in modern library-safe,
thread-safe code.
As for your specific example, which I assume is strncpy_s, the
standard function which already solves this problem without the
additonal confusing and error-prone size arguments is snprintf:
snprintf(dest, destsize, "%s", source). And the nonstandard but widely
available function that's even more convenient is strlcpy. And the
name strncpy_s is horribly misleading since its behavior has nothing
to do with strncpy (which is for working with fixed-size, non-C-string
fields, not bounded copying).
Rich