Рискну ли я переполнению буфера здесь и как бы этого избежать? - PullRequest
0 голосов
/ 08 декабря 2018

Я реализовал простую структуру списка, в которой отдельные элементы списка определяются следующей структурой:

struct list_elem {
    struct list_elem *next;  // ptr to the next element
    char             *data;  // ptr to data
};

Теперь я хочу сделать следующее:

struct list_elem *elem;
int main() {
    elem->data = "some_string";
    strcat(elem->data, "another_string");
}

Я переживаю из-за переполнения, потому что справочная страница состояний strcat:

Функция char *strcat(char *dest, const char *src) добавляет строку src к строке dest, перезаписывая завершающий нулевой байт ('\ 0') в конце dest, а затем добавляет завершающий нулевой байт.Строки могут не перекрываться, и в строке dest должно быть достаточно места для результата. Если dest недостаточно велико, поведение программы непредсказуемо ;переполнение буфера - любимая возможность для атак на защищенные программы.

И в основном я не знал, сколько памяти выделено для моего элемента списка.

Ответы [ 2 ]

0 голосов
/ 08 декабря 2018

Это утверждение:

elem->data = "some_string";

делает указатель data на строковый литерал "some_string".
А здесь:

strcat(elem->data, "another_string");

вы пытаетесь скопировать строкулитерал "another_string" на указатель, который указывает на другой строковый литерал.Согласно стандарту, попытка изменить строковый литерал приводит к неопределенному поведению, поскольку он может храниться в хранилище только для чтения.

Вы должны выделить память для data, например:

elem->data = calloc(50, 1); // sizeof (char) is 1

Затем скопируйте "some_string" в него;

strcpy (elem->data, "some_string");

Затем объедините "another_string" к нему:

strcat (elem->data, "another_string");

В качестве альтернативы вы можете использовать snprintf() также:

snprintf (elem->data, 49, "%s%s", "some_string", "another_string");

РЕДАКТИРОВАТЬ:

Спасибо @alk за указание этого.

Указатель elem не указывает на допустимую память.Сначала вы должны выделить память для указателя struct list_elem elem, например:

elem = malloc (sizeof (struct list_elem));
if (elem == NULL)
    exit(EXIT_FAILURE);
0 голосов
/ 08 декабря 2018

Вы можете искать функции astrxxx (которые не являются стандартными функциями C).Они динамически распределяют память во время работы. Примеры реализации Github

  • astrcat реализован выше.
  • asprintf - это динамическая версия sprintf.
  • и болеепредоставляется некоторыми компиляторами GNU

Примечание: вы ДОЛЖНЫ БЕСПЛАТНО динамически распределять память !!

Плюс, вы должны использовать его следующим образом:

struct list_elem elem;    //removed *, as it can cause seg fault if not initialized. you have to initialize by using struct list_elem * elem=malloc(sizeof(struct list_elem)); or something.
int main() {
    elem.data = strdup("some_string");//you must free data later
    astrcat(&elem.data, "another_string");
    //use it
    free(elem.data);
}

Сначала struct list_elem* elem инициализируется как NULL, поэтому его необходимо инициализировать с действительным адресом перед -> инструкциями.Вы можете назначить указатель на раздел данных для data, который не может быть изменен в обычном режиме.

...