To understand the usage of free in the C programming language I tried running this code on Ubuntu, but on running the EXE file I am receiving a SIGABRT error. Why is the program not exiting normally?
为了理解免费在C编程语言中的用法,我尝试在Ubuntu上运行这段代码,但是在运行EXE文件时,我收到了一个SIGABRT错误。为什么程序不能正常退出?
#include<stdio.h>
#include<stdlib.h>
int main()
{
int ret;
int *ptr;
ptr = (int *)malloc(sizeof(int)*10);
free(ptr);
ptr = &ret;
free(ptr);
return 0;
}
7 个解决方案
#1
38
Attempting to free a pointer you didn't get from malloc
(or one of its friends) causes undefined behaviour. Your second free(ptr)
call attempts just that.
试图从malloc(或它的一个朋友)中释放一个没有得到的指针会导致未定义的行为。您的第二个空闲(ptr)调用尝试这样做。
From the C spec, §7.22.3.3 The free
function, paragraph 2:
从C规范,§7.22.3.3*函数,第二款:
The
free
function causes the space pointed to byptr
to be deallocated, that is, made available for further allocation. Ifptr
is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call tofree
orrealloc
, the behavior is undefined.*函数使ptr所指向的空间被释放,即为进一步分配提供的空间。如果ptr是一个空指针,则不会发生任何操作。否则,如果参数与内存管理函数之前返回的指针不匹配,或者通过调用free或realloc来释放空间,则该行为未定义。
#2
11
While all the the undefined behavior answers are correct, seeing an implementation might be more helpful.
虽然所有未定义的行为答案都是正确的,但是查看实现可能更有帮助。
I think a very good reference to this is K&R C malloc. An explanation of how it works is in "The C Programming Langugage", Chapter 8.7.
我认为一个很好的例子是K&R C malloc。它是如何工作的解释在“C编程语言”,第8.7章。
Remember when looking at code from standard library functions in C that they have an implementation and a specification, where the implementation might have reproducible behavior that is not required by its specification.
请记住,当查看来自C中的标准库函数的代码时,它们有一个实现和一个规范,其中的实现可能具有其规范所不需要的可重复行为。
Essentially almost all malloc
implementations have a free list where they manage free memory regions in a list (or multiple lists). The free list is often handled in a way, that calling free
on a memory region multiple times will put this list in an incorrect state.
基本上,几乎所有的malloc实现都有一个空闲列表,它们在其中管理列表(或多个列表)中的空闲内存区域。空闲列表通常以某种方式处理,在内存区域多次调用free将使该列表处于不正确的状态。
Also malicious behavior can be invoked when data structures are purposefully crafted. Phrack has a dated article on how to invoke code execution when passing invalid memory to free
while corrupting the freelist.
此外,当有目的地构建数据结构时,还可以调用恶意行为。Phrack有一篇过时的文章,关于如何在传递无效内存到free时调用代码执行,同时破坏freelist。
Other malloc implementations might also be worth looking at (this is an incomplete list of allocation libraries).
其他malloc实现可能也值得关注(这是一个不完整的分配库列表)。
#3
11
ptr = &ret;
free(ptr);
is the same as:
是一样的:
free(&ret);
ret
resides on the stack, not on the heap. Attempting to free()
memory that was not allocated (with malloc()
, etc.) on the heap will cause undefined behavior.
ret驻留在堆栈上,而不是堆上。尝试释放堆上未分配(使用malloc()等)的()内存将导致未定义的行为。
#4
9
The function free()
only works for the memory that has been allocated on heap
by malloc()
. Not for the static allocation, because static allocations are automatically handled. Here is the mistake:
函数free()只适用于malloc()在堆上分配的内存。不是静态分配,因为静态分配是自动处理的。这是错误:
int ret;
ptr = &ret;
free(ptr);
You can't do this because the memory for ret
is not allocated on the heap. It's in the stack and only the memory of the heap should be freed.
不能这样做,因为ret的内存没有分配到堆上。它在堆栈中,只有堆的内存应该被释放。
#5
8
Your second free(ptr)
is causing undefined behavior as you are attempting to free a pointer which you didn't allocate. Also note that static allocations are automatically reclaimed, so you don't require them to free it.
当您试图释放一个没有分配的指针时,第二个空闲(ptr)会导致未定义的行为。还要注意,静态分配是自动回收的,所以不需要它们释放它。
#6
5
ptr = &ret;
free(ptr);
Here you are trying to free the local storage stack variable's memory. As per rule you should not free it. When the main() exits all local storage memory on stack always get free.
这里尝试释放本地存储堆栈变量的内存。按照规定,你不应该释放它。当main()退出堆栈时,堆栈上的所有本地存储内存总是空闲的。
Free only works with Heap allocation memory.
Free仅适用于堆分配内存。
#7
2
There are three areas where variables may be created in a c or c++ program.
有三个领域可以在c或c++程序中创建变量。
- global or static variables are at fixed locations in the executable binary file.
- 全局变量或静态变量位于可执行二进制文件中的固定位置。
- automatic variables outside of static scope are on the stack
- 堆栈上有静态范围之外的自动变量
- malloc'ed or calloc'ed variables are on the heap.
- 堆上有malloc或calloc变量。
free() is the function that releases previously allocated memory on the heap. A pointer to memory on the heap is returned by malloc or similar functions. The only way to read or write that memory is via the pointer. A pointer is an address, and a pointer* is the content pointed to at that address.
free()是释放先前在堆上分配的内存的函数。指向堆上内存的指针由malloc或类似函数返回。读取或写入内存的唯一方法是通过指针。指针是一个地址,指针*是指向该地址的内容。
In the example shown, there are two variables, defined in Main, and effectively static, and the returned value from Main, which is on the stack. Using the miniumum int, 16 bits, here's a possible memory map. In this map, the instructions start at 0, the stack starts at some non-zero value, (beginning of stack - bos) and grows by incrementing, and a heap starts at the maximum address (...FFFF, aka -1) and grows by decrememeting:
在所示的示例中,有两个变量(以Main方式定义,实际上是静态的)和来自Main的返回值(位于堆栈上)。使用最小整数,16位,这是一个可能的内存映射。在这个映射中,指令从0开始,堆栈从某个非零值开始(堆栈- bos),然后递增,堆从最大地址开始(……)FFFF,又名-1),通过脱皮生长:
(Remember, MIN_INT is -32768, MAX_INT is 32767... the spec guarantees only 16 bits, signed)
(记住,MIN_INT是-32768,MAX_INT是32767…)规范只保证16位,签名)
Each byte has an address which is 'n' bits wide - 16, 32 or 64 bits, typically
每个字节有一个“n”位宽的地址——通常是16位、32位或64位
-1. (start of heap, for example, 16 bit addr: 0xFFFF, 32 bit addr: 0xFFFFFFFF or 64 bit addr: 0xFFFFFFFFFFFFFFFF)
1。(比如堆的开始,16位addr: 0xFFFF, 32位addr: 0xffffffffffff或64位addr: 0xffffffffffffffffffffffff)
-2. (1st location down from beginning of heap. 0x...FFFE) ptr[ 9 ], at one time
2。(从堆开始向下的第一个位置。ptr[9],一次。
-3. (2nd location down from beginning of heap. 0x...FFFD)
3所示。(从堆开始向下的第二个位置。0 x…FFFD)
-4. (3rd location down from beginning of heap. 0x...FFFC) ptr[ 8 ], at one time
4所示。(堆的第三个位置。FFFC) ptr[8],一次
[snip]
(剪)
-17. (16th location down from beginning of heap. 0x...FFEF)
-17年。(从堆开始往下第16个位置。0 x…FFEF)
-18. (17th location down from beginning of heap. 0x...FFEE) ptr[ 1 ], at one time
-18年。(从堆开始往下的第17个位置。(FFEE) ptr[1],一次
-19. (18th location down from beginning of heap. 0x...FFED)
-19年。(从堆开始的第18个位置。0 x…ff)
-20 (19th location down from beginning of heap. 0x...FFEC) ptr[ 0 ], at one time
-20(从堆开始往下的第19个位置。FFEC) ptr[0],一次
-21. (top of heap, 10 X 16 bit ints down from beginning of heap. 0x...FFEB), at one time
-21年。(堆的顶部,10 X 16位从堆开始往下输入。0 x…FFEB),
: A very large range of address on 32 or 64 bit machines... :
: 32位或64位机器上的一个非常大的地址范围……:
tos: ( Top of stack 0x...tos )
栈顶0x…服务条款)
bos + ( sizeof( int ) - 1) End of int returned from Main()
bos + (sizeof(int) - 1)从Main()返回
bos: (beginning of stack: above static data ) Start of int returned from Mail()
bos:(堆栈开始:上面的静态数据)从Mail()返回的int的开始
togs: (top of global/static) End of "ptr"
togs:(全局/静态顶部)“ptr”结束
: (size of a pointer is width of address bus... whatever it takes)
:(指针的大小是地址总线的宽度……)无论代价)
togs-(n-1): (top of global/static - (sizeof( int* ) - 1)) start of "ptr"
togs-(n-1):(全局/静态-(sizeof(int*) -1)“ptr”开始
(togs-n) : End of "ret"
(togs-n):“ret”的结尾
(togs-n)-1: start of "ret"
(togs-n)1:“后悔”的开始
(any global stuff the compiler adds for itself, the debugger, etc.)
(编译器为自己添加的任何全局内容、调试器等等)
(end of program code)
(程序代码的结束)
(start of program code)
(程序代码的开始)
(top of non-program code)
(顶部non-program代码)
0 (start of non-program code, 0x...0000 )
0(启动非程序代码,0x…)0000)
At run-time, "ptr" and "ret" are probably both start at '0', since they're fixed, static, values, read out of the file the executable binary comes from.
在运行时,“ptr”和“ret”可能都是从‘0’开始的,因为它们是固定的、静态的、值,从可执行二进制文件中读取。
As the program runs, the value of "ptr" changes, first, to point into the heap, at the malloc'ed array of 10 ints: "0x...FFEC"
随着程序的运行,“ptr”的值会发生变化,首先是指向堆,指向10 ints的malloc'ed数组:“0x…FFEC”
The call to free() doesn't change the value of ptr, its still "0x...FFEC" Free'ing "0x...FFEC" is legit and runs without anything funny.
对free()的调用不会改变ptr的值,它仍然是“0x…”FFEC 0 x“免费的”……FFEC"是合法的,运行时没有任何有趣的东西。
The assignment "ptr = &ret" sets a new value into "ptr", "(togs-n)-1", the start of "ret".
赋值"ptr = &ret"将新值设为"ptr" (togs-n)-1",为"ret"的开始。
Free'ing "(togs-n)-1" causes an immediate crash because "free" checks the value of "(togs-n)-1" and it is NOT in the valid range for a heap address.
“Free”(togs-n)-1“会立即导致崩溃,因为“Free”检查“(togs-n)-1”的值,而它不在堆地址的有效范围内。
"ret" remains blank, its never set, but since its global/static, it remains at whatever it was when the linker wrote it to disk.
“ret”仍然是空的,它从来没有设置过,但是由于它的全局/静态,它仍然保持在链接器将它写到磁盘时的状态。
#1
38
Attempting to free a pointer you didn't get from malloc
(or one of its friends) causes undefined behaviour. Your second free(ptr)
call attempts just that.
试图从malloc(或它的一个朋友)中释放一个没有得到的指针会导致未定义的行为。您的第二个空闲(ptr)调用尝试这样做。
From the C spec, §7.22.3.3 The free
function, paragraph 2:
从C规范,§7.22.3.3*函数,第二款:
The
free
function causes the space pointed to byptr
to be deallocated, that is, made available for further allocation. Ifptr
is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call tofree
orrealloc
, the behavior is undefined.*函数使ptr所指向的空间被释放,即为进一步分配提供的空间。如果ptr是一个空指针,则不会发生任何操作。否则,如果参数与内存管理函数之前返回的指针不匹配,或者通过调用free或realloc来释放空间,则该行为未定义。
#2
11
While all the the undefined behavior answers are correct, seeing an implementation might be more helpful.
虽然所有未定义的行为答案都是正确的,但是查看实现可能更有帮助。
I think a very good reference to this is K&R C malloc. An explanation of how it works is in "The C Programming Langugage", Chapter 8.7.
我认为一个很好的例子是K&R C malloc。它是如何工作的解释在“C编程语言”,第8.7章。
Remember when looking at code from standard library functions in C that they have an implementation and a specification, where the implementation might have reproducible behavior that is not required by its specification.
请记住,当查看来自C中的标准库函数的代码时,它们有一个实现和一个规范,其中的实现可能具有其规范所不需要的可重复行为。
Essentially almost all malloc
implementations have a free list where they manage free memory regions in a list (or multiple lists). The free list is often handled in a way, that calling free
on a memory region multiple times will put this list in an incorrect state.
基本上,几乎所有的malloc实现都有一个空闲列表,它们在其中管理列表(或多个列表)中的空闲内存区域。空闲列表通常以某种方式处理,在内存区域多次调用free将使该列表处于不正确的状态。
Also malicious behavior can be invoked when data structures are purposefully crafted. Phrack has a dated article on how to invoke code execution when passing invalid memory to free
while corrupting the freelist.
此外,当有目的地构建数据结构时,还可以调用恶意行为。Phrack有一篇过时的文章,关于如何在传递无效内存到free时调用代码执行,同时破坏freelist。
Other malloc implementations might also be worth looking at (this is an incomplete list of allocation libraries).
其他malloc实现可能也值得关注(这是一个不完整的分配库列表)。
#3
11
ptr = &ret;
free(ptr);
is the same as:
是一样的:
free(&ret);
ret
resides on the stack, not on the heap. Attempting to free()
memory that was not allocated (with malloc()
, etc.) on the heap will cause undefined behavior.
ret驻留在堆栈上,而不是堆上。尝试释放堆上未分配(使用malloc()等)的()内存将导致未定义的行为。
#4
9
The function free()
only works for the memory that has been allocated on heap
by malloc()
. Not for the static allocation, because static allocations are automatically handled. Here is the mistake:
函数free()只适用于malloc()在堆上分配的内存。不是静态分配,因为静态分配是自动处理的。这是错误:
int ret;
ptr = &ret;
free(ptr);
You can't do this because the memory for ret
is not allocated on the heap. It's in the stack and only the memory of the heap should be freed.
不能这样做,因为ret的内存没有分配到堆上。它在堆栈中,只有堆的内存应该被释放。
#5
8
Your second free(ptr)
is causing undefined behavior as you are attempting to free a pointer which you didn't allocate. Also note that static allocations are automatically reclaimed, so you don't require them to free it.
当您试图释放一个没有分配的指针时,第二个空闲(ptr)会导致未定义的行为。还要注意,静态分配是自动回收的,所以不需要它们释放它。
#6
5
ptr = &ret;
free(ptr);
Here you are trying to free the local storage stack variable's memory. As per rule you should not free it. When the main() exits all local storage memory on stack always get free.
这里尝试释放本地存储堆栈变量的内存。按照规定,你不应该释放它。当main()退出堆栈时,堆栈上的所有本地存储内存总是空闲的。
Free only works with Heap allocation memory.
Free仅适用于堆分配内存。
#7
2
There are three areas where variables may be created in a c or c++ program.
有三个领域可以在c或c++程序中创建变量。
- global or static variables are at fixed locations in the executable binary file.
- 全局变量或静态变量位于可执行二进制文件中的固定位置。
- automatic variables outside of static scope are on the stack
- 堆栈上有静态范围之外的自动变量
- malloc'ed or calloc'ed variables are on the heap.
- 堆上有malloc或calloc变量。
free() is the function that releases previously allocated memory on the heap. A pointer to memory on the heap is returned by malloc or similar functions. The only way to read or write that memory is via the pointer. A pointer is an address, and a pointer* is the content pointed to at that address.
free()是释放先前在堆上分配的内存的函数。指向堆上内存的指针由malloc或类似函数返回。读取或写入内存的唯一方法是通过指针。指针是一个地址,指针*是指向该地址的内容。
In the example shown, there are two variables, defined in Main, and effectively static, and the returned value from Main, which is on the stack. Using the miniumum int, 16 bits, here's a possible memory map. In this map, the instructions start at 0, the stack starts at some non-zero value, (beginning of stack - bos) and grows by incrementing, and a heap starts at the maximum address (...FFFF, aka -1) and grows by decrememeting:
在所示的示例中,有两个变量(以Main方式定义,实际上是静态的)和来自Main的返回值(位于堆栈上)。使用最小整数,16位,这是一个可能的内存映射。在这个映射中,指令从0开始,堆栈从某个非零值开始(堆栈- bos),然后递增,堆从最大地址开始(……)FFFF,又名-1),通过脱皮生长:
(Remember, MIN_INT is -32768, MAX_INT is 32767... the spec guarantees only 16 bits, signed)
(记住,MIN_INT是-32768,MAX_INT是32767…)规范只保证16位,签名)
Each byte has an address which is 'n' bits wide - 16, 32 or 64 bits, typically
每个字节有一个“n”位宽的地址——通常是16位、32位或64位
-1. (start of heap, for example, 16 bit addr: 0xFFFF, 32 bit addr: 0xFFFFFFFF or 64 bit addr: 0xFFFFFFFFFFFFFFFF)
1。(比如堆的开始,16位addr: 0xFFFF, 32位addr: 0xffffffffffff或64位addr: 0xffffffffffffffffffffffff)
-2. (1st location down from beginning of heap. 0x...FFFE) ptr[ 9 ], at one time
2。(从堆开始向下的第一个位置。ptr[9],一次。
-3. (2nd location down from beginning of heap. 0x...FFFD)
3所示。(从堆开始向下的第二个位置。0 x…FFFD)
-4. (3rd location down from beginning of heap. 0x...FFFC) ptr[ 8 ], at one time
4所示。(堆的第三个位置。FFFC) ptr[8],一次
[snip]
(剪)
-17. (16th location down from beginning of heap. 0x...FFEF)
-17年。(从堆开始往下第16个位置。0 x…FFEF)
-18. (17th location down from beginning of heap. 0x...FFEE) ptr[ 1 ], at one time
-18年。(从堆开始往下的第17个位置。(FFEE) ptr[1],一次
-19. (18th location down from beginning of heap. 0x...FFED)
-19年。(从堆开始的第18个位置。0 x…ff)
-20 (19th location down from beginning of heap. 0x...FFEC) ptr[ 0 ], at one time
-20(从堆开始往下的第19个位置。FFEC) ptr[0],一次
-21. (top of heap, 10 X 16 bit ints down from beginning of heap. 0x...FFEB), at one time
-21年。(堆的顶部,10 X 16位从堆开始往下输入。0 x…FFEB),
: A very large range of address on 32 or 64 bit machines... :
: 32位或64位机器上的一个非常大的地址范围……:
tos: ( Top of stack 0x...tos )
栈顶0x…服务条款)
bos + ( sizeof( int ) - 1) End of int returned from Main()
bos + (sizeof(int) - 1)从Main()返回
bos: (beginning of stack: above static data ) Start of int returned from Mail()
bos:(堆栈开始:上面的静态数据)从Mail()返回的int的开始
togs: (top of global/static) End of "ptr"
togs:(全局/静态顶部)“ptr”结束
: (size of a pointer is width of address bus... whatever it takes)
:(指针的大小是地址总线的宽度……)无论代价)
togs-(n-1): (top of global/static - (sizeof( int* ) - 1)) start of "ptr"
togs-(n-1):(全局/静态-(sizeof(int*) -1)“ptr”开始
(togs-n) : End of "ret"
(togs-n):“ret”的结尾
(togs-n)-1: start of "ret"
(togs-n)1:“后悔”的开始
(any global stuff the compiler adds for itself, the debugger, etc.)
(编译器为自己添加的任何全局内容、调试器等等)
(end of program code)
(程序代码的结束)
(start of program code)
(程序代码的开始)
(top of non-program code)
(顶部non-program代码)
0 (start of non-program code, 0x...0000 )
0(启动非程序代码,0x…)0000)
At run-time, "ptr" and "ret" are probably both start at '0', since they're fixed, static, values, read out of the file the executable binary comes from.
在运行时,“ptr”和“ret”可能都是从‘0’开始的,因为它们是固定的、静态的、值,从可执行二进制文件中读取。
As the program runs, the value of "ptr" changes, first, to point into the heap, at the malloc'ed array of 10 ints: "0x...FFEC"
随着程序的运行,“ptr”的值会发生变化,首先是指向堆,指向10 ints的malloc'ed数组:“0x…FFEC”
The call to free() doesn't change the value of ptr, its still "0x...FFEC" Free'ing "0x...FFEC" is legit and runs without anything funny.
对free()的调用不会改变ptr的值,它仍然是“0x…”FFEC 0 x“免费的”……FFEC"是合法的,运行时没有任何有趣的东西。
The assignment "ptr = &ret" sets a new value into "ptr", "(togs-n)-1", the start of "ret".
赋值"ptr = &ret"将新值设为"ptr" (togs-n)-1",为"ret"的开始。
Free'ing "(togs-n)-1" causes an immediate crash because "free" checks the value of "(togs-n)-1" and it is NOT in the valid range for a heap address.
“Free”(togs-n)-1“会立即导致崩溃,因为“Free”检查“(togs-n)-1”的值,而它不在堆地址的有效范围内。
"ret" remains blank, its never set, but since its global/static, it remains at whatever it was when the linker wrote it to disk.
“ret”仍然是空的,它从来没有设置过,但是由于它的全局/静态,它仍然保持在链接器将它写到磁盘时的状态。