您是否使用TR 24731的“安全”function?

ISO C委员会( ISO / IEC JTC1 / SC21 / WG14 )已经出版TR 24731-1 ,并正在研究TR 24731-2 :

TR 24731-1:C库的扩展第一部分:边界检查接口

WG14正在研究更安全的C库函数。 这个TR的目的是修改现有的程序,通常是通过添加一个额外的缓冲区长度的参数。 最新的草案在N1225号文件中。 理由是在N1173号文件中。 这将成为技术报告types2。

TR 24731-2:C库的扩展 – 第二部分:dynamic分配函数

WG14正在研究更安全的C库函数。 这个TR面向使用dynamic分配的新程序,而不是缓冲区长度的额外参数。 最新的草案在N1337号文件中。 这将成为技术报告types2。

问题

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

自成立以来(当它是一个单一的TR)我一直是这些TR的口头批评者,并且不会在我的任何软件中使用它们。 它们掩盖了症状而不是处理原因,而且我认为如果有的话,它们会对软件devise产生负面影响,因为它们提供了一种错误的安全感,而不是促进现有的可以更有效地实现相同目标的做法。 我并不孤单,实际上我并不知道在开发这些TR的委员会之外有一个主要的支持者。

我使用glibc,因此知道我将不必处理这个废话,正如glibc的首席维护者Ulrich Drepper 所说 :

build议的安全(r)ISO C库未能完全解决问题。 …提议让程序员的生活更加困难是不会有帮助的。 但这正是所提出的。 …他们都需要做更多的工作,或者只是简单的愚蠢。

他继续提出一些build议function的细节问题,并在其他地方表示,glibc永远不会支持这一点。

奥斯汀集团(负责维护POSIX)对TR提出了非常严格的审查,他们的评论和委员会的回应在这里提供 。 奥斯汀集团的审查做了很好的工作,详细说明了与TR的许多问题,所以我不会在这里进入个别的细节。

所以底线是:我没有使用一个支持或者支持这个的实现,我不打算使用这些函数,我没有看到TR中的正面价值。 我个人认为,任何forms的TR依然存在的唯一原因,是因为微软最近被certificate是非常有能力通过标准委员会来抨击事情的,尽pipe遭到了广泛的反对。 如果这些function已经标准化了,我认为这些function将不会被广泛使用,因为这个提议已经存在了几年了,而且还没有得到真正的社区支持。

直接回答问题

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

  • 您是否使用支持TR24731-1function的库或编译器?

    不,我不知道。

  • 如果是这样,哪个编译器或库在哪个平台上?

    我相信这些function是由MS Visual Studio(例如MS VC ++ 2008 Edition)提供的,并且有警告鼓励您使用它们。

  • 您是否修复了使用这些函数的代码,从而发现了任何错误?

    还没。 我不希望在我的代码中发现很多。 我使用的其他一些代码 – 也许。 但是我还没有被说服。

  • 哪些function提供最大的价值?

    我喜欢printf_s()系列的函数不接受“ %n ”格式说明符。

  • 有没有提供任何价值或负面价值?

    tmpfile_s()tmpnam_s()函数是一个可怕的失望。 他们确实需要更像mkstemp() ,它们都创build文件并打开它,以确保没有TOCTOU(检查时间和使用时间)漏洞。 就目前来看,这两个价值很小。

    我也认为strerrorlen_s()提供的价值很小。

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

    我有两个想法。 我开始研究一个库,可以通过一个标准的C库实现TR 24731的function,但是由于需要进行unit testing来certificate它正常工作,所以已经陷入了困境。 我不确定是否继续。 我有一些我想要移植到Windows上的代码(主要是出于在所有平台上提供支持的不正当的愿望 – 现在在Unix衍生产品上工作了几十年)。 不幸的是,为了让它在没有MSVC编译器警告的情况下编译,我必须用东西来粘贴代码,以防止MSVC使用完全可靠的(当经过仔细使用的)标准C库函数时对我产生怀疑。 这不是开胃。 我不得不面对20多年来在这个时期发展起来的一个系统, 不得不处理某人的乐趣(让人们不需要的时候采用TR 24731)是令人讨厌的。 这就是为什么我开始开发图书馆的原因 – 允许我在Unix和Windows上使用相同的接口。 但我不知道我会从这里做什么。

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

    在收集问题数据的同时,我不去跟踪标准网站。 asprintf()vasprintf()函数可能是有价值的; 我会用这些。 我不确定内存streamI / Ofunction。 在C级标准化strdup()将是一个巨大的进步。 对于我来说,这似乎比第一部分(边界检查)接口更less有争议。

