Как избежать вызова fopen () с буфером, который не заканчивается нулем в C? - PullRequest
0 голосов
/ 20 сентября 2018

Давайте посмотрим на этот пример:

static FILE *open_file(const char *file_path)
{
    char buf[80];
    size_t n = snprintf(buf, sizeof (buf), "%s", file_path);
    assert(n < sizeof (buf));
    return fopen(buf, "r");
}

Здесь assert() отключен.Со страницы руководства для snprintf:

"После успешного возврата эти функции возвращают количество напечатанных символов (исключая нулевой байт, используемый для завершения вывода в строки)."

Итак, еслион возвращает 80, тогда строка заполнит буфер и не будет завершена \ 0.Это вызовет проблему, поскольку fopen() предполагает, что оно завершено нулем.

Каков наилучший способ предотвратить это?

Ответы [ 3 ]

0 голосов
/ 20 сентября 2018

Итак, если он вернет 80, то строка заполнит буфер и не будет завершена как \0

Это неверно: строка будет нулевойпрекращено независимо от того, что вы принимаете за file_path.Очевидно, что строка будет обрезана в sizeof(buf)-1.

Обратите внимание, что snprintf также может вернуть число выше 80.Это будет означать, что строка, которую вы хотите напечатать, длиннее, чем предоставленный вами буфер.

Каков наилучший способ предотвратить это?

Вы уже делаетеэто: assert не является необходимым для предотвращения неопределенных строк.Вы можете использовать возвращаемое значение, чтобы решить, произошло ли какое-либо усечение, и передать больший буфер для компенсации:

// Figure out the size
size_t n = snprintf(NULL, 0, "%s", file_path);
// Allocate the buffer and print into it
char *tmpBuf = malloc(n+1);
snprintf(tmpBuf, n+1, "%s", file_path);
// Prepare the file to return
FILE *res = fopen(tmpBuf, "r");
// Free the temporary buffer
free(tmpBuf);
return res;
0 голосов
/ 20 сентября 2018

Здесь есть несколько проблем.

Первый assert() используется для выявления проблем как часть тестирования дизайнера.Он не предназначен для использования в производственном коде.

Во-вторых, если путь к файлу не завершен, вы действительно хотите вызвать fopen()?

Обычно, это делается, чтобы добавить одиндо ожидаемого количества символов.

static FILE *open_file(const char *file_path)
{
    char buf[80 + 1] = {0};

    size_t n = snprintf(buf, 80, "%s", file_path);
    assert(n < sizeof (buf));
    return fopen(buf, "r");
}
0 голосов
/ 20 сентября 2018

Каков наилучший способ предотвратить это?

Просто, не указывайте в нем ненулевую завершенную строку.Помимо академических вопросов, вы контролируете код, который пишете.Вам не нужно защищаться от саботажа проекта всеми возможными способами, вам просто не нужно саботировать себя.

Если бы все проверяли и перепроверяли все в коде, потеря производительности была бы невероятной.Есть причина, по которой fopen этого не делает.

...