strtok_s and compilers C11 onward compliance - c

The declaration of strtok_s in C11, and its usage, look to be very different from the strtok_s in compilers like the latest bundled with Visual Studio 2022 (17.4.4) and also GCC 12.2.0 (looking at MinGW64 distribution).
I fear the different form has been developed as a safer and accepted alternative to strtok long before C11. What happens now if someone wants to use strtok_s and stay C11 compliant?
Are the compiler supplied libraries C11 compliant?
Maybe it's just that I've been fooled by something otherwise obvious, and someone can help me...
This is C11 (and similar is to C17 and early drafts of C23):
char *strtok_s(char * restrict s1,
rsize_t * restrict s1max,
const char * restrict s2,
char ** restrict ptr);
the same can be found as a good reference in the safec library
While MSC/VC and GCC have the form
char* strtok_s(
char* str,
const char* delimiters,
char** context
);

The C11 "Annex K bounds checking interfaces" was received with a lot of scepticism and in practice nearly no standard lib implemented it. See for example Field Experience With Annex K — Bounds Checking Interfaces.
As for the MSVC compiler, it doesn't conform to any C standard and never made such claims - you can try this out to check if you are using such a compiler or not:
#if !defined(__STDC__) || (__STDC__==0)
#error This compiler is non-conforming.
#endif
In particular, MSVC did not implement Annex K either, but already had non-standard library extensions in place prior to C11.
In practice _s means:
Possibly more safe or possibly less safe, depending on use and what the programmer expected.
Non-portable.
Possibly non-conforming.
If portability and standard conformance are important, then avoid _s functions.
In practice _s functions protect against two things: getting passed non-sanitized input or null pointers. So assuming that you do proper input sanitation and don't pass null pointers to library functions, the _s functions aren't giving you extra safety, just extra execution bloat and portability problems.

What happens now if someone wants to use strtok_s and stay C11 compliant?
You de facto can't.
And it's not limited to just strtok_s(). The entire C11 Annex K set of implementations is fractured, and because the major deviations from the standard are from Microsoft's implementation, there will probably never be a way to write portable, standard-conforming code using the Annex K functions.
Per N1967 Field Experience With Annex K — Bounds Checking Interface:
Available Implementations
Despite the specification of the APIs having been around for over a
decade only a handful of implementations exist with varying degrees of
completeness and conformance. The following is a survey of
implementations that are known to exist and their status.
While two of the implementations below are available in portable
source code form as Open Source projects, none of the popular Open
Source distribution such as BSD or Linux has chosen to make either
available to their users. At least one (GNU C Library) has repeatedly
rejected proposals for inclusion for some of the same reasons as those
noted by the Austin Group in their initial review of TR 24731-1
N1106]. It appears unlikely that the APIs will be provided by future
versions of these distributions.
Microsoft Visual Studio
Microsoft Visual Studio implements an early version of the APIs.
However, the implementation is incomplete and conforms neither to C11
nor to the original TR 24731-1. For example, it doesn't provide the
set_constraint_handler_s function but instead defines a
_invalid_parameter_handler _set_invalid_parameter_handler(_invalid_parameter_handler) function with similar behavior but a slightly different and incompatible
signature. It also doesn't define the abort_handler_s and
ignore_handler_s functions, the memset_s function (which isn't
part of the TR), or the RSIZE_MAX macro. The Microsoft
implementation also doesn't treat overlapping source and destination
sequences as runtime-constraint violations and instead has undefined
behavior in such cases.
As a result of the numerous deviations from the specification the
Microsoft implementation cannot be considered conforming or portable.
...
Safe C Library
Safe C Library [SafeC] is a fairly efficient and portable but
unfortunately very incomplete implementation of Annex K with support
for the string manipulation subset of functions declared in
<string.h>.
Due to its lack of support for Annex K facilities beyond the
<string.h> functions the Safe C Library cannot be considered a
conforming implementation.
Even the Safe C library is non-conforming.
Whether these functions are "safer" is debatable. Read the entire document.
Unnecessary Uses
A widespread fallacy originated by Microsoft's deprecation of the standard functions in an effort to increase the adoption of the APIs is that every call to the standard functions is necessarily unsafe and should be replaced by one to the "safer" API. As a result, security-minded teams sometimes naively embark on months-long projects rewriting their working code and dutifully replacing all instances of the "deprecated" functions with the corresponding APIs. This not only leads to unnecessary churn and raises the risk of injecting new bugs into correct code, it also makes the rewritten code less efficient.
Also, read the updated N1969 Updated Field Experience With Annex K — Bounds Checking Interfaces:
Despite more than a decade since the original proposal and nearly ten years since the ratification of ISO/IEC TR 24731-1:2007, and almost five years since the introduction of the Bounds checking interfaces into the C standard, no viable conforming implementations has emerged. The APIs continue to be controversial and requests for implementation continue to be rejected by implementers.
The design of the Bounds checking interfaces, though well-intentioned, suffers from far too many problems to correct. Using the APIs has been seen to lead to worse quality, less secure software than relying on established approaches or modern technologies. More effective and less intrusive approaches have become commonplace and are often preferred by users and security experts alike.
Therefore, we propose that Annex K be either removed from the next revision of the C standard, or deprecated and then removed.