总的来说,我没有被第一部分“边界检查接口”所证实。 第2部分“dynamic分配函数”草案中的材料比较好。

如果这取决于我,我会沿着第1部分的方向移动,但我也修改了C99标准C库中的接口,它返回一个char *到string的开头(例如strcpy()strcat() ),所以不是返回一个指向开始的指针,而是返回一个指向新string末尾的空字节的指针。 这会使一些常见的习惯用法(比如重复地将string连接到另一个string的末尾)更高效,因为这会使得避免重复使用strcat()代码所呈现的二次行为变得微不足道。 这些replace都将确保输出string的空终止,就像TR24731版本一样。 我不完全反对检查界面的想法,也不是exception处理函数。 这是一个棘手的业务。


微软的实现与标准规范不一样

更新(2011-05-08)

另见这个问题 。 令人遗憾的是,对于TR24731function的实用性而言,一些function的定义在微软的实现和标准之间是不同的,使得它们对我来说是无用的。 我的回答引用了vsnprintf_s()

例如,TR 24731-1说vsnprintf_s()的接口是:

 #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()的接口是:

 int vsnprintf_s( char *buffer, size_t sizeOfBuffer, size_t count, const char *format, va_list argptr ); 

参数

  • 缓冲区 – 输出的存储位置。
  • sizeOfBuffer – 输出缓冲区的大小。
  • count – 要写入的最大字符数(不包括结束空字符)或_TRUNCATE。
  • 格式 – 格式说明。
  • argptr – 指向参数列表的指针。

请注意,这不仅仅是一个types映射的问题:固定参数的数量是不同的,因此是不可调和的。 对我(也可能是标准委员会)来说,我还不清楚“sizeOfBuffer”和“count”的好处。 它看起来像是两次相同的信息(或者,至less对于这两个参数,通常会用相同的值来编写代码)。

同样, scanf_s()及其亲属也有问题。 微软表示,缓冲区长度参数的types是unsigned (明确指出'尺寸参数是unsignedtypes,而不是size_t ')。 相反,在附录K中,size参数是rsize_ttypes,它是size_t的受限变体( rsize_tsize_t另一个名称,但RSIZE_MAX小于SIZE_MAX )。 所以,再次,调用scanf_s()的代码必须以不同的方式写入Microsoft C和Standard C.

最初,我打算使用“安全”函数来获取一些在Windows和Unix上干净地编译的代码,而不需要编写条件代码。 由于这是因为微软和ISO的function并不总是一样,所以放弃的时间已经到了。


Visual Studio 2015中Microsoft's vsnprintf()更改

vsnprintf()的Visual Studio 2015文档中,注意到界面已经改变:

从Visual Studio 2015和Windows 10中的UCRT开始, vsnprintf不再与_vsnprintf相同。 vsnprintf函数符合C99标准; 保留_vnsprintf以保持向后兼容性。

但是, vsnprintf_s()的Microsoft接口没有改变。


微软和附件K之间差异的其他例子

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

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

localtime_s()的MSDN变体相比,定义如下:

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

和POSIX变体localtime_r()定义为:

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

