memset_s():此文本的标准含义是什么?

Dev*_*lar 12 c language-lawyer

在C11中,K.3.7.4.1 memset_s函数,我发现了一些相当混乱的文本:

不同于memsetmemset_s必须严格按照(5.1.2.3)中所述的抽象机规则评估对函数的任何调用。也就是说,对该memset_s函数的任何调用均应假定指示,s并且n将来可能会访问该内存,因此必须包含指示的值c

这意味着,memset(必须的)“进行评价严格按照抽象机的规则”。(所引用的章节是5.1.2.3 程序执行。)

我不明白标准memset在这里明确排除了的余地memset_s,以及这对任何一个函数的实现者意味着什么。

Jon*_*ler 12

假设您已经读过密码:

{
    char password[128];

    if (fgets(password, sizeof(password), stdin) != 0)
    {
        password[strcspn(password), "\n\r"]) = '\0';
        validate_password(password);
        memset(password, '\0', sizeof(password));
    }
}
Run Code Online (Sandbox Code Playgroud)

您已经仔细修改了密码,以免意外被发现。

不幸的是,允许编译器省略该memset()调用,因为password不再使用它。的规则memset_s()意味着不能忽略该呼叫;该password变量必须被清零,不管优化。

memset_s(password, sizeof(password), '\0', sizeof(password));
Run Code Online (Sandbox Code Playgroud)

这是附件K中为数不多的真正有用的功能之一。(我们可以辩论必须重复使用大小的优点。但是,在更一般的情况下,第二个大小可以是变量,而不是常量,然后第一个大小将成为运行时保护,以防止变量失控。 )

请注意,此要求放在编译器而不是库上。该memset_s()功能将正确的行为,如果它被调用时,就如同memset()将正确的行为,如果它被调用。讨论中的规则说,编译器必须调用memset_s(),即使它可以省略该调用,memset()因为不再使用该变量。

  • 不一定,不是-尤其是因为尚不清楚,您可以安全地将volatile指针传递给一个不知道它会得到一个的函数。 (2认同)
  • @EugeneSh.:恕我直言,一个简单的循环`for (size_t i = 0; i < sizeof password; i++) { *(volatile char *)(password + i) = 0; }` 应该可以解决问题,使 `memset_s` 成为 C 标准的一个相当无用的补充。 (2认同)
  • @chqrlie我不会称之为无用的。您也可以用循环替换`memset`。 (2认同)