Related

Why didn't gcc (or glibc) implement _s functions?

_s functions, such as scanf_s, printf_s seems to be optional standard. MSVC has implemented these functions, but gcc hasn't.
Is there specific reason for not implementing secure functions? Is scanf of glibc secure enough?
The _s functions are optional (Annex K of the C11 standard). They're widely regarded as 'not very beneficial'.
In the answers to my question Do you use the TR-24731 "safe" functions?, you can find information about where there are problems with the standard specification — such as crucial differences between the standard and Microsoft's implementation. TR 24731-1 was a technical report from the C standard committee. The report was incorporated almost verbatim — with an extra, previously omitted, function, memset_s() — in the C11 standard as (optional but 'normative') Annex K. There's also TR 24731-2 for a different set of functions — without the _s suffix. It ran into resistance for a different set of reasons.
Also, there is a proposal before the C Standard Committee that the functions defined in Annex K should be removed from the next revision of the standard:
N1967 Field Experience with Annex K — Bounds Checking Interfaces
That paper is a straightforward and compelling read of the reasons why the TR-24731 (*_s()) functions have not been widely implemented.
Key reasons include:
The problem is only spotted once, then fixed, and then the *_s() function is unnecessary.
This makes it very hard to test the *_s() functions, or the code which uses them.
It isn't easy to integrate the new functions into old code (which is where there'd be most benefit).
The functions inherently slow down software with extensive but redundant checking.
See the paper for more details. The paper ends with the section:
Suggested Technical Corrigendum
Despite more than a decade since the original proposal and nearly ten years since the ratification of ISO/IEC TR 24731-1:2007, and almost five years since the introduction of the Bounds checking interfaces into the C standard, no viable conforming implementations has emerged. The APIs continue to be controversial and requests for implementation continue to be rejected by implementers.
The design of the Bounds checking interfaces, though well-intentioned, suffers from far too many problems to correct. Using the APIs has been seen to lead to worse quality, less secure software than relying on established approaches or modern technologies. More effective and less intrusive approaches have become commonplace and are often preferred by users and security experts alike.
Therefore, we propose that Annex K be either removed from the next revision of the C standard, or deprecated and then removed.
Annex K was not removed from C17. Two new papers from the standards committee (ISO JTC1/SC22/WG14) discuss Annex K (and are in favour of retaining the functions):
Bounds-checking Interfaces: Field Experience and Future Directions
Annex K Repairs

How to install C11 compiler on Mac OS with optional string functions included?

