C: Копирование меньшего участка памяти в больший без знания размера меньшего, как в realloc()

Как функция realloc (c), которая принимает только длину нового раздела памяти, копирует старый (меньший, чтобы вызвать рассматриваемую ситуацию) раздел памяти? память на новую? (предполагается, что это необходимо, например, память не может быть найдена смежной с блоком old для его расширения)

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

Спасибо, Дж.

РЕДАКТИРОВАТЬ: код, иллюстрирующий крайний пример:

int main ( void ) {
  unsigned int i=0;
  void *test_ptr1, *test_ptr2;

  // this first bit just finds the size of the available heap, ignore it if you wish
  do {
    free(test_ptr1); 
    printf("%u\n",i);
    i+=1073741824; // 1GiB
  } while ((test_ptr1 = malloc(i)));
  i-=1073741824;
  do {
    free(test_ptr1); 
    printf("%u\n",i);
    i+=1048576; // 1MiB
  } while ((test_ptr1 = malloc(i)));
  i-=1048576;
  do {
    free(test_ptr1); 
     printf("%u\n",i);
     i+=1024; // 1KiB
  } while ((test_ptr1 = malloc(i)));
  i-=1024;
  do {
    free(test_ptr1);
    printf("%u\n",i); 
    i+=128; // 128B
  } while ((test_ptr1 = malloc(i)));
  i-=128;
  do {
    free(test_ptr1);
    printf("%u\n",i); 
    i++; // 1B
  } while ((test_ptr1 = malloc(i)));
  i--;

  // i is now equal to the size of the available heap (I think...)

  test_ptr1 = calloc(i-1, 1); // calloc all but one byte of the available heap
  test_ptr2 = malloc(1); // malloc the reamining byte
  printf("proving calloc: %u\n", ((char *)test_ptr1)[i-2]); // outputs 0, this might be a point of weakness int this program, if this is optimised in any way it fails to demonstrate the effect
  *(char *)test_ptr2 = 'c'; // initialise the byte to 'c'
  free(test_ptr1); // free the vast majority of the heap
  if ((test_ptr1 = realloc(test_ptr2, i-1))) { // realloc the one byte to the space taken up by the previous calloc that was freed in the previous line
    printf("realloc success: %c\n", *(char *)test_ptr1); // outputs c, but whats in the rest of this memory section? and more informatively, where was it coppied from?
    getc(stdin);
    free(test_ptr1);
    free(test_ptr2);
    return 0; 
  } else {
    printf("realloc failed\n");
    free(test_ptr2);
    return -1;
  }
}

выход:

1945305043
1945305044
1945305045
1945305046
1945305047
1945305048
1945305049
1945305050
1945305051
1945305052
1945305053
1945305054
1945305055
1945305056
proving calloc: 0
realloc success: c

person jayjay    schedule 02.10.2013    source источник
comment
Если кто-то еще хочет узнать ответ на этот вопрос, вам может быть интересна эта ссылка: bytes.com/topic/c/answers/600170-implementing-realloc это было очень полезно, но прочитайте все, потому что в первых нескольких сообщениях есть неверная информация.   -  person jayjay    schedule 02.10.2013


Ответы (1)


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

Вы правы, взгляните на документацию:

Содержимое блока памяти сохраняется до меньшего из нового и старого размеров, даже если блок перемещается в новое место. Если новый размер больше, значение новой выделенной части неопределенно.

person Leo Chapiro    schedule 02.10.2013
comment
хорошо, спасибо, но как он узнает, какая часть нового раздела неопределенна? (чтобы он не скопировал эту часть из старого раздела и не попал в недопустимую память) это значение будет new_size-old_size, но он не знает значение old_size (или знает?) - person jayjay; 02.10.2013
comment
Оно не знает! Он берет указатель на начало блока памяти и просто вырезает заданный размер! - person Leo Chapiro; 02.10.2013
comment
То есть, если я правильно вас понимаю, неопределенная память в новом разделе будет иметь то же значение, что и недопустимая память, примыкающая к старому разделу? Это ли не дыра в безопасности? Спасибо еще раз - person jayjay; 02.10.2013
comment
Да, но основной целью realloc является изменение размера блока памяти. В документации сказано: функция может переместить блок памяти в новое место... - person Leo Chapiro; 02.10.2013
comment
Что произойдет, если я: выделю все, кроме небольшой части кучи (в конце), затем выделю эту небольшую часть, освободию очень большой раздел и перераспределю меньшее место, чтобы заполнить больший раздел; это не удастся, будет заполнено данными из другого процесса или ?? - person jayjay; 02.10.2013
comment
Я добавил код выше. Я думаю, это доказывает, что процесс сложнее, чем просто блочное копирование, или что во время копирования, когда процесс достигает конца доступной памяти, он снова начинает копирование с самого начала. - person jayjay; 02.10.2013
comment
Кажется, это работает неправильно: вывод Timeout codepad.org/prTlASzP (вероятно, цикл while) - person Leo Chapiro; 02.10.2013
comment
неудивительно, что время ожидания компиляции/выполнения онлайн истекло, это не совсем лучший/самый эффективный код в мире... добавлены последние биты вывода с моей машины выше. ты - person jayjay; 02.10.2013