首页 > 后端开发 > C++ > 正文

TIL CANnex K 存在,但您不应该使用它

DDD
发布: 2024-11-03 13:58:03
原创
344 人浏览过

TIL CAnnex K exists but you shouldn

Annex K 是技术名称。其他常见关键字是 __STDC_LIB_EXT1__ 和 __STDC_WANT_LIB_EXT1__。附件 K 定义了“安全”_s 后缀,例如 sprintf_s() 和 scanf_s()。

另请查看附录 K (2015) 的现场经验和边界检查 - cppreference.com 技术文档。

目标

_s() 函数有什么意义?他们检查参数是否有更多不变量,例如“如果流为空、字符串为空、bufsz 为零或缓冲区写入超出指定长度的越界,则将调用约束处理程序”。这似乎是个好主意,对吧?是的!确实如此!

要点是你可以/可以这样做:

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>

int main() {
  printf_s("Hello %s!\n", "Alan Turing");
  return 0;
}
登录后复制
登录后复制

这与没有 __STDC_WANT_LIB_EXT1__ 的正常做事方式相比如何?

幸福之路

FILE *file = fopen("hello.txt", "r");
// file is OK.
登录后复制
FILE *file;
errno_t err = fopen_s(&file, "hello.txt", "r");
// file is OK
登录后复制

悲伤之路

FILE *file = fopen("notexist.txt", "r");
// file is NULL, errno is set.
登录后复制
FILE *file;
errno_t err = fopen_s(&file, "notexist.txt", "r");
// file is NULL, err is set.
登录后复制

坏路

FILE *file = fopen(NULL, NULL);
// idk.
登录后复制
FILE *file;
errno_t err = fopen_s(&file, NULL, NULL);
// Constraint violated. Abort with message.
登录后复制

是的,您可以自定义约束处理程序以仅登录到文件并继续,就像什么都没发生一样。

set_constraint_handler_s(ignore_handler_s);
set_constraint_handler_s(abort_handler_s);
set_constraint_handler_s(my_awesome_handler);
登录后复制

注意到普通的 fopen() 如何具有相同的返回值(可能不同的 errno)来指示不同级别的错误严重程度?这就是 fopen_s() 试图改进的地方。至少,这是我读到的。我认为它就像 Rust 的panic!() 与返回的 Result 相比。它还可能通过提供 size_of_dest 参数来帮助阻止一些缓冲区溢出攻击,以避免溢出任何目标缓冲区,如 strcpy_s() 和 gets_s()。

char* gets( char* str ); // (removed in C11)
char* gets_s( char* str, rsize_t n ); // (since C11, annex K)
登录后复制

将 stdin 读入 str 指向的字符数组中,直到找到换行符或发生文件结尾。在读入数组的最后一个字符之后立即写入一个空字符。换行符被丢弃,但不存储在缓冲区中。

gets() 函数不执行边界检查,因此该函数极易受到缓冲区溢出攻击。它不能安全使用(除非程序运行在限制 stdin 上显示内容的环境中)。因此,该函数在 C99 标准的第三次勘误中已被弃用,并在 C11 标准中被完全删除。 fgets() 和 gets_s() 是推荐的替代品。

警告:切勿使用 gets()。

// BAD
char buffer[1000];
gets(buffer);
// ⚠️ Could write >1000 chars to `buffer`!
登录后复制
// GOOD
char buffer[1000];
gets_s(buffer, sizeof(buffer));
// This will stop at 1000 chars.
登录后复制

_s() 函数似乎非常适合阻止可能发生缓冲区溢出的常见位置。

问题

它们并没有在所有地方实现。 _s() 函数是一个扩展,在 GNU 的 glibc 等 libc 实现中不可用。还有其他一些小问题,比如它对于多线程来说不符合人体工程学,以及对于 strcpy_s() 之类的东西使用 sizeof(src) 而不是 sizeof(dest) 的常见错误,但与可用性问题相比,所有这些都显得苍白无力。

我能找到的大多数在线信息似乎表明 MSVC 是唯一实现了附件 K 的主要编译器/libc。

鉴于这些花哨的 _s() 函数并不存在于您的代码需要编译的所有地方,您需要编写如下代码:

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>

int main() {
  printf_s("Hello %s!\n", "Alan Turing");
  return 0;
}
登录后复制
登录后复制

...对于您想要执行 strlen_s() 或 fopen_s() 或 strcpy_s() 的每个实例。这是发疯的好方法。

很明显,你不会编写依赖于平台的代码只是为了执行基本的 printf() 和 strcpy() 但是将所有 #ifdef __STDC_LIB_EXT1__ #else 内容包装在库中怎么样?

我通过 Google 快速搜索发现了两个看起来很有前途的库:

  • safec:安全 C 库网站 GitHub 页面 ⭐335
  • sbaresearch/slibc:C11 附件 K“边界检查接口”ISO/IEC 9899:2011 ⭐14
  • 的实现

所以...如果您想(或安全人员要求)使用 _s() 函数,但又不想将自己限制为 MSVC,那么您可以使用其中一个 ☝ 库。

?如需了解更多信息,请参阅附录 K (2015) 的现场经验和边界检查 - cppreference.com 技术文档。

以上是TIL CANnex K 存在,但您不应该使用它的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板