Как этот буфер может быть переполнен?
Я заранее прошу прощения за бесполезное название этого вопроса, но, похоже, ничто не подходит лучше.
Идея здесь состоит в том, чтобы скопировать argv
в другую переменную, по сути сделав его копию. Итак, основная идея того, что делает функция, заключается в том, чтобы использовать malloc()
, чтобы запросить некоторое пространство для копии, а затем выполнить итерацию по argv
, создавая копии каждого элемента.
Это код, с которым я работаю, среда разработки сейчас Visual Studio 2019 (даже если это не строго компилятор C...):
// Returns a copy of an array of strings (intended for argv, but should work with any of them):
wchar_t** copyArgv(size_t argc, wchar_t* argv[]) {
// Allocate space for the array of arguments:
wchar_t** argsCopy = malloc(((argc + 1) * sizeof(wchar_t*)));
if (!argsCopy)
return NULL;
// Copy each one of them:
for (size_t i = 0; i < argc; i++) {
argsCopy[i] = _wcsdup(argv[i]);
if (!argsCopy[i]) {
// Should also free any previous copied string I left that part out in the paste.
free(argsCopy);
return NULL;
}
}
argsCopy[argc] = NULL;
return argsCopy;
}
Я пробовал разные способы сделать копию argv, но каждый из них позволяет VS полагать, что может быть переполнение буфера, когда я делаю копию аргумента (строка: argsCopy[i] = _wcsdup(argv[i]);
) или считываю недопустимым данные в следующей строке, означающие чтение за пределами зарезервированного пространства.
Все это привело меня к мысли, что проблема заключается в (сейчас) единственном вызове malloc()
, чтобы зарезервировать пространство для массива аргументов.
И все же я бьюсь головой о стену, пытаясь понять, в чем проблема, я имею в виду, я думаю, что я требую достаточно места.
Я пробовал и другие компиляторы, последние стабильные версии Clang и GCC, похоже, не показывают такого предупреждения. Поэтому я решил спросить вас, бывалые программисты, можете ли вы обнаружить проблему или это какая-то ошибка компилятора (вряд ли, я уверен, что).
Для справки: точные предупреждения, которые выдает VS2019 (в 64-битной компиляции):
В назначении:
Переполнение буфера при записи в argsCopy: размер записи составляет "((argc + 1)) * sizeof (wchar_t *)", но может быть записано "16".
Следующая строка, тест для NULL:
Чтение недопустимых данных из argsCopy: читаемый размер составляет ((argc + 1)) * sizeof (wchar_t *) 'байтов, но может быть прочитано 16 байтов.
Ответы
Ответ 1
Это предупреждения от статического анализатора. Например, он пытается распознать ситуации переполнения буфера.
Предупреждение
Важно отметить, что это предупреждения, а не сообщения об ошибках. Компилятор говорит, что может быть что-то потенциально не так. Статический анализ, как правило, сложная вещь.
Ложно положительный
Нет ситуации переполнения буфера, поэтому это ложный положительный результат. Я бы предположил, что это сообщение исчезнет в будущем обновлении.
Немного изменить код
Если мы изменим строку выделения памяти следующим образом:
wchar_t** argsCopy = (wchar_t**)calloc(argc + 1, sizeof(wchar_t*));
тогда больше не будет предупреждений от Visual Studio 2019.
Количество выделенных байтов остается неизменным. Тем не менее, предупреждения исчезают.
Тестовое задание
Перед изменением список ошибок VS выглядит следующим образом:
После применения предложенных мной изменений исчезли предупреждения:
Ответ 2
Вы не должны освобождать память, указанную двойным указателем. Это может привести к утечке памяти. Вы должны были делать
free(argsCopy[0]);
Ответ 3
Однако я могу ошибаться, поиграв с онлайн-копией визуальной студии (https://rextester.com/l/c_online_compiler_visual), я вынужден предположить, что вы забыли включить string.h
или wchar.h
(любой из них работает). Visual Studio предполагает, что ваш возвращаемый тип является целым числом вместо wchar_t *, так как функция не определена. Кажется, что есть немного "волшебства" из-за того, что это зарезервированная функция, начинающаяся с _
, и поэтому она не выдает других предупреждений? Опять же без вашего точного окружения, хотя я вынужден частично спекулировать (ваш комментарий об изменении цели дал мне, надеюсь, правильный совет).
Ответ 4
Ключевым моментом может быть то, что вы не использовали недостаточно места для хранения данных, которые хотите скопировать.
Я не знаю, действительно ли я понимаю, что вы хотите сделать, я предполагаю, что вы хотите скопировать двумерный символьный массив в другой сегмент памяти, а затем вернуть его адрес, и массив имеет строки 'argc', адрес каждой строки строки хранится в массиве argv.
Но почему вы использовали argc+1
вместо argc
? Для malloc
дополнительного пространства для предотвращения переполнения буфера? и что более важно, sizeof(wchar_t*)
вернет размер указателя (8 байт в 64-битной системе). Он не вернет размер одной строки в нужном нам двумерном массиве.
Ответ 5
1) Один из способов репликации argv описан ниже, но. 2) Я не могу понять, почему вы хотите сделать копию argv? какие варианты использования/пользовательские проблемы это решает?
как я упоминал в (1), здесь есть один из способов, который заключается в копировании всего содержимого argv в ваш буфер. Это выглядит примерно так (PS: могут быть ошибки компиляции, когда я печатаю в телефоне, находясь в такси, поэтому у меня нет доступа к высококачественному C-компилятору для перекрестной проверки)
int numArgc = argc
char** argvCopy;
for (i=0;i<argc,i++)
{
argvCopy[i] = malloc(sizeof(char)*strlen(argv[i]));
strcpy(argvCopy[i], argv[i]);
}
//please do not forget to Free this malloc'ed memory (a very common C programming error) //when you don't need it anymore
пожалуйста, расскажите проблему, которую вы хотите решить