./thrash 中的错误:free():无效指针
Error in ./thrash: free(): invalid pointer
我知道这个问题已经被问过好几次了,但是 none 的解决方案为我提供了任何帮助。我正在编写一个实验室程序,它在 C 中分配了大量内存,特别是一个 char 指针数组,每个指针都在内存中分配了一个页面的大小,即 4096 字节。
char** pgs =(char**) malloc(sizeof(char *) * pages);
if(pgs == NULL){
printf("Failed to allocate memory");
exit(0);
}
int i;
for(i = 0; i < pages; i++){
pgs[i] = malloc(4096);
/*if(pgs[i] == NULL){
printf("Failed to allocate memory");
exit(0);
}*/
*pgs[i] = "[=10=]";
/*if(pgs[i] == NULL){
printf("Failed to allocate memory");
exit(0);
}*/
}
在程序中间,随机访问和修改此数组的元素以引起抖动(作为实验的一部分):
while(time(NULL) - startTime < seconds){
long rando = rand() % pages;
if(modify > 0){
*pgs[rando]++;
}
else{
long temp = *pgs[rando];
}
在程序结束时,我尝试释放此内存:
for(i = 0; i < pages; i++){
free(pgs[i]);
}
free(pgs);
然而,我遇到了可怕的 "invalid pointer" 错误。如果有人对如何修复此问题有任何建议或知识,请分享。
您显示的程序片段存在许多问题,其中一些已在评论中指出:
- 程序应该在标准错误上报告错误,而不是标准输出。
- 程序在失败时应以 non-zero 状态退出。
- 程序应该在没有警告的情况下编译。
- 一般消息和特定错误消息应以换行符结尾。
- 程序只尝试修改每一页的一个字节。
但是,主要问题是问题中的代码使用了 *pgs[rando]++
,它旨在修改分配的内存。这等同于 *(pgs[rando]++)
递增指针然后读取值并丢弃它 — 而不是等同于 (*pgs[rando])++
将修改字节 pgs[rando][0]
。问题中的代码应该生成关于 value computed is not used
的警告(如果您确保编译时所有警告都被视为错误,则生成错误)。因为您的代码正在递增指针,所以返回给内存分配系统的值 free()
通常与内存分配系统返回给您的值不同,因此您确实传递了无效指针至 free()
.
这段代码避免了上述问题。它执行固定次数的迭代并且不使用 time()
。它打印 sum
以便优化器无法优化对内存的读取访问。
/* SO 4971-2352 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { PAGESIZE = 4096 };
int main(void)
{
int pages = PAGESIZE;
char **pgs = (char **)malloc(sizeof(char *) * pages);
if (pgs == NULL)
{
fprintf(stderr, "Failed to allocate memory\n");
exit(EXIT_FAILURE);
}
for (int i = 0; i < pages; i++)
{
pgs[i] = malloc(PAGESIZE);
if (pgs[i] == NULL)
{
fprintf(stderr, "Failed to allocate memory\n");
exit(EXIT_FAILURE);
}
memset(pgs[i], '[=10=]', PAGESIZE); // Or use calloc()!
}
size_t sum = 0;
for (int i = 0; i < PAGESIZE * PAGESIZE; i++)
{
int pagenum = rand() % pages;
int offset = rand() % PAGESIZE;
int modify = i & 2;
if (modify != 0)
{
pgs[pagenum][offset]++;
}
else
{
sum += pgs[pagenum][offset];
}
}
printf("Sum: 0x%.8zX\n", sum);
for (int i = 0; i < pages; i++)
free(pgs[i]);
free(pgs);
return 0;
}
我调用了该代码 thrash31.c
并将其编译成 thrash31
使用:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror thrash31.c -o thrash31
$
当运行用一个定时程序时,我得到了输出:
$ timecmd -u -- thrash31
2018-04-07 15:48:58.546809 [PID 9178] thrash31
Sum: 0x001FE976
2018-04-07 15:48:59.355508 [PID 9178; status 0x0000] - 0.808699s
$
因此, 运行 大约用了 0.8 秒。它生成的总和每次都相同,因为代码不会为随机数生成器提供种子。
我知道这个问题已经被问过好几次了,但是 none 的解决方案为我提供了任何帮助。我正在编写一个实验室程序,它在 C 中分配了大量内存,特别是一个 char 指针数组,每个指针都在内存中分配了一个页面的大小,即 4096 字节。
char** pgs =(char**) malloc(sizeof(char *) * pages);
if(pgs == NULL){
printf("Failed to allocate memory");
exit(0);
}
int i;
for(i = 0; i < pages; i++){
pgs[i] = malloc(4096);
/*if(pgs[i] == NULL){
printf("Failed to allocate memory");
exit(0);
}*/
*pgs[i] = "[=10=]";
/*if(pgs[i] == NULL){
printf("Failed to allocate memory");
exit(0);
}*/
}
在程序中间,随机访问和修改此数组的元素以引起抖动(作为实验的一部分):
while(time(NULL) - startTime < seconds){
long rando = rand() % pages;
if(modify > 0){
*pgs[rando]++;
}
else{
long temp = *pgs[rando];
}
在程序结束时,我尝试释放此内存:
for(i = 0; i < pages; i++){
free(pgs[i]);
}
free(pgs);
然而,我遇到了可怕的 "invalid pointer" 错误。如果有人对如何修复此问题有任何建议或知识,请分享。
您显示的程序片段存在许多问题,其中一些已在评论中指出:
- 程序应该在标准错误上报告错误,而不是标准输出。
- 程序在失败时应以 non-zero 状态退出。
- 程序应该在没有警告的情况下编译。
- 一般消息和特定错误消息应以换行符结尾。
- 程序只尝试修改每一页的一个字节。
但是,主要问题是问题中的代码使用了 *pgs[rando]++
,它旨在修改分配的内存。这等同于 *(pgs[rando]++)
递增指针然后读取值并丢弃它 — 而不是等同于 (*pgs[rando])++
将修改字节 pgs[rando][0]
。问题中的代码应该生成关于 value computed is not used
的警告(如果您确保编译时所有警告都被视为错误,则生成错误)。因为您的代码正在递增指针,所以返回给内存分配系统的值 free()
通常与内存分配系统返回给您的值不同,因此您确实传递了无效指针至 free()
.
这段代码避免了上述问题。它执行固定次数的迭代并且不使用 time()
。它打印 sum
以便优化器无法优化对内存的读取访问。
/* SO 4971-2352 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { PAGESIZE = 4096 };
int main(void)
{
int pages = PAGESIZE;
char **pgs = (char **)malloc(sizeof(char *) * pages);
if (pgs == NULL)
{
fprintf(stderr, "Failed to allocate memory\n");
exit(EXIT_FAILURE);
}
for (int i = 0; i < pages; i++)
{
pgs[i] = malloc(PAGESIZE);
if (pgs[i] == NULL)
{
fprintf(stderr, "Failed to allocate memory\n");
exit(EXIT_FAILURE);
}
memset(pgs[i], '[=10=]', PAGESIZE); // Or use calloc()!
}
size_t sum = 0;
for (int i = 0; i < PAGESIZE * PAGESIZE; i++)
{
int pagenum = rand() % pages;
int offset = rand() % PAGESIZE;
int modify = i & 2;
if (modify != 0)
{
pgs[pagenum][offset]++;
}
else
{
sum += pgs[pagenum][offset];
}
}
printf("Sum: 0x%.8zX\n", sum);
for (int i = 0; i < pages; i++)
free(pgs[i]);
free(pgs);
return 0;
}
我调用了该代码 thrash31.c
并将其编译成 thrash31
使用:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror thrash31.c -o thrash31
$
当运行用一个定时程序时,我得到了输出:
$ timecmd -u -- thrash31
2018-04-07 15:48:58.546809 [PID 9178] thrash31
Sum: 0x001FE976
2018-04-07 15:48:59.355508 [PID 9178; status 0x0000] - 0.808699s
$
因此, 运行 大约用了 0.8 秒。它生成的总和每次都相同,因为代码不会为随机数生成器提供种子。