memset_s (): Что означает стандарт с этим фрагментом текста? - PullRequest
12 голосов
/ 12 июня 2019

В C11, K.3.7.4.1 Функция memset_s , я нашел этот немного запутанный текст:

В отличие от memset, любой вызов memset_s функция должна оцениваться строго в соответствии с правилами абстрактной машины, как описано в (5.1.2.3).То есть любой вызов функции memset_s должен предполагать, что память, обозначенная s и n, может быть доступна в будущем и, следовательно, должна содержать значения, обозначенные c.

Это означает, что memset является , а не (обязательно) "оцененным строго в соответствии с правилами абстрактной машины".(Упомянутая глава: 5.1.2.3 Выполнение программы .)

Я не понимаю, какую свободу дает стандарт memset, который здесь явно исключен для memset_sи что это будет означать для разработчика любой функции.

1 Ответ

12 голосов
/ 12 июня 2019

Представьте, что вы прочитали пароль:

{
    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));

Это одна из немногих действительно полезных функций в Приложении K .(Мы можем обсудить преимущества повторения размера. Однако в более общем случае второй размер может быть переменной, а не константой, и тогда первый размер становится защитой во время выполнения от неуправляемой переменной.)

Обратите внимание, что это требование накладывается на компилятор, а не на библиотеку.Функция memset_s() будет вести себя правильно, если она вызывается, точно так же, как memset() будет вести себя правильно , если она вызывается.Обсуждаемое правило гласит, что компилятор должен вызвать memset_s(), даже если он может пропустить вызов memset(), поскольку переменная больше никогда не используется.

...