В memcpy как справиться с переполнением памяти?

int main ()
{
    char *destination;
    char source[10] = "jigarpatel";
    destination = (char*) malloc(5);
    memcpy(destination, source, 10);
    printf("%s and size is %d", destination, strlen(destination));
    free(destination);
    return 0;
}

Выход:

 jigarpatel and size is 10

Вопрос:

Здесь я выделил всего 5 байт для назначения, но длина назначения составляет 10, почему это так?

Где хранятся остальные байты?

Безопасно ли это во встроенной системе? Есть ли вероятность сбоя или ошибки сегментации?

Как я могу обнаружить этот тип ошибки?

Еще один вопрос:

видите, я пишу одну библиотеку, где пользователь запрашивает необходимую память, а библиотека говорит выделить 10 байтов, а затем пользователь malloc 10 байтов и передать указатель на библиотеку. теперь библиотека хранит там некоторые данные ... теперь посмотрите, сказала ли библиотека выделить 10 байтов, но пользователь выделил только 5 байтов и дал этот указатель на библиотеку, тогда как я могу определить, что у пользователя недостаточно памяти malloc.


person Jeegar Patel    schedule 16.08.2011    source источник
comment
Примечание: в C вы не должны приводить результат malloc() - вы должны сделать это в C++, но это избыточно и потенциально опасно в C.   -  person Paul R    schedule 16.08.2011
comment
Еще одно замечание: помимо случайности записи за конец буфера, у вас есть еще одна случайность, что printf и strlen нашли 0 байт после l, но вы не имели права ожидать и этого.   -  person Steve Jessop    schedule 16.08.2011


Ответы (4)


Иногда это работает, но это определенно небезопасно ни в одной системе. Вы пишете за пределами того, что вам дает malloc. С точки зрения C это незаконно, но с точки зрения ОС это может быть нормально (эта память может быть выгружена с соответствующими разрешениями).

Другая проблема заключается в том, что если вы позже снова вызовете malloc, это может дать вам немного памяти, включая те 5 байтов, которые вы используете без запроса. Это должно обеспечить несколько интересных сеансов отладки.

здесь я только что выделил только 5 байтов для места назначения, тогда почему длина места назначения равна 10?

Для адресата выделено только 5 байта, но из-за того, как malloc работает в вашей системе, это не приводит к недопустимой записи, поскольку он находится внутри допустимой страницы.

где хранятся остальные байты.?

Сразу после первых 5, пока.

Безопасно ли это во встроенной системе? какие-либо шансы на сбой или ошибку сегментации.?

Это небезопасно в любой системе. Много шансов на сбои.

как я могу обнаружить этот тип ошибок.?

Использование valgrind или любого отладчика памяти. Краткое введение в valgrind можно найти здесь.

¹ Например, в Linux (Glibc) небольшие (~ 64 байта) malloc запросы обслуживаются из небольшого списка предварительно выделенных страниц, называемых "fastbins". Каждый фастбин имеет фиксированный размер, поэтому использование выделенного фастбина до этого размера не приведет к нарушению сегментации. Более подробную информацию о том, как это происходит, можно найти здесь для более тщательное рассмотрение темы вы можете найти на исходный код malloc.

person cnicutar    schedule 16.08.2011
comment
видите, я пишу одну библиотеку, где пользователь запрашивает необходимую память, а библиотека говорит выделить 10 байтов, а затем пользователь malloc 10 байтов и передать указатель на библиотеку. теперь библиотека хранит там некоторые данные ... теперь посмотрите, сказала ли библиотека выделить 10 байтов, но пользователь выделил только 5 байтов и дал этот указатель на библиотеку, тогда как я могу определить, что у пользователя недостаточно памяти malloc? - person Jeegar Patel; 16.08.2011
comment
@ Mr.32 Вы не можете. Это C, так что стрелять себе в ногу — основное право пользователей. В качестве альтернативы вы можете отобрать у них оружие и выделить память самостоятельно. - person cnicutar; 16.08.2011
comment
Просто повторю и подчеркну, даже если он не вылетает 999 999 раз на миллион, это по определению чистая удача, и изменения в компиляторе, ОС или библиотеках могут изменить положение ваших звезд в любой день. - person tripleee; 16.08.2011

Здесь я только что выделил только 5 байт для места назначения, тогда почему длина места назначения равна 10?

printf("%s and size is %d",destination,strlen(destination)); 

strlen() считает \0 концом строки, поэтому он продолжает считать, пока не встретит \0. Это не означает, что destination выделено столько памяти.

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

где хранятся остальные байты?
Остальные байты перезаписывают некоторые другие области памяти, кроме 5 байтов, выделенных для destination.

Безопасно ли это во встроенной системе? есть ли вероятность сбоя или ошибки сегментации?
Это НЕ безопасно. Это вызывает неопределенное поведение и, если вам повезет, это сработает.

как обнаружить ошибки такого типа?
На каждой платформе есть определенные инструменты профилирования памяти, такие как Valgrind для Linux/Unix, вы можете использовать их, и они укажут на такие переопределения памяти.

person Alok Save    schedule 16.08.2011

Нет, это небезопасно — запись за пределы выделенного блока обычно приводит к повреждению кучи.

Используйте такие инструменты, как valgrind, чтобы обнаружить эту и другие ошибки.

person Paul R    schedule 16.08.2011

Вам повезло, что он не разбился. Третий параметр memcpy должен быть равен 4, а затем вы должны поместить нулевой символ в позицию 5, чтобы завершить строку.

person Ed Heal    schedule 16.08.2011