I'm trying the below code to see if the optional string functions in C are supported (I've got Mac OS X El Capitan and XCode installed)...
#include <stdio.h>
int main(void)
{
#if defined __STDC_LIB_EXT1__
printf("Optional functions are defined.\n");
#else
printf("Optional functions are not defined.\n");
#endif
return 0;
}
...but it suggests they aren't.
I've tried all the different compilers I have from XCode (cc, gcc, llvm-gcc, clang).
I've also tried brew install gcc assuming that the GNU C compiler would give me these extra functions, but it doesn't.
Is there a way to simply install a C11 compatible compiler on Mac OS that'll give me these additional (i.e. safe) string functions.
Summary: You won't get it to work. There are better ways to make sure your code is correct. For now, use the address sanitizer instead.
Also known as "Annex K" of the C11 standard or TR 24731, these functions are not widely implemented. The only commonly available implementation is part of Microsoft Visual Studio, other common C implementations have rejected (explicitly, even) the functionality in annex K. So, while annex K is technically part of the standard, for practical purposes it should be treated as a Microsoft-specific extension.
See Field Experience With Annex K — Bounds Checking Interfaces (document N1967) for more information. According to this report, there are only four implementations of annex K, two are for Windows, one is considered "very incomplete" and the remaining one is "unsuitable for production use without considerable changes."
However, the argument that these string functions are "safe" is a bit misleading. These functions merely add bounds checking, which only works if the functions are called correctly—but then again, the "non-safe" functions only work if they are called correctly too. From the report cited above,
Despite more than a decade since the original proposal and nearly ten years since the ratification of ISO/IEC TR 24731-1:2007, and almost five years since the introduction of the Bounds checking interfaces into the C standard, no viable conforming implementations has emerged. The APIs continue to be controversial and requests for implementation continue to be rejected by implementers.
The design of the Bounds checking interfaces, though well-intentioned, suffers from far too many problems to correct. Using the APIs has been seen to lead to worse quality, less secure software than relying on established approaches or modern technologies. More effective and less intrusive approaches have become commonplace and are often preferred by users and security experts alike.
Therefore, we propose that Annex K be either removed from the next revision of the C standard, or deprecated and then removed.
I suggest using the address sanitizer as an alternative.
Do not use strncpy, strncat or the like as "safe" functions, they're not designed to do that and they are not drop-in replacements for strcpy, strcat, etc., unlike strcpy_s, strcat_s, which are drop-in replacements.
If you are not using Windows or Embarcadero you need to use the external safeclib: https://github.com/rurban/safeclib/releases
No other libc's comes with the safe C11 Annex K extensions.
For an overview of the various libc quirks regarding this see https://rurban.github.io/safeclib/doc/safec-3.3/d1/dae/md_doc_libc-overview.html

Does C standard mandate that platforms must not define behaviors beyond those given in standard

