代码之家  ›  专栏  ›  技术社区  ›  Jonathan Leffler

您是否使用TR 24731“安全”功能?

  •  70
  • Jonathan Leffler  · 技术社区  · 16 年前

    ISO C委员会( ISO/IEC JTC1/SC21/WG14 已发表 TR 24731-1 正在努力 TR 24731-2 :

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

    wg14正在研究一个关于更安全的C库函数的tr。这个tr面向修改现有程序,通常通过添加一个具有缓冲区长度的额外参数。最新草案载于N1225号文件。文件N1173中有一个基本原理。这将成为技术报告类型2。

    TR 24731-2:C库扩展第二部分:动态分配函数

    wg14正在研究一个关于更安全的C库函数的tr。这个tr面向使用动态分配而不是缓冲区长度的额外参数的新程序。最新草案载于N1337号文件。这将成为技术报告类型2。

    问题

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

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

    我用的是glibc,因为我知道我不用去处理这些废话,作为glibc的首席维护官ulrich drepper, said about the topic :

    建议的SAFE(R)ISO C库 未能完全解决问题。 …提议创造一个 程序员更难做到的是 帮助。但这正是 提出。…他们都需要更多 要做的工作或只是简单的工作 愚蠢的。

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

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

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

        2
  •  28
  •   Jonathan Leffler    6 年前

    直接回答问题

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

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

      不,我没有。

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

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

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

      还没有。我不希望在我的代码中发现很多。我使用的其他一些代码-可能。但我还没有被说服。

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

      我喜欢printf_()函数系列不接受 %n '格式说明符。

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

      这个 tmpfile_s() tmpnam_s() 功能令人失望。他们真的需要更像 mkstemp() 它创建并打开文件以确保不存在TOCTU(检查时间、使用时间)漏洞。事实上,这两种方法的价值很低。

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

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

      我对此有两种想法。我开始在一个库上工作,这个库将在标准的C库上实现TR24731的功能,但被证明它正常工作所需的大量单元测试所捕获。我不确定是否继续。我有一些代码要移植到Windows上(主要是出于在所有平台上提供支持的一种反常愿望——它已经在Unix衍生产品上工作了几十年了)。不幸的是,要让它在没有msvc编译器警告的情况下编译,我必须用一些东西来粉饰代码,以防止msvc使用完全可靠(小心使用时)的标准C库函数来窃取我的信息。这不是开胃菜。我必须处理20年中大部分时间在那个时期发展起来的系统,这已经够糟糕的了;必须处理某人的有趣想法(让人们在不需要的时候采用TR 24731)是令人讨厌的。这也是我开始开发库的部分原因——允许我在Unix和Windows上使用相同的接口。但我不确定我会从这里做什么。

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

      直到我在收集问题数据的时候去了标准网站,我才开始跟踪它。这个 asprintf() vasprintf() 函数可能是有价值的,我会使用它们。我不确定内存流I/O功能。有 strdup() 在C级标准化将是一个巨大的进步。对于我来说,这似乎没有第1部分(边界检查)接口那么有争议。

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

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


    Microsoft的实现与标准规范不同

    更新(2011-05-08)

    也见此 question . 遗憾的是,对于tr24731函数的有用性来说,有些函数的定义在微软实现和标准之间是不同的,这使它们(对我来说)毫无用处。我的答案是 vsnprintf_s() .

    例如,tr 24731-1表示 VSNPrimtfx() 是:

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

    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() 及其亲属。 Microsoft 表示缓冲区长度参数的类型为 unsigned (显式说明“大小参数的类型为” 未签名的 不是 size_t ''。相反,在附录K中,尺寸参数为 rsize_t ,这是 西泽特 ( 拉西泽特 是的另一个名字 西泽特 但是 RSIZE_MAX 小于 SIZE_MAX )所以,代码调用 SCANFFA() 对于Microsoft C和标准C,必须以不同的方式编写。

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


    Microsoft的更改 vsnprintf() 在Visual Studio 2015中

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

    从Visual Studio 2015和Windows 10中的UCRT开始, vsnprintf 不再与相同 _vsnprintf . 这个 VSNPrTNF 功能符合C99标准; _vnsprintf 为了向后兼容而保留。

    但是,Microsoft界面 vsnprintf_s() 未更改。


    微软与附件K之间的其他差异示例

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

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

    localtime_s() 定义为:

    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标准函数和POSIX函数是等效的。微软的函数在接口上是不同的,尽管它与C11标准共享一个名称。

    另一个不同的例子是 Microsoft strtok_s() Annex K的 斯特罗克() :

    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个。这意味着微软的 斯特罗克() 与POSIX兼容 strtok_r() _“,因此,如果您更改函数名(例如通过宏)_“,对这些函数的调用实际上是可互换的,但是标准C(附录K)版本与带有额外参数的两个版本不同。

    问题 Different declarations of qsort_r() on Mac and Linux 有一个同样讨论的答案 qsort_s() 如微软和 QSORT*() 正如TR24731-1所定义的,接口是不同的。


    ISO/IEC 9899:2011_C11标准

    C11标准( December 2010 Draft ;您可以获得最终标准的PDF副本, ISO/IEC 9899:2011 (来自30美元的ansi网络商店)中的tr24731-1函数作为标准的可选部分。它们在附录K(边界检查接口)中定义,这是“规范性的”而不是“信息性的”,但它是可选的。

    C11标准中没有TR24731-2功能,这很遗憾,因为 VasPrimff() 函数及其相关函数可能非常有用。

    快速总结:

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

    将附件K从C11继承人中删除的建议

    Deduplicator 在A中指出 comment 关于另一个问题,即在ISO C标准委员会(ISO/IEC JTC1/SC22/WG14)面前有一个提案。

    它包含对附录K功能的一些现有实现的引用,这些功能都没有被广泛使用(但如果您感兴趣,可以通过文档找到它们)。

    文件以建议结尾:

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

    我支持这个建议。

        3
  •  7
  •   Jonathan Leffler    11 年前

    好了,现在站起来 对于 TR24731-2:

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

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

    我也非常赞成孟斯韦尔斯:比如 AsPrimff() , open_memstream() (不是) fmemopen() !!!!)为您分配足够大的缓冲区,并为您提供 FILE* 为了进行打印,您的打印功能可以完全不知道它们是打印到字符串还是文件中,您可以简单地忘记这个问题,即需要多少空间。

        4
  •  5
  •   Kevin    15 年前

    您是否使用支持TR24731-1函数的库或编译器? 如果是,哪个编译器或库以及在哪个平台上?

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

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

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

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

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

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

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

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

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

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

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

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

    不。

        5
  •  5
  •   user3080602    11 年前

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

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

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