Почему strcpy вызывает ошибку сегментации глобальных переменных?

StackOverflow https://stackoverflow.com/questions/122877

Вопрос

Итак, у меня есть код C:

#include <stdio.h>
#include <string.h>

/* putting one of the "char*"s here causes a segfault */
void main() {
  char* path = "/temp";
  char* temp;
  strcpy(temp, path);
}

Это компилируется, запускается и ведет себя так, как выглядит.Однако если один или оба указателя на символы объявлены как глобальная переменная, strcpy приведет к ошибке сегментации.Почему это происходит?Очевидно, в моем понимании объема есть ошибка.

Это было полезно?

Решение

Как упоминалось в других плакатах, корень проблемы в том, что temp не инициализирован.Когда она объявлена ​​в стеке как автоматическая переменная, она будет содержать весь мусор, оказавшийся в этой области памяти.Очевидно, для компилятора+ЦП+ОС, который вы используете, мусор в этом месте является допустимым указателем.Функция strcpy "успешает" в том, что она не выполняет сегментацию, а на самом деле копирует строку в какое-то произвольное место в другом месте памяти.Подобная проблема повреждения памяти вселяет страх в сердца программистов C во всем мире, поскольку ее чрезвычайно сложно отлаживать.

Когда вы перемещаете объявление переменной temp в глобальную область видимости, оно помещается в раздел BSS и автоматически обнуляется.Попытки разыменовать *temp приводят к сбою сегмента.

Когда вы перемещаете *path в глобальную область видимости, *temp перемещается на одну позицию в стеке вверх.Мусор в этом месте, очевидно, не является допустимым указателем, поэтому разыменование *temp приводит к сбою сегмента.

Другие советы

Переменная temp не указывает ни на какое хранилище (память) и не инициализирована.

если temp объявлен как char temp[32]; тогда код будет работать независимо от того, где он объявлен.Однако есть и другие проблемы с объявлением temp с фиксированным размером, но это вопрос для другого дня.

Теперь, почему происходит сбой при объявлении глобально, а не локально.Удача...

При локальном объявлении значение temp берется из того значения, которое может находиться в стеке в данный момент.Это удача, что он указывает на адрес, который не вызывает сбоя.Однако это уничтожает память, используемую кем-то другим.

При глобальном объявлении на большинстве процессоров эти переменные будут храниться в сегментах данных, которые будут использовать нулевые страницы.Таким образом char *temp выглядит так, как будто было объявлено char *temp=0.

Вы забыли выделить и инициализировать temp:

temp = (char *)malloc(TEMP_SIZE);

Просто убедитесь, что TEMP_SIZE достаточно велик.Вы также можете вычислить это во время выполнения, а затем убедиться, что размера достаточно (должен быть как минимум strlen(path))

Как упоминалось выше, вы забыли выделить место для temp.я предпочитаю strdup к malloc+strcpy.Он делает то, что вы хотите.

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

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

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

Я хотел бы переписать первый фрагмент Адама как

// Make temp a static array of 256 chars
char temp[256];
strncpy(temp, sizeof(temp), path);
temp[sizeof(temp)-1] = '\0';

Таким образом вы:

1. don't have magic numbers laced through the code, and
2. you guarantee that your string is null terminated.

Второй момент связан с потерей последнего символа исходной строки, если ее длина >=256 символов.

Важная часть, на которую следует обратить внимание:
Строка назначения dest должна быть достаточно большой для приема копии.
В вашей ситуации у temp нет памяти, выделенной для копирования.

Скопировано со страницы руководства strcpy:

DESCRIPTION
   The  strcpy()  function  copies the string pointed to by src (including
   the terminating '\0' character) to the array pointed to by  dest.   The
   strings  may not overlap, and the destination string dest must be large
   enough to receive the copy.

Вы вызываете неопределенное поведение, поскольку не инициализируете temp переменная.Он указывает на случайное место в памяти, поэтому ваша программа может работать, но скорее всего будет сегфолт.Вам нужно, чтобы строка назначения была массивом или указывала на динамическую память:

// Make temp a static array of 256 chars
char temp[256];
strncpy(temp, 256, path);

// Or, use dynamic memory
char *temp = (char *)malloc(256);
strncpy(temp, 256, path);

Кроме того, используйте strncpy() вместо strcpy() во избежание переполнения буфера.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top