The C standard makes clear that a compiler/library combination is allowed to do whatever it likes with the following code:
int doubleFree(char *p)
{
int temp = *p;
free(p);
free(p);
return temp;
}
In the event that a compiler does not require use of a particular bundled library, however, is there anything in the C standard which would forbid a library from defining a meaningful behavior? As a simple example, suppose code were written for a platform which had reference-counted pointers, such that following p = malloc(1234); __addref(p); __addref(p); the first two calls to free(p) would decrement the counter but not free the memory. Any code written for use with such a library would naturally work only with such a library (and the __addref() calls would likely fail on most others), but such a feature could be helpful in many cases when e.g. it is necessary to pass the a string repeatedly to a method which expects to be given a string produced with strdup and consequently calls free on it.
In the event that a library would define a useful behavior for some action like double-freeing a pointer, is there anything in the C standard which would authorize a compiler to unilaterally break it?
There is really two question here, your formally stated one and your broader one outlined in your comments to questions raised by others.
Your formal question is answers by the definition of undefined behavior and section 4 on conformance. The definition says (emphasis mine):
behavior, upon use of a nonportable or erroneous program construct or of erroneous data,
for which this International Standard imposes no requirements
With emphasis on nonportable and imposes no requirements. This really says it all, the compiler is free to optimize in unpleasant manners or can also chose to make the behavior documented and well defined, this of course mean the program is no longer strictly conforming, which brings us to section 4:
A strictly conforming program shall use only those features of the language and library
specified in this International Standard.2) It shall not produce output dependent on any
unspecified, undefined, or implementation-defined behavior, and shall not exceed any
minimum implementation limit.
but a conforming implementation is allowed extensions as long as they don't break a conforming program:
A conforming implementation may have extensions (including additional
library functions), provided they do not alter the behavior of any strictly conforming
program.3)
As the C FAQ says:
There are very few realistic, useful, strictly conforming programs. On the other hand, a merely conforming program can make use of any compiler-specific extension it wants to.
Your informal question deals with compilers taking more aggressive optimization opportunies with undefined behavior and in the long run the fear this will make real world systems programming impossible. While I do understand how this relatively new aggressive stance seems very programmer unfriendly to many in the end a compiler won't last very long if people can not build useful programs with it. A related blog post by John Regehr: Proposal for a Friendly Dialect of C.
One could argue the opposite, that compilers have made a lot of effort to build extensions to support varying needs not supported by the standard. I think the article GCC hacks in the Linux kernel demonstrates this well. It goes into the many gcc extensions that the Linux kernel relies on and clang has in general attempted to support as many gcc extensions as possible.
Whether compilers have removed useful handling of undefined behavior which hampers effective systems programming is not clear to me. I think specific questions on alternatives for individual cases of undefined behavior that has been exploited in systems programming and no longer work would be useful and interesting to the community.
Does C standard mandate that platforms must not define behaviors beyond those given in standard
Quite simply, no, it does not. The standard says:
An implementation shall be accompanied by a document that defines all implementation-
defined and locale-specific characteristics and all extensions.
There is no restriction anywhere in the standard that prohibits implementations from providing any other documentation they like. If you like, you can read N1570, the latest freely available draft of the ISO C standard, and confirm the lack of any such prohibition.
In the event that a library would define a useful behavior for some action like double-freeing a pointer, is there anything in the C standard which would authorize a compiler to unilaterally break it?
A C implementation includes both the compiler and the standard library. free() is part of the standard library. The standard does not define the behavior of passing the same pointer value to free() twice, but an implementation is free to define the behavior. Any such documentation is not required, and is outside the scope of the C standard.
If a C implementation documented, for example, that calling free() a second time on the same pointer value has no effect, but then doing so actually causes the program to crash, that would violate the implementation's own documentation, but it would not violate the C standard. There is no specific requirement in the C standard that says an implementation must conform to its own documentation, beyond the documentation that's required by the standard. An implementation's conformance to its own documentation is enforce by the market and by common sense, not by the C standard.
In the event that a library would define a useful behavior for some action like double-freeing a pointer, is there anything in the C standard which would authorize a compiler to unilaterally break it?
The compiler and the standard library (i.e. the one in which free is defined) are both part of the implementation - it isn't really coherent to talk about one of them doing something "unilaterally".
If a compiler "does not require use of a particular bundled library", then (other than perhaps as a freestanding implementation) it alone is not an implementation, so the standard doesn't apply to it at all. The behavior of a combination of a library and a compiler are the responsibility of whoever chooses to combine them (which may be the author of either component, or someone else entirely) and label this combination as an implementation. It would, of course, be wise not to document extensions implemented by the library as features of this implementation without confirming that the compiler does not break them. For that matter, you would also need to make sure that the compiler doesn't break anything used internally by the library.
In answer to your main question: no, it does not. If the end result of combining a library and a compiler (and kernel, dynamic loader, etc) is a conforming hosted environment, it is a conforming implementation even if some extensions that the library's author would like to have provided are not supported by the final result of combining them, but it does not require them to work, either. Conversely, if the result does not conform - for example if the compiler breaks the internals of the library and thereby causes some library function not to conform - then it is not a conforming implementation. Any program which calls free twice on the same pointer, or uses any reserved identifier starting with two underscores, causes undefined behavior and therefore is not a strictly conforming program.

Is C99 backward compatible with C89?