除了名称之外,C11标准和POSIXfunction是相同的。 即使它与C11标准共享一个名称,微软的function在界面上也是不同的。

另一个差异的例子是微软的strtok_s()和附件K的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); 

请注意,Microsoft变体有3个参数,而附件K变体有4个。这意味着微软strtok_s()的参数列表与POSIX的strtok_r()兼容 – 所以如果您更改函数名称(例如由一个macros) – 但标准C(附件K)版本是不同的两个额外的论据。


ISO / IEC 9899:2011 – C11标准

C11标准( 2010年12月草案 ;您可以从ANSI网上商店获得30美元的ISO / IEC 9899:2011的权威标准的PDF副本)确实具有TR24731-1的function,作为标准。 它们在附件K(边界检查接口)中定义,它是“规范的”而不是“信息的”,但它是可选的。

C11标准中没有TR24731-2的function – 这是令人难过的,因为vasprintf()函数及其相关可能是非常有用的。

快速总结:

  • C11包含TR24731-1
  • C11不包含TR24731-2

build议从C11的inheritance人中删除附件K.

去复本者在另一个问题的评论中指出,ISO C标准委员会(ISO / IEC JTC1 / SC22 / WG14)

  • 附件K – 边界检查接口的 N1967 现场经验

它包含对附件K函数的一些现有实现的引用 – 它们都没有被广泛使用(但是如果你感兴趣,你可以通过文档find它们)。

文件以build议结束:

因此,我们build议将附件K从C标准的下一版本中删除,或者弃用,然后删除。

我支持这一build议。

好的,现在代表TR24731-2:

是的,自从我在glibc中看到它们以来,我一直使用asprintf() / vasprintf() ,是的,我是一个强大的倡导者。

为什么? 因为它们提供了我所需要的东西:一种function强大,灵活,安全和(相对)易于使用的方法,将任何文本格式化为新分配的string。

我也赞成memstreams:像asprintf()open_memstream() (而不是fmemopen() !!!)为你分配一个足够大的缓冲区,并给你一个FILE*来做你的打印,所以你的打印function可以完全不知道它们是打印成string还是文件,你可以简单的忘记这个问题,你需要多less空间。

您是否使用支持TR24731-1function的库或编译器? 如果是这样,哪个编译器或库在哪个平台上?

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

您是否修复了使用这些函数的代码,从而发现了任何错误?

sorting….我写了我自己的安全函数库(只有大约15个,我们经常使用),将在多个平台上使用 – Linux,Windows,VxWorks,INtime,RTX和uItron。 创build安全function的原因是:

  • 由于不正确地使用标准的C函数,我们遇到了大量的错误。
  • 我不满意从TRfunction传入或返回的信息,或在某些情况下,他们的POSIX备选信息。

一旦函数写完了,就会发现更多的错误。 所以是的,使用这些function是有价值的。

哪些function提供最大的价值?

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

有没有提供任何价值或负面价值?

fopen_s和类似的函数为我个人增加了很less的价值。 我很好,如果fopen返回NULL。 你应该总是检查函数的返回值。 如果有人忽略了fopen的返回值,那么是什么让他们检查fopen_s的返回值呢? 我明白,fopen_s将返回更具体的错误信息,这在某些情况下可能是有用的。 但是对于我正在做的事情,这并不重要。

你打算将来使用图书馆吗?

我们现在正在使用它 – 在我们自己的“安全”库中。

你跟踪TR24731-2的工作吗?

没有。

不,这些function绝对没有用处,除了鼓励代码编写,所以它只能在Windows上编译。

snprintf是完全安全的(当正确实施时),snprintf_s是毫无意义的。 如果缓冲区溢出,strcat_s将销毁数据 (通过清除连接string)。 还有许多其他例子完全不知道事情是如何工作的。

真正有用的function是BSD strlcpy和strlcat。 但是微软和Drepper都为了自己的私心而拒绝了这些,让C程序员无处不在。