【问题标题】:memset_s(): What does the standard mean with this piece of text?memset_s():标准对这段文字意味着什么?
【发布时间】:2019-06-12 15:17:57
【问题描述】:

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

memset 不同,对memset_s 函数的任何调用都应严格按照(5.1.2.3)中描述的抽象机规则进行评估。也就是说,对memset_s 函数的任何调用都应假定sn 指示的内存将来可以访问,因此必须包含c 指示的值。

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

我无法理解标准赋予memset 的余地,此处明确排除了memset_s,以及这对任一函数的实现者意味着什么。

【问题讨论】:

标签: c language-lawyer


【解决方案1】:

假设你已经阅读了一个密码:

{
    char password[128];

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

您已经小心地破解了密码,以免被意外找到。

不幸的是,允许编译器省略memset() 调用,因为password 不再使用。 memset_s() 的规则表示调用不能省略;无论优化如何,password 变量必须归零。

memset_s(password, sizeof(password), '\0', sizeof(password));

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

请注意,此要求放在编译器而不是库上。 memset_s() 函数在被调用时会正常运行,就像memset()如果被调用时会正常运行一样。正在讨论的规则表明编译器必须调用memset_s(),即使它可以省略对memset()的调用,因为该变量不再使用。

【讨论】:

  • 不会memset((volatile void*)password, '\0', sizeof(password)); 解决它吗?
  • 不一定,不——尤其是因为不清楚你是否可以安全地将 volatile 指针传递给一个不知道它会得到一个函数的函数。
  • @DevSolar:是的,要求编译器实际生成对memset_s() 的调用,即使函数是memset(),也可以省略。库编写者只需确保 memset_s() 完成其工作。
  • @EugeneSh.:恕我直言,一个简单的循环 for (size_t i = 0; i < sizeof password; i++) { *(volatile char *)(password + i) = 0; } 应该可以解决问题,使 memset_s 成为 C 标准的一个相当无用的补充。
  • @chqrlie 我不会说它没用。你也可以用循环替换memset
猜你喜欢
  • 2021-07-10
  • 2017-05-05
  • 1970-01-01
  • 2023-01-03
  • 2017-12-31
  • 2018-09-04
  • 1970-01-01
  • 2020-11-04
  • 1970-01-01
相关资源
最近更新 更多