I'm used to old-style C and and have just recently started to explore c99 features. I've just one question: Will my program compile successfully if I use c99 in my program, the c99 flag with gcc and link it with prior c99 libraries?
So, should I stick to old C89 or evolve?
I believe that they are compatible in that respect. That is as long as the stuff that you are compiling against doesn't step on any of the new goodies. For instance, if the old code contains enum bool { false, true }; then you are in trouble. As a similar dinosaur, I am slowly embracing the wonderful new world of C99. After all, it has only been out there lurking for about 10 years now ;)
You should evolve. Thanks for listening :-)
Actually, I'll expand on that.
You're right that C99 has been around for quite a while. You should (in my opinion) be using that standard for anything other than legacy code (where you just fix bugs rather than add new features). It's probably not worth it for legacy code but you should (as with all business decisions) do your own cost/benefit analysis.
I'm already ensuring my new code is compatible with C1x - while I'm not using any of the new features yet, I try to make sure it won't break.
As to what code to look out for, the authors of the standards take backward compatibility very seriously. Their job was not ever to design a new language, it was to codify existing practices.
The phase they're in at the moment allows them some more latitude in updating the language but they still follow the Hippocratic oath in terms of their output: "first of all, do no harm".
Generally, if your code is broken with a new standard, the compiler is forced to tell you. So simply compiling your code base will be an excellent start. However, if you read the C99 rationale document, you'll see the phrase "quiet change" appear - this is what you need to watch out for.
These are behavioral changes in the compiler that you don't need to be informed about and may be the source of much angst and gnashing of teeth if your application starts acting strange. Don't worry about the "quiet change in c89" bits - if they were a problerm, you would have already been bitten by them.
That document, by the way, is an excellent read to understand why the actual standard says what it says.
Some C89 features are not valid C99
Arguably, those features exist only for historical reasons, and should not be used in modern C89 code, but they do exist.
The C99 N1256 standard draft foreword paragraph 5 compares C99 to older revisions, and is a good place to start searching for those incompatibilities, even though it has by far more extensions than restrictions.
Implicit int return and variable types
Mentioned by Lutz in a comment, e.g. the following are valid C89:
static i;
f() { return 1; }
but not C99, in which you have to write:
static int i;
int f() { return 1; }
This also precludes calling functions without prototypes in C99: Are prototypes required for all functions in C89, C90 or C99?
n1256 says:
remove implicit int
Return without expression for non void function
Valid C89, invalid C99:
int f() { return; }
I think in C89 it returns an implementation defined value. n1256 says:
return without expression not permitted in function that returns a value
Integer division with negative operand
C89: rounds to an implementation defined direction
C99: rounds to 0
So if your compiler rounded to -inf, and you relied on that implementation defined behavior, your compiler is now forced to break your code on C99.
https://stackoverflow.com/a/3604984/895245
n1256 says:
reliable integer division
Windows compatibility
One major practical concern is being able to compile in Windows, since Microsoft does not intend to implement C99 fully too soon.
This is for example why libgit2 limits allowed C99 features.
Respectfully: Try it and find out. :-)
Though, keep in mind that even if you need to fix a few minior compiling differences, moving up is probably worth it.
If you don't violate the explicit C99 features,a c90 code will work fine c99 flag with another prior c99 libraries.
But there are some dos based libraries in C89 like ,, that will certainly not work.
C99 is much flexible so feel free to migrate :-)
The calling conventions between C libraries hasn't changed in ages, and in fact, I'm not sure it ever has.
Operating systems at this point rely heavily on the C calling conventions since the C APIs tend to be the glue between the pieces of the OS.
So, basically the answer is "Yes, the binaries will be backwards compatible. No, naturally, code using C99 features can't later be compiled with a non-C99 compiler."
It's intended to be backwards compatible. It formalizes extensions that many vendors have already implemented. It's possible, maybe even probable, that a well written program won't have any issues when compiling with C99.
In my experience, recompiling some modules and not others to save time... wastes a lot of time. Usually there is some easily overlooked detail that needs the new compiler to make it all compatible.
There are a few parts of the C89 Standard which are ambiguously written, and depending upon how one interprets the rule about types of pointers and the objects they're accessing, the Standard may be viewed as describing one of two very different languages--one of which is semantically much more powerful and consequently usable in a wider range of fields, and one of which allows more opportunities for compiler-based optimization. The C99 Standard "clarified" the rule to make clear that it makes no effort to mandate compatibility with the former language, even though it was overwhelmingly favored in many fields; it also treats as undefined some things that were defined in C89 but only because the C89 rules weren't written precisely enough to forbid them (e.g. the use of memcpy for type punning in cases where the destination has heap duration).
C99 may thus be compatible with the language that its authors thought was described by C89, but is not compatible with the language that was processed by most C89 compilers throughout the 1990s.

Do you use the TR 24731 'safe' functions? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
The community reviewed whether to reopen this question 9 months ago and left it closed:
Original close reason(s) were not resolved
Improve this question
The ISO C committee (ISO/IEC JTC1/SC21/WG14) has published TR 24731-1 and is working on TR 24731-2:
TR 24731-1: Extensions to the C Library Part I: Bounds-checking interfaces
WG14 is working on a TR on safer C library functions. This TR is oriented towards modifying existing programs, often by adding an extra parameter with the buffer length. The latest draft is in document N1225. A rationale is in document N1173. This is to become a Technical Report type 2.
TR 24731-2: Extensions to the C Library - Part II: Dynamic allocation functions
WG14 is working on a TR on safer C library functions. This TR is oriented towards new programs using dynamic allocation instead of an extra parameter for the buffer length. The latest draft is in document N1337. This is to become a Technical Report type 2.
Questions
Do you use a library or compiler with support for the TR24731-1 functions?
If so, which compiler or library and on which platform(s)?
Did you uncover any bugs as a result of fixing your code to use these functions?
Which functions provide the most value?
Are there any that provide no value or negative value?
Are you planning to use the library in the future?
Are you tracking the TR24731-2 work at all?
I have been a vocal critic of these TRs since their inception (when it was a single TR) and would never use them in any of my software. They mask symptoms instead of addressing causes and it is my opinion that if anything they will have a negative impact on software design as they provide a false sense of security instead of promoting existing practices that can accomplish the same goals much more effectively. I am not alone, in fact I am not aware of a single major proponent outside of the committee developing these TRs.
I use glibc and as such know that I will be spared having to deal with this nonsense, as Ulrich Drepper, lead maintainer for glibc, said about the topic:
The proposed safe(r) ISO C library
fails to address to issue completely.
... Proposing to make the life of a
programmer even harder is not going to
help. But this is exactly what is
proposed. ... They all require more
work to be done or are just plain
silly.
He goes on to detail problems with a number of the proposed functions and has elsewhere indicated that glibc would never support this.
The Austin Group (responsible for maintaining POSIX) provided a very critical review of the TR, their comments and the committee responses available here. The Austin Group review does a very good job detailing many of the problems with the TR so I won't go into individual details here.
So the bottom line is: I don't use an implementation that supports or will support this, I don't plan on ever using these functions, and I see no positive value in the TR. I personally believe that the only reason the TR is still alive in any form is because it is being pushed hard by Microsoft who has recently proved very capable of getting things rammed though standards committees despite wide-spread opposition. If these functions are ever standardized I don't think they will ever become widely used as the proposal has been around for a few years now and has failed to garner any real community support.
Direct answer to question
I like Robert's answer, but I also have some views on the questions I raised.
Do you use a library or compiler with support for the TR24731-1 functions?
No, I don't.
If so, which compiler or library and on which platform(s)?
I believe the functions are provided by MS Visual Studio (MS VC++ 2008 Edition, for example), and there are warnings to encourage you to use them.
Did you uncover any bugs as a result of fixing your code to use these functions?
Not yet. And I don't expect to uncover many in my code. Some of the other code I work with - maybe. But I've yet to be convinced.
Which functions provide the most value?
I like the fact that the printf_s() family of functions do not accept the '%n' format specifier.
Are there any that provide no value or negative value?
The tmpfile_s() and tmpnam_s() functions are a horrible disappointment. They really needed to work more like mkstemp() which both creates the file and opens it to ensure there is no TOCTOU (time-of-check, time-of-use) vulnerability. As it stands, those two provide very little value.
I also think that strerrorlen_s() provides very little value.
Are you planning to use the library in the future?
I am in two minds about it. I started work on a library that would implement the capabilities of TR 24731 over a standard C library, but got caught by the amount of unit testing needed to demonstrate that it is working correctly. I'm not sure whether to continue that. I have some code that I want to port to Windows (mainly out of a perverse desire to provide support on all platforms - it's been working on Unix derivatives for a couple of decades now). Unfortunately, to get it to compile without warnings from the MSVC compilers, I have to plaster the code with stuff to prevent MSVC wittering about me using the perfectly reliable (when carefully used) standard C library functions. And that is not appetizing. It is bad enough that I have to deal with most of two decades worth of a system that has developed over that period; having to deal with someone's idea of fun (making people adopt TR 24731 when they don't need to) is annoying. That was partly why I started the library development - to allow me to use the same interfaces on Unix and Windows. But I'm not sure what I'll do from here.
Are you tracking the TR24731-2 work at all?
I'd not been tracking it until I went to the standards site while collecting the data for the question. The asprintf() and vasprintf() functions are probably valuable; I'd use those. I'm not certain about the memory stream I/O functions. Having strdup() standardized at the C level would be a huge step forward. This seems less controversial to me than the part 1 (bounds checking) interfaces.
Overall, I'm not convinced by part 1 'Bounds-Checking Interfaces'. The material in the draft of part 2 'Dynamic Allocation Functions' is better.
If it were up to me, I'd move somewhat along the lines of part 1, but I'd also revised the interfaces in the C99 standard C library that return a char * to the start of the string (e.g. strcpy() and strcat()) so that instead of returning a pointer to the start, they'd return a pointer to the null byte at the end of the new string. This would make some common idioms (such as repeatedly concatenating strings onto the end of another) more efficient because it would make it trivial to avoid the quadratic behaviour exhibited by code that repeatedly uses strcat(). The replacements would all ensure null-termination of output strings, like the TR24731 versions do. I'm not wholly averse to the idea of the checking interface, nor to the exception handling functions. It's a tricky business.
Microsoft's implementation is not the same as the standard specification
Update (2011-05-08)
See also this question. Sadly, and fatally to the usefulness of the TR24731 functions, the definitions of some of the functions differs between the Microsoft implementation and the standard, rendering them useless (to me). My answer there cites vsnprintf_s().
For example, TR 24731-1 says the interface to vsnprintf_s() is:
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdarg.h>
#include <stdio.h>
int vsnprintf_s(char * restrict s, rsize_t n,
const char * restrict format, va_list arg);
Unfortunately, MSDN says the interface to vsnprintf_s() is:
int vsnprintf_s(
char *buffer,
size_t sizeOfBuffer,
size_t count,
const char *format,
va_list argptr
);
Parameters
buffer - Storage location for output.
sizeOfBuffer - The size of the buffer for output.
count - Maximum number of characters to write (not including the terminating null), or _TRUNCATE.
format - Format specification.
argptr - Pointer to list of arguments.
Note that this is not simply a matter of type mapping: the number of fixed arguments is different, and therefore irreconcilable. It is also unclear to me (and presumably to the standards committee too) what benefit there is to having both 'sizeOfBuffer' and 'count'; it looks like the same information twice (or, at least, code will commonly be written with the same value for both parameters).
Similarly, there are also problems with scanf_s() and its relatives. Microsoft says that the type of the buffer length parameter is unsigned (explicitly stating 'The size parameter is of type unsigned, not size_t'). In contrast, in Annex K, the size parameter is of type rsize_t, which is the restricted variant of size_t (rsize_t is another name for size_t, but RSIZE_MAX is smaller than SIZE_MAX). So, again, the code calling scanf_s() would have to be written differently for Microsoft C and Standard C.
Originally, I was planning to use the 'safe' functions as a way of getting some code to compile cleanly on Windows as well as Unix, without needing to write conditional code. Since this is defeated because the Microsoft and ISO functions are not always the same, it is pretty much time to give up.
Changes in Microsoft's vsnprintf() in Visual Studio 2015
In the Visual Studio 2015 documentation for vsnprintf(), it notes that the interface has changed:
Beginning with the UCRT in Visual Studio 2015 and Windows 10, vsnprintf is no longer identical to _vsnprintf. The vsnprintf function complies with the C99 standard; _vnsprintf is retained for backward compatibility.
However, the Microsoft interface for vsnprintf_s() has not changed.
Other examples of differences between Microsoft and Annex K
The C11 standard variant of localtime_s() is defined in ISO/IEC 9899:2011 Annex K.3.8.2.4 as:
struct tm *localtime_s(const time_t * restrict timer,
struct tm * restrict result);
compared with the MSDN variant of localtime_s() defined as:
errno_t localtime_s(struct tm* _tm, const time_t *time);
and the POSIX variant localtime_r() defined as:
struct tm *localtime_r(const time_t *restrict timer,
struct tm *restrict result);
The C11 standard and POSIX functions are equivalent apart from name. The Microsoft function is different in interface even though it shares a name with the C11 standard.
Another example of differences is Microsoft's strtok_s() and Annex K's strtok_s():
char *strtok_s(char *strToken, const char *strDelimit, char **context);
vs:
char *strtok_s(char * restrict s1, rsize_t * restrict s1max, const char * restrict s2, char ** restrict ptr);
Note that the Microsoft variant has 3 arguments whereas the Annex K variant has 4. This means that the argument list to Microsoft's strtok_s() is compatible with POSIX's strtok_r() — so calls to these are effectively interchangeable if you change the function name (e.g. by a macro) — but the Standard C (Annex K) version is different from both with the extra argument.
The question Different declarations of qsort_r() on Mac and Linux has an answer that also discusses qsort_s() as defined by Microsoft and qsort_s() as defined by TR24731-1 — again, the interfaces are different.
ISO/IEC 9899:2011 — C11 Standard
The C11 standard (December 2010 Draft; you could at one time obtain a PDF copy of the definitive standard, ISO/IEC 9899:2011, from the ANSI web store for 30 USD) does have the TR24731-1 functions in it as an optional part of the standard. They are defined in Annex K (Bounds-checking Interfaces), which is 'normative' rather than 'informational', but it is optional.
The C11 standard does not have the TR24731-2 functions in it — which is sad because the vasprintf() function and its relatives could be really useful.
Quick summary:
C11 contains TR24731-1
C11 does not contain TR24731-2
C18 is the same as C11 w.r.t TR24731.
Proposal to remove Annex K from the successor to C11
Deduplicator pointed out in a comment to another question that there is a proposal before the ISO C standard committee (ISO/IEC JTC1/SC22/WG14)
N1967 Field Experience with Annex K — Bounds Checking Interfaces
It contains references to some of the extant implementations of the Annex K functions — none of them widely used (but you can find them via the document if you are interested).
The document ends with the recommendation:
Therefore, we propose that Annex K be either removed from the next revision of the C standard, or deprecated and then removed.
I support that recommendation.
The C18 standard did not alter the status of Annex K. There is a paper N2336 advocating for making some changes to Annex K, repairing its defects rather than removing it altogether.
Ok, now a stand for TR24731-2:
Yes, I've used asprintf()/vasprintf() ever since I've seen them in glibc, and yes I am a very strong advocate of them.
Why?
Because they deliver precisely what I need over and over again: A powerful, flexible, safe and (relatively) easy to use way to format any text into a freshly allocated string.
I am also much in favor of the memstream functions: Like asprintf(), open_memstream() (not fmemopen()!!!) allocates a sufficiently large buffer for you and gives you a FILE* to do your printing, so your printing functions can be entirely ignorant of whether they are printing into a string or a file, and you can simply forget about how much space you will need.
Do you use a library or compiler with support for the TR24731-1 functions?
If so, which compiler or library and on which platform(s)?
Yes, Visual Studio 2005 & 2008 (for Win32 development obviously).
Did you uncover any bugs as a result of fixing your code to use these functions?
Sort of.... I wrote my own library of safe functions (only about 15 that we use frequently) that would be used on multiple platforms -- Linux, Windows, VxWorks, INtime, RTX, and uItron. The reason for creating the safe functions were:
We had encountered a large number of bugs due to improper use of the standard C functions.
I was not satisfied with the information passed into or returned from the TR functions, or in some cases, their POSIX alternatives.
Once the functions were written, more bugs were discovered. So yes, there was value in using the functions.
Which functions provide the most value?
Safer versions of vsnprintf, strncpy, strncat.
Are there any that provide no value or negative value?
fopen_s and similar functions add very little value for me personally. I'm OK if fopen returns NULL. You should always check the return value of the function. If someone ignores the return value of fopen, what is going to make them check the return value of fopen_s? I understand that fopen_s will return more specific error information which can be useful in some contexts. But for what I'm working on, this doesn't matter.
Are you planning to use the library in the future?
We are using it now -- inside our own "safe" library.
Are you tracking the TR24731-2 work at all?
No.
No, these functions are absolutely useless and serve no purpose other than to encourage code to be written so it only compiles on Windows.
snprintf is perfectly safe (when implemented correctly) so snprintf_s is pointless. strcat_s will destroy data if the buffer is overflowed (by clearing the concatenated-to string). There are many many other examples of complete ignorance of how things work.
The real useful functions are the BSD strlcpy and strlcat. But both Microsoft and Drepper have rejected these for their own selfish reasons, to the annoyance of C programmers everywhere.

Resources