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?
Yes, Visual Studio 2005 & 2008 (for Win32 development obviously).
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:
Once the functions were written, more bugs were discovered. So yes, there was value in using the functions.
Safer versions of vsnprintf, strncpy, strncat.
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.
We are using it now -- inside our own "safe" library.
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.
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:
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.
Ok, now a stand for TR24731-2:
Yes, I've used
asprintf()
/vasprintf()
ever since I've seen them in the 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 memstreams: Like
asprintf()
,open_memstream()
(notfmemopen()
!!!) allocates a sufficiently large buffer for you and gives you aFILE*
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 the question, how much space you will need.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?
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?
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()
andstrcat()
) 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 usesstrcat()
. 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()
.Similarly, there are also problems with
scanf_s()
and its relatives. Microsoft says that the type of the buffer length parameter isunsigned
(explicitly stating 'The size parameter is of typeunsigned
, notsize_t
'). In contrast, in Annex K, the size parameter is of typersize_t
, which is the restricted variant ofsize_t
(rsize_t
is another name forsize_t
, butRSIZE_MAX
is smaller thanSIZE_MAX
). So, again, the code callingscanf_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 2015In the Visual Studio 2015 documentation for
vsnprintf()
, it notes that the interface has changed: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:compared with the MSDN variant of
localtime_s()
defined as:and the POSIX variant
localtime_r()
defined as: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'sstrtok_s()
:vs:
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'sstrtok_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 discussesqsort_s()
as defined by Microsoft andqsort_s()
as defined by TR24731-1 — again, the interfaces are different.ISO/IEC 9899:2011 — C11 Standard
The C11 standard (December 2010 Draft; you can 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:
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)
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.