Используя memcpy (), чтобы переместить хвост буфера в его начало?(Перекрытие) - PullRequest
0 голосов
/ 18 мая 2018

У меня есть буфер чтения двоичного файла, который читает структуры переменной длины. В конце буфера всегда будет неполная структура. Я хочу переместить такой конец буфера в его начало, а затем прочитать buffer_size - tail_len байт во время следующего чтения файла. Как то так:

char[8192] buf;
cur = 0, rcur = 0;
while(1){
  read("file", &buf[rcur], 8192-rcur);
  while (cur + sizeof(mystruct) < 8192){
    mystruct_ptr = &buf[cur];
    if (mystruct_prt->tailsize + cur >= 8192) break; //incomplete
    //do stuff
    cur += sizeof(mystruct) + mystruct_ptr->tailsize;
  }
  memcpy(buf,&buf[cur],8192-cur);
  rcur=8192-cur;
  cur = 0;
}

Это должно быть в порядке, если хвост маленький, а буфер большой, потому что тогда memcpy скорее всего не будет перекрывать скопированный сегмент памяти во время итерации одной копии. Однако это звучит немного рискованно, когда хвост становится большим - больше 50% буфера.

Если буфер действительно велик, а tail тоже огромен, тогда все равно должно быть в порядке, поскольку существует физический предел того, сколько данных может быть скопировано за одну операцию, которое, если я правильно помню, составляет 512 байт для современных процессоров x86_64, использующих векторные блоки. Я думал о добавлении условия, которое проверяет длину хвоста и, если оно слишком велико по сравнению с размером буфера, выполняет наивное побайтовое копирование, но вопрос таков:

Насколько большой слишком большой, чтобы считать такое перекрытие memcpy более или менее безопасным. tail > buffer size - 2kb

1 Ответ

0 голосов
/ 18 мая 2018

Согласно стандарту, memcpy() имеет неопределенное поведение, если области источника и назначения перекрываются. Неважно, насколько велики регионы или насколько они совпадают. Неопределенное поведение никогда не может считаться безопасным.

Если вы пишете в конкретную реализацию, и эта реализация определяет поведение для некоторого такого копирования, и вы не заботитесь о переносимости, тогда вы можете положиться на специфическое поведение вашей реализации в этом отношении. Но я рекомендую нет. Это было бы неприятной ошибкой, ожидающей укуса людей, которые решили использовать код в какой-то другой реализации. Может быть, даже будущее тебя.

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

...