Почему важно проверять, что вернула функция malloc
Содержание:
Remarks
The realloc function changes the size of an allocated memory block. The memblock argument points to the beginning of the memory block. If memblock is NULL, realloc behaves the same way as malloc and allocates a new block of size bytes. If memblock is not NULL, it should be a pointer returned by a previous call to calloc, malloc, or realloc.
The size argument gives the new size of the block, in bytes. The contents of the block are unchanged up to the shorter of the new and old sizes, although the new block can be in a different location. Because the new block can be in a new memory location, the pointer returned by realloc is not guaranteed to be the pointer passed through the memblock argument. realloc does not zero newly allocated memory in the case of buffer growth.
realloc sets errno to ENOMEM if the memory allocation fails or if the amount of memory requested exceeds _HEAP_MAXREQ. For information on this and other error codes, see errno, _doserrno, _sys_errlist, and _sys_nerr.
realloc calls malloc in order to use the C++ _set_new_mode function to set the new handler mode. The new handler mode indicates whether, on failure, malloc is to call the new handler routine as set by _set_new_handler. By default, malloc does not call the new handler routine on failure to allocate memory. You can override this default behavior so that, when realloc fails to allocate memory, malloc calls the new handler routine in the same way that the operator does when it fails for the same reason. To override the default, call
early in ones program, or link with NEWMODE.OBJ (see Link Options).
When the application is linked with a debug version of the C run-time libraries, realloc resolves to _realloc_dbg. For more information about how the heap is managed during the debugging process, see The CRT Debug Heap.
realloc is marked and , meaning that the function is guaranteed not to modify global variables, and that the pointer returned is not aliased. For more information, see noalias and restrict.
By default, this function’s global state is scoped to the application. To change this, see Global state in the CRT.
NOTES top
By default, Linux follows an optimistic memory allocation strategy.
This means that when malloc() returns non-NULL there is no guarantee
that the memory really is available. In case it turns out that the
system is out of memory, one or more processes will be killed by the
OOM killer. For more information, see the description of
/proc/sys/vm/overcommit_memory and /proc/sys/vm/oom_adj in proc(5),
and the Linux kernel source file Documentation/vm/overcommit-
accounting.rst.
Normally, malloc() allocates memory from the heap, and adjusts the
size of the heap as required, using sbrk(2). When allocating blocks
of memory larger than MMAP_THRESHOLD bytes, the glibc malloc()
implementation allocates the memory as a private anonymous mapping
using mmap(2). MMAP_THRESHOLD is 128 kB by default, but is
adjustable using mallopt(3). Prior to Linux 4.7 allocations
performed using mmap(2) were unaffected by the RLIMIT_DATA resource
limit; since Linux 4.7, this limit is also enforced for allocations
performed using mmap(2).
To avoid corruption in multithreaded applications, mutexes are used
internally to protect the memory-management data structures employed
by these functions. In a multithreaded application in which threads
simultaneously allocate and free memory, there could be contention
for these mutexes. To scalably handle memory allocation in
multithreaded applications, glibc creates additional memory
allocation arenas if mutex contention is detected. Each arena is a
large region of memory that is internally allocated by the system
(using brk(2) or mmap(2)), and managed with its own mutexes.
SUSv2 requires malloc(), calloc(), and realloc() to set errno to
ENOMEM upon failure. Glibc assumes that this is done (and the glibc
versions of these routines do this); if you use a private malloc
implementation that does not set errno, then certain library routines
may fail without having a reason in errno.
Crashes in malloc(), calloc(), realloc(), or free() are almost always
related to heap corruption, such as overflowing an allocated chunk or
freeing the same pointer twice.
The malloc() implementation is tunable via environment variables; see
mallopt(3) for details.
Fundamento
El lenguaje de programación C gestiona la memoria de forma estática, automática o dinámica. Las variables estáticas se asignan en la memoria principal, por lo general junto con el código ejecutable del programa, y persisten durante toda la vida del programa; las variables automáticas se asignan sobre la pila (stack), comienzan cuando se invocan las funciones y acaban cuando se llama a . Para las variables estáticas y automáticas se requiere que el tamaño de la asignación sea constante en tiempo de compilación (antes de , que permite «arrays» automáticos de longitud variable). Si el tamaño requerido no se conoce hasta el tiempo de ejecución (por ejemplo, si los datos de tamaño arbitrario se están leyendo del usuario o desde un archivo de disco), la utilización de objetos de datos de tamaño fijo es insuficiente.
La vida útil de la memoria asignada es también una preocupación. Ni la memoria estática ni automática es adecuada para todas las situaciones. Los datos automáticos asignados no persisten en varias llamadas de función, mientras que los datos estáticos persisten durante toda la vida del programa, sean o no necesarios. En muchas situaciones, el programador requiere una mayor flexibilidad en la gestión de la vida útil de la memoria asignada.
Estas limitaciones se evitan mediante el uso de la gestión de memoria en la que la memoria es más explícitamente (y más flexiblemente) manejada, típicamente mediante la asignación desde el montón (heap), un área de memoria estructurada para este fin. En C, la función , perteneciente a la cabecera , se utiliza para asignar un bloque de memoria en el montón. El programa accede a este bloque de memoria a través de un puntero que regresa. Cuando ya no se necesita la memoria, se pasa el puntero a la función , la cual libera la memoria de modo que se puede utilizar para otros fines.
Algunas plataformas ofrecen llamadas de biblioteca que permiten en tiempo de ejecución la asignación dinámica de la pila C en lugar de la pila (por ejemplo Unix alloca(), Microsoft Windows de CRTL malloca() ). Esta memoria se libera automáticamente cuando la función de llamada termina. La necesidad de este se ve reducida por los cambios en el estándar C99, que añade soporte para arrays de longitud variable de ámbito de bloque que tienen tamaños que determine en tiempo de ejecución.
Notes
By default, Linux follows an optimistic memory allocation strategy. This means that when malloc() returns non-NULL there is no guarantee that the
memory really is available. In case it turns out that the system is out of memory, one or more processes will be killed by the OOM killer. For more
information, see the description of /proc/sys/vm/overcommit_memory and /proc/sys/vm/oom_adj in proc(5), and the Linux kernel source file
Documentation/vm/overcommit-accounting.
Normally, malloc() allocates memory from the heap, and adjusts the size of the heap as required, using sbrk(2). When allocating blocks of
memory larger than MMAP_THRESHOLD bytes, the glibc malloc() implementation allocates the memory as a private anonymous mapping using
mmap(2). MMAP_THRESHOLD is 128 kB by default, but is adjustable using mallopt(3). Allocations performed using (2) are
unaffected by the RLIMIT_DATA resource limit (see getrlimit(2)).
To avoid corruption in multithreaded applications, mutexes are used internally to protect the memory-management data structures employed by these functions.
In a multithreaded application in which threads simultaneously allocate and free memory, there could be contention for these mutexes. To scalably handle memory
allocation in multithreaded applications, glibc creates additional memory allocation arenas if mutex contention is detected. Each arena is a large
region of memory that is internally allocated by the system (using brk(2) or (2)), and managed with its own mutexes.
The UNIX 98 standard requires malloc(), calloc(), and realloc() to set errno to ENOMEM upon failure. Glibc assumes that
this is done (and the glibc versions of these routines do this); if you use a private malloc implementation that does not set errno, then certain
library routines may fail without having a reason in errno.
Crashes in malloc(), calloc(), realloc(), or free() are almost always related to heap corruption, such as overflowing an
allocated chunk or freeing the same pointer twice.
Recent versions of Linux libc (later than 5.4.23) and glibc (2.x) include a malloc() implementation which is tunable via environment variables. For
details, see (3).
DESCRIPTION top
The malloc() function allocates size bytes and returns a pointer to
the allocated memory. The memory is not initialized. If size is 0,
then malloc() returns either NULL, or a unique pointer value that can
later be successfully passed to free().
The free() function frees the memory space pointed to by ptr, which
must have been returned by a previous call to malloc(), calloc(), or
realloc(). Otherwise, or if free(ptr) has already been called
before, undefined behavior occurs. If ptr is NULL, no operation is
performed.
The calloc() function allocates memory for an array of nmemb elements
of size bytes each and returns a pointer to the allocated memory.
The memory is set to zero. If nmemb or size is 0, then calloc()
returns either NULL, or a unique pointer value that can later be
successfully passed to free(). If the multiplication of nmemb and
size would result in integer overflow, then calloc() returns an
error. By contrast, an integer overflow would not be detected in the
following call to malloc(), with the result that an incorrectly sized
block of memory would be allocated:
malloc(nmemb * size);
The realloc() function changes the size of the memory block pointed
to by ptr to size bytes. The contents will be unchanged in the range
from the start of the region up to the minimum of the old and new
sizes. If the new size is larger than the old size, the added memory
will not be initialized. If ptr is NULL, then the call is equivalent
to malloc(size), for all values of size; if size is equal to zero,
and ptr is not NULL, then the call is equivalent to free(ptr).
Unless ptr is NULL, it must have been returned by an earlier call to
malloc(), calloc(), or realloc(). If the area pointed to was moved,
a free(ptr) is done.
The reallocarray() function changes the size of the memory block
pointed to by ptr to be large enough for an array of nmemb elements,
each of which is size bytes. It is equivalent to the call
realloc(ptr, nmemb * size);
However, unlike that realloc() call, reallocarray() fails safely in
the case where the multiplication would overflow. If such an over‐
flow occurs, reallocarray() returns NULL, sets errno to ENOMEM, and
leaves the original block of memory unchanged.
APPLICATION USAGE top
The description of realloc() has been modified from previous versions
of this standard to align with the ISO/IEC 9899:1999 standard.
Previous versions explicitly permitted a call to realloc(p, 0) to
free the space pointed to by p and return a null pointer. While this
behavior could be interpreted as permitted by this version of the
standard, the C language committee have indicated that this
interpretation is incorrect. Applications should assume that if
realloc() returns a null pointer, the space pointed to by p has not
been freed. Since this could lead to double-frees, implementations
should also set errno if a null pointer actually indicates a failure,
and applications should only free the space if errno was changed.
NOTES top
By default, Linux follows an optimistic memory allocation strategy.
This means that when malloc() returns non-NULL there is no guarantee
that the memory really is available. In case it turns out that the
system is out of memory, one or more processes will be killed by the
OOM killer. For more information, see the description of
/proc/sys/vm/overcommit_memory and /proc/sys/vm/oom_adj in proc(5),
and the Linux kernel source file Documentation/vm/overcommit-
accounting.rst.
Normally, malloc() allocates memory from the heap, and adjusts the
size of the heap as required, using sbrk(2). When allocating blocks
of memory larger than MMAP_THRESHOLD bytes, the glibc malloc()
implementation allocates the memory as a private anonymous mapping
using mmap(2). MMAP_THRESHOLD is 128 kB by default, but is
adjustable using mallopt(3). Prior to Linux 4.7 allocations
performed using mmap(2) were unaffected by the RLIMIT_DATA resource
limit; since Linux 4.7, this limit is also enforced for allocations
performed using mmap(2).
To avoid corruption in multithreaded applications, mutexes are used
internally to protect the memory-management data structures employed
by these functions. In a multithreaded application in which threads
simultaneously allocate and free memory, there could be contention
for these mutexes. To scalably handle memory allocation in
multithreaded applications, glibc creates additional memory
allocation arenas if mutex contention is detected. Each arena is a
large region of memory that is internally allocated by the system
(using brk(2) or mmap(2)), and managed with its own mutexes.
SUSv2 requires malloc(), calloc(), and realloc() to set errno to
ENOMEM upon failure. Glibc assumes that this is done (and the glibc
versions of these routines do this); if you use a private malloc
implementation that does not set errno, then certain library routines
may fail without having a reason in errno.
Crashes in malloc(), calloc(), realloc(), or free() are almost always
related to heap corruption, such as overflowing an allocated chunk or
freeing the same pointer twice.
The malloc() implementation is tunable via environment variables; see
mallopt(3) for details.
RemarksRemarks
Функция realloc изменяет размер выделенного блока памяти.The realloc function changes the size of an allocated memory block. Аргумент мемблокк указывает на начало блока памяти.The memblock argument points to the beginning of the memory block. Если мемблокк имеет значение NULL, перераспределение ведет себя таким же образом, как и malloc , и выделяет новый блок размером байтов.If memblock is NULL, realloc behaves the same way as malloc and allocates a new block of size bytes. Если мемблокк не равно null, это должен быть указатель, возвращенный предыдущим вызовом метода calloc, mallocили realloc.If memblock is not NULL, it should be a pointer returned by a previous call to calloc, malloc, or realloc.
Аргумент size задает новый размер блока в байтах.The size argument gives the new size of the block, in bytes. Содержимое блока в пределах наименьшего из нового и старого размеров остается неизменным, хотя новый блок может находиться в другом расположении.The contents of the block are unchanged up to the shorter of the new and old sizes, although the new block can be in a different location. Так как новый блок может находиться в новом месте в памяти, указатель, возвращаемый методом realloc , не обязательно должен быть указателем, передаваемым через аргумент мемблокк .Because the new block can be in a new memory location, the pointer returned by realloc is not guaranteed to be the pointer passed through the memblock argument. перераспределение не приводит к обнулению памяти в случае роста буфера.realloc does not zero newly allocated memory in the case of buffer growth.
наборы перераспределения имеют значение еномем , если выделение памяти завершается неудачей или объем запрошенной памяти превышает _HEAP_MAXREQ.realloc sets errno to ENOMEM if the memory allocation fails or if the amount of memory requested exceeds _HEAP_MAXREQ. Дополнительные сведения об этих и других кодах ошибок см. в разделе errno, _doserrno, _sys_errlist и _sys_nerr.For information on this and other error codes, see errno, _doserrno, _sys_errlist, and _sys_nerr.
перераспределения вызывают malloc для использования функции _set_new_mode C++ для установки нового режима обработчика.realloc calls malloc in order to use the C++ _set_new_mode function to set the new handler mode. Новый режим обработчика указывает, что в случае сбоя malloc вызывает новую подпрограммы обработчика, заданную _set_new_handler.The new handler mode indicates whether, on failure, malloc is to call the new handler routine as set by _set_new_handler. По умолчанию malloc не вызывает новую подпрограммы обработчика при сбое выделения памяти.By default, malloc does not call the new handler routine on failure to allocate memory. Это поведение по умолчанию можно переопределить таким образом, чтобы при перераспределении не удалось выделить память, malloc вызывает новую подпрограммы обработчика таким же образом, как это делает оператор в случае сбоя по той же причине.You can override this default behavior so that, when realloc fails to allocate memory, malloc calls the new handler routine in the same way that the operator does when it fails for the same reason. Чтобы переопределить значение по умолчанию, вызовитеTo override the default, call
на ранних этапах программы или выполните компоновку с использованием NEWMODE.OBJ (см. раздел Параметры ссылок).early in ones program, or link with NEWMODE.OBJ (see Link Options).
Если приложение связано с отладочной версией библиотек времени выполнения C, перераспределения разрешается в _realloc_dbg.When the application is linked with a debug version of the C run-time libraries, realloc resolves to _realloc_dbg. Дополнительные сведения об управлении кучей в процессе отладки см. в разделе Куча отладки CRT.For more information about how the heap is managed during the debugging process, see The CRT Debug Heap.
Переопределение помечено как и , что означает, что функция гарантированно не изменяет глобальные переменные и что возвращаемый указатель не имеет псевдонима.realloc is marked and , meaning that the function is guaranteed not to modify global variables, and that the pointer returned is not aliased. Дополнительные сведения см. в разделах noalias и restrict.For more information, see noalias and restrict.
По умолчанию глобальное состояние этой функции ограничивается приложением.By default, this function’s global state is scoped to the application. Чтобы изменить это, см. раздел глобальное состояние в CRT.To change this, see Global state in the CRT.
Характерные ошибки при использовании
Память остаётся «занятой», даже если ни один указатель в программе на неё не ссылается (для освобождения памяти используется функция free). Накопление «потерянных» участков памяти приводит к постепенной деградации системы. Ошибки, связанные с неосвобождением занятых участков памяти, называются утечками памяти (англ. memory leaks).
- Если объём обрабатываемых данных больше, чем объём выделенной памяти, возможно повреждение других областей динамической памяти. Такие ошибки называются ошибками переполнения буфера (англ. buffer overflow).
- Если указатель на выделенную область памяти после освобождения продолжает использоваться, то при обращении к «уже не существующему» блоку динамической памяти может произойти исключение (англ. exception), сбой программы, повреждение других данных или не произойти ничего (в зависимости от типа операционной системы и используемого аппаратного обеспечения).
- Если для одной области памяти free вызывается более чем один раз, то это может повредить данные самой библиотеки, содержащей malloc/free, и привести к непредсказуемому поведению в произвольные моменты времени.
Перераспределение памяти
Если размер выделяемой памяти нельзя задать заранее, например при вводе последовательности значений до определенной команды, то для увеличения размера массива при вводе следующего значения необходимо выполнить следующие действия:
- Выделить блок памяти размерности n+1 (на 1 больше текущего размера массива)
- Скопировать все значения, хранящиеся в массиве во вновь выделенную область памяти
- Освободить память, выделенную ранее для хранения массива
- Переместить указатель начала массива на начало вновь выделенной области памяти
- Дополнить массив последним введенным значением
Все перечисленные выше действия (кроме последнего) выполняет функция
void* realloc (void* ptr, size_t size);
- ptr — указатель на блок ранее выделенной памяти функциями malloc(), calloc() или realloc() для перемещения в новое место. Если этот параметр равен NULL, то выделяется новый блок, и функция возвращает на него указатель.
- size — новый размер, в байтах, выделяемого блока памяти. Если size = 0, ранее выделенная память освобождается и функция возвращает нулевой указатель, ptr устанавливается в NULL.
Размер блока памяти, на который ссылается параметр ptr изменяется на size байтов. Блок памяти может уменьшаться или увеличиваться в размере. Содержимое блока памяти сохраняется даже если новый блок имеет меньший размер, чем старый. Но отбрасываются те данные, которые выходят за рамки нового блока. Если новый блок памяти больше старого, то содержимое вновь выделенной памяти будет неопределенным. Пример на Си Выделить память для ввода массива целых чисел. После ввода каждого значения задавать вопрос о вводе следующего значения.
123456789101112131415161718192021222324252627
#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>#include <malloc.h>int main(){ int *a = NULL, i = 0, elem; char c; do { printf(«a= «, i); scanf(«%d», &elem); a = (int*)realloc(a, (i + 1) * sizeof(int)); a = elem; i++; getchar(); printf(«Next (y/n)? «); c = getchar(); } while (c == ‘y’); for (int j = 0; j < i; j++) printf(«%d «, a); if (i>2) i -= 2; printf(«\n»); a = (int*)realloc(a, i * sizeof(int)); // уменьшение размера массива на 2 for (int j = 0; j < i; j++) printf(«%d «, a); getchar(); getchar(); return 0;}
Результат выполнения
Язык Си
RETURN VALUE top
Upon successful completion, realloc() shall return a pointer to the
(possibly moved) allocated space. If size is 0, either:
* A null pointer shall be returned and errno set to an
implementation-defined value.
* A unique pointer that can be successfully passed to free() shall
be returned, and the memory object pointed to by ptr shall be
freed. The application shall ensure that the pointer is not used
to access an object.
If there is not enough available memory, realloc() shall return a
null pointer and set errno to . If realloc() returns a null
pointer and errno has been set to , the memory referenced by
ptr shall not be changed.
COLOPHON top
This page is part of release 5.08 of the Linux man-pages project. A
description of the project, information about reporting bugs, and the
latest version of this page, can be found at
https://www.kernel.org/doc/man-pages/.
GNU 2020-06-09 MALLOC(3)
Pages that refer to this page:
memusage(1),
mremap(2),
__after_morecore_hook(3),
ber_memalloc(3),
ber_memcalloc(3),
ber_memfree(3),
ber_memrealloc(3),
ber_memvfree(3),
exec(3),
execl(3),
execle(3),
execlp(3),
execv(3),
execvp(3),
execvpe(3),
__free_hook(3),
freeifaddrs(3),
getdelim(3),
getifaddrs(3),
getline(3),
lber-memory(3),
ldap_memalloc(3),
ldap_memcalloc(3),
ldap_memfree(3),
ldap_memory(3),
ldap_memrealloc(3),
ldap_memvfree(3),
ldap_strdup(3),
malloc_hook(3),
__malloc_hook(3),
__malloc_initialize_hook(3),
__memalign_hook(3),
mtrace(3),
muntrace(3),
pmdafetch(3),
pmdaFetch(3),
pmdaSetFetchCallBack(3),
pmfault(3),
PM_FAULT_CHECK(3),
PM_FAULT_CLEAR(3),
__pmFaultInject(3),
PM_FAULT_POINT(3),
PM_FAULT_RETURN(3),
__pmFaultSummary(3),
__realloc_hook(3),
strdup(3),
strdupa(3),
strndup(3),
strndupa(3),
signal-safety(7)
Возвращаемое значениеReturn Value
Функция malloc возвращает указатель void на выделенное пространство или значение NULL , если объем доступной памяти недостаточен.malloc returns a void pointer to the allocated space, or NULL if there is insufficient memory available. Чтобы получить указатель на тип, отличный от , используйте приведение типа к возвращаемому значению.To return a pointer to a type other than , use a type cast on the return value. Дисковое пространство, на который указывает возвращаемое значение, будет гарантированно соответствовать требованиям к выравниванию для хранения объектов любого типа, если таковые требования не превышают базовые.The storage space pointed to by the return value is guaranteed to be suitably aligned for storage of any type of object that has an alignment requirement less than or equal to that of the fundamental alignment. (В Visual C++ основное выравнивание — это выравнивание, которое требуется для , или 8 байт.(In Visual C++, the fundamental alignment is the alignment that’s required for a , or 8 bytes. В коде, ориентированном на 64-разрядные платформы, это 16 байт.) Используйте _aligned_malloc , чтобы выделить хранилище для объектов с более высоким требованием выравнивания, например типы SSE __m128 и , и типы, объявленные с помощью, где n больше 8.In code that targets 64-bit platforms, it’s 16 bytes.) Use _aligned_malloc to allocate storage for objects that have a larger alignment requirement—for example, the SSE types __m128 and , and types that are declared by using where n is greater than 8. Если Размер равен 0, функция malloc выделяет элемент нулевой длины в куче и возвращает допустимый указатель на этот элемент.If size is 0, malloc allocates a zero-length item in the heap and returns a valid pointer to that item. Всегда проверяйте возврат от malloc, даже если требуемый объем памяти мал.Always check the return from malloc, even if the amount of memory requested is small.
Errores comunes
El uso inadecuado de asignación de memoria dinámica con frecuencia puede ser una fuente de errores.
La mayoría de los errores comunes son los siguientes:
- No comprobar errores de asignación. La asignación de memoria no está garantizada que tenga éxito. Si no se comprueba la asignación de memoria, puede producirse un error del programa o de la totalidad del sistema.
- Las pérdidas de memoria. Si no se desasigna memoria usando conduce a la acumulación de la memoria de un solo uso, que ya no es utilizado por el programa. Estos recursos de memoria desperdiciados pueden conducir a errores de asignación cuando se hayan agotado esos recursos.
- Los errores lógicos. Todas las asignaciones deben seguir el mismo patrón: la asignación mediante malloc , el uso para almacenar datos, desasignación mediante free . Las fallas que se adhieran a este patrón, como el uso de la memoria después de una llamada a la o antes de una llamada a , llamada a dos veces seguidas («doble liberación»), etc, por lo general conducen a una caída del programa.