关于C#:您是否使用TR 24731’安全’功能?

Do you use the TR 24731 'safe' functions?

ISO C委员会(ISO/IEC JTC1/SC21/WG14)发布了TR 24731-1,并正在研究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.

号问题

  • 您是否使用支持TR24731-1函数的库或编译器?
  • 如果是,哪个编译器或库以及在哪个平台上?
  • 您是否发现了由于修复代码以使用这些函数而导致的任何错误?
  • 哪些功能提供的价值最大?
  • 有没有没有提供任何价值或负值?
  • 你打算将来使用图书馆吗?
  • 你在跟踪TR24731-2的工作吗?


我从一开始就对这些TRS(当它是一个单一的TR时)进行了声乐批评,并且永远不会在我的任何软件中使用它们。它们掩盖了症状,而不是解决原因,我认为,如果有任何问题,它们将对软件设计产生负面影响,因为它们提供了一种错误的安全感,而不是促进现有实践,从而更有效地实现相同的目标。我并不孤单,事实上,我不知道在委员会之外有一个主要的支持者在制定这些TRS。

我使用glibc,因为我知道我将不必处理这些废话,正如glibc的主要维护人员ulrich drepper所说的主题:

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.

他继续详细讨论了一些被提议的函数的问题,并在其他地方指出glibc永远不会支持这一点。

奥斯汀集团(负责维护POSIX)对TR、他们的意见和委员会的回应进行了非常重要的审查。Austin Group Review非常好地详细说明了TR的许多问题,因此我不想在这里讨论个别的细节。

因此,底线是:我不使用支持或将支持这一点的实现,我也不打算使用这些函数,而且我在tr中看不到任何积极的价值。我个人认为,tr在任何形式上仍然存在的唯一原因是,它正受到微软的大力推动,微软最近证明了它非常有能力变瘦。尽管遭到广泛反对,但通用汽车还是冲击了标准委员会。如果这些功能曾经被标准化,我认为它们将永远不会被广泛使用,因为提案已经存在几年了,并且没有获得任何真正的社区支持。


直接回答问题

我喜欢罗伯特的回答,但我对我提出的问题也有一些看法。好的。

  • 您是否使用支持TR24731-1函数的库或编译器?好的。

    No, I don't.

    Ok.

  • 如果是,哪个编译器或库以及在哪个平台上?好的。

    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.

    Ok.

  • 您是否发现了由于修复代码以使用这些函数而导致的任何错误?好的。

    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.

    Ok.

  • 哪些功能提供的价值最大?好的。

    I like the fact that the printf_s() family of functions do not accept the '%n' format specifier.

    Ok.

  • 有没有没有提供任何价值或负值?好的。

    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.

    Ok.

    I also think that strerrorlen_s() provides very little value.

    Ok.

  • 你打算将来使用图书馆吗?好的。

    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.

    Ok.

  • 你在跟踪TR24731-2的工作吗?好的。

    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.

    Ok.

总的来说,我不相信第1部分"边界检查接口"。第2部分"动态分配函数"草案中的材料更好。好的。

如果由我决定的话,我会沿着第1部分的行移动一些,但是我也修改了c99标准C库中的接口,这些接口将char *返回到字符串的开头(例如strcpy()strcat()),这样它们就不会返回指向开始的指针,而是返回指向新字符串末尾的空字节的指针。这将使一些常见的习惯用法(例如重复地将字符串连接到另一个字符串的末尾)更加有效,因为避免重复使用strcat()的代码所表现出的二次性行为非常简单。这些替换将确保输出字符串的空终止,就像TR24731版本那样。我并不完全反对检查接口的想法,也不反对异常处理函数。这是一件棘手的事情。好的。Microsoft的实现与标准规范不同

更新(2011-05-08)好的。

另请参见此问题。遗憾的是,对于tr24731函数的有用性来说,有些函数的定义在微软实现和标准之间是不同的,这使它们(对我来说)毫无用处。我的回答引用了vsnprintf_s()。好的。

例如,TR 24731-1表示,与vsnprintf_s()的接口是:好的。

1
2
3
4
5
#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);

不幸的是,msdn说与vsnprintf_s()的接口是:好的。

1
2
3
4
5
6
7
int vsnprintf_s(
   char *buffer,
   size_t sizeOfBuffer,
   size_t count,
   const char *format,
   va_list argptr
);

参数好的。

  • 缓冲区-输出的存储位置。
  • size of buffer-输出缓冲区的大小。
  • count-要写入的最大字符数(不包括终止的空字符)或_truncate。
  • 格式-格式规范。
  • argptr-指向参数列表的指针。

注意,这不仅仅是类型映射的问题:固定参数的数量是不同的,因此是不可调和的。我也不清楚"sizeofbuffer"和"count"对我(也可能对标准委员会)有什么好处;它看起来像两次相同的信息(或者,至少,代码通常用两个参数相同的值编写)。好的。

同样,scanf_s()及其亲属也存在问题。微软称缓冲区长度参数的类型是unsigned(明确说明"大小参数是unsigned类型,而不是size_t类型")。相反,在附录K中,尺寸参数为rsize_t型,是size_t的限制性变体(rsize_tsize_t的另一个名称,但RSIZE_MAXSIZE_MAX小。因此,再次强调,调用scanf_s()的代码必须以不同的方式为Microsoft C和标准C编写。好的。

最初,我计划使用"safe"函数来获取一些代码,以便在Windows和Unix上清晰地编译,而无需编写条件代码。因为微软和ISO的功能并不总是相同,所以这是失败的,现在是放弃的时候了。好的。Visual Studio 2015中Microsoft的vsnprintf()的变化

在用于vsnprintf()的Visual Studio 2015文档中,它注意到接口已更改:好的。

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.

Ok.

但是,用于vsnprintf_s()的Microsoft界面没有改变。好的。微软与附件K之间的其他差异示例

在ISO/IEC 9899:2011附录K.3.8.2.4中,localtime_s()的C11标准变体定义为:好的。

1
2
struct tm *localtime_s(const time_t * restrict timer,
                       struct tm * restrict result);

localtime_s()的msdn变体相比,定义为:好的。

1
errno_t localtime_s(struct tm* _tm, const time_t *time);

和posix变体localtime_r()定义为:好的。

1
2
struct tm *localtime_r(const time_t *restrict timer,
                       struct tm *restrict result);

除名称外,C11标准函数和POSIX函数是等效的。微软的函数在接口上是不同的,尽管它与C11标准共享一个名称。好的。

另一个不同的例子是微软的strtok_s()和附件K的strtok_s():好的。

1
char *strtok_s(char *strToken, const char *strDelimit, char **context);

VS:好的。

1
char *strtok_s(char * restrict s1, rsize_t * restrict s1max, const char * restrict s2, char ** restrict ptr);

请注意,Microsoft变体有3个参数,而附录K变体有4个。这意味着Microsoft的strtok_s()的参数列表与posix的strtok_r()兼容,因此,如果更改函数名(例如,通过宏),对这些参数的调用实际上是可以互换的,但是标准的C(附件K)版本与额外的参数不同。好的。

在Mac和Linux上,qsort_r()的不同声明的问题有一个答案,也讨论了由微软定义的qsort_s()和由tr24731-1定义的qsort_s()——同样,接口是不同的。好的。 ISO / IEC标准:2011 9899 C11

的C11(2010十二月标准草案;你可以在一个时间obtain拷贝和PDF的nomenclaturii明确标准,ISO / IEC 9899:2011,从ANSI Web商店为30美元)是否有tr24731 - 1功能在它作为一个可选的部分标准。他们是实体,在附录K(bounds -"检查interfaces),这是比"informational规范地"而",但它是可选的。

的好。

有标准的不tr24731 C11 - 2功能在它-这是悲伤的,因为vasprintf()和它的功能真的亲戚可能是个有用的。

的好。

快速的总结:

的好。

  • 包含tr24731 C11 - 1
  • 不contain tr24731 C11 - 2
  • C18 w.r.t tr24731 C11是一样的。

建议是消除这种附件K是从successor C11

在comment deduplicator pointed了另一个问题,有建议在ISO C标准委员会(ISO / IEC jtc1 / sc22 / wg14)

的好。

  • n1967场经验与附录K - bounds interfaces检查

它包含一些references的extant implementations附录K的无土地的使用功能(大白,但你可以找到他们,如果你是通过文件interested)。

的好。

与recommendation结束的文件:

的好。

因此,在propose附录K,是不是removed从第二版的标准或deprecated C,然后removed。

的好。

和支持,recommendation。

的好。

的C18的地位没有改变标准的附录K。有advocating纸业n2336附录K为制作一些变化,而其repairing removing共defects比它。

的好。 好的。


好的,现在是TR24731-2的一个代表:

是的,自从我在glibc里见过他们以来,我就用过asprintf()/vasprintf(),是的,我是他们的强烈拥护者。

为什么?因为它们一遍又一遍地提供我所需要的:一种功能强大、灵活、安全且(相对)易于使用的方式,可以将任何文本格式化为新分配的字符串。

我也很支持Memstreams:像asprintf()open_memstream()(不是fmemopen()!!!!)为您分配足够大的缓冲区,并为您提供一个FILE*来进行打印,因此您的打印功能完全不知道它们是打印到字符串还是文件中,您可以简单地忘记这个问题,即需要多少空间。


不,这些函数是绝对无用的,除了鼓励编写代码之外没有其他用途,所以它只能在Windows上编译。

snprintf是完全安全的(正确实现时),所以snprintf没有意义。如果缓冲区溢出(通过清除连接到字符串),strcat_将销毁数据。还有许多其他完全不了解事物如何工作的例子。

真正有用的函数是bsd strlcpy和strlcat。但是微软和Drepper都出于自私的原因拒绝了这些,这让各地的C程序员都很恼火。


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)?

是的,Visual Studio 2005&2008(显然是针对Win32开发)。

Did you uncover any bugs as a result of fixing your code to use these functions?

某种程度上。。。。我编写了自己的安全函数库(我们经常使用的只有大约15个),它将用于多个平台——Linux、Windows、VxWorks、InTime、RTX和Uitron。创建安全功能的原因是:

  • 由于标准C函数的使用不当,我们遇到了大量的错误。
  • 我对传递到tr函数或从tr函数返回的信息不满意,在某些情况下,对它们的posix替代方法也不满意。

一旦函数被写入,就会发现更多的错误。所以是的,使用函数是有价值的。

Which functions provide the most value?

更安全版本的vsnprintf、strncpy、strncat。

Are there any that provide no value or negative value?

fopen_和类似的功能对我个人来说没有什么价值。如果fopen返回空值,我没问题。您应该始终检查函数的返回值。如果有人忽略了fopen的返回值,怎么让他们检查fopen的返回值?我理解fopen_将返回更具体的错误信息,在某些情况下可能有用。但对于我正在做的事情,这并不重要。

Are you planning to use the library in the future?

我们现在正在使用它——在我们自己的"安全"库中。

Are you tracking the TR24731-2 work at all?

不。