添加结构代码后,Valgrind 无效写入
Valgrind invalid write, after struct code addition
对于学校,我必须用单元格初始化地图。
在使用 Valgrind 分析我的代码时,我 运行 遇到了一些问题。
我使用的初始化函数之前工作,但在添加两个额外的整数指针和一个整数后停止运行。内存是动态分配的,错误出现在之前也存在的部分,这让我很困惑。发生的错误如下:
==4877== Invalid write of size 4
==4877== at 0x401723: initialize_map (list.c:312)
==4877== by 0x400B99: main (initialization.c:14)
==4877== Address 0x550deb8 is 0 bytes after a block of size 2,584 alloc'd
==4877== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4877== by 0x4016EA: initialize_map (list.c:306)
==4877== by 0x400B99: main (initialization.c:14)
==4877==
==4877== Invalid write of size 4
==4877== at 0x40172D: initialize_map (list.c:313)
==4877== by 0x400B99: main (initialization.c:14)
==4877== Address 0x550debc is 4 bytes after a block of size 2,584 alloc'd
==4877== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4877== by 0x4016EA: initialize_map (list.c:306)
==4877== by 0x400B99: main (initialization.c:14)
==4877==
valgrind: m_mallocfree.c:277 (mk_plain_bszB): Assertion 'bszB != 0' failed.
valgrind: This is probably caused by your program erroneously writing past the
end of a heap block and corrupting heap metadata. If you fix any
invalid writes reported by Memcheck, this assertion failure will
probably go away. Please try that before reporting this as a bug.
初始化代码如下:
worldmap* initialize_map(game_settings* settings)
{
int maxplayers = 10;
int rows = settings->rows;
int cols = settings->cols;
worldmap* world = malloc(sizeof(worldmap)); //free in cleanup_map
if(world != NULL)
{
world->rows = rows;
world->cols = cols;
world->map = malloc(sizeof(cell)*rows*cols); //free in cleanup_map
for(int i = 0; i < rows;i++)
{
for(int j = 0; j < cols;j++)
{
cell* cell = index_map(world, j, i); //cell* is world->map + offset
cell->type = CELL_DIRT;
cell->owner = 0;
}
}
world->players = 0;
world->score = NULL; //NULL pointer, since this pointer set in a later function
world->playerturns = NULL; //NULL pointer, since this pointer set in a later function
return world;
}
else{printf("No world found.\n");}
}
此 initialize_map()
代码的新增内容是:int maxplayers
、world->players
、world->score
和 world->playerturns
,其余代码在 运行 它在 valgrind 中,没有这些添加。在这段代码中 index_map()
returns a cell* w->map+y_offset + x_offset
我在其他几篇文章中读到,这可能与像这样再次单独分配整数值和整数指针有关(我试图在出现无效写入错误的部分执行此操作):
world->map = malloc(sizeof(cell)*rows*cols);
for(int i = 0; i < rows;i++)
{
for(int j = 0; j < cols;j++)
{
cell* cell = index_map(world, j, i); //cell8 is world->map + offset
cell->type = malloc(sizeof(celltype);
*(cell->type) = CELL_DIRT;
cell->owner = malloc(sizeof(int);
*(cell->type) = 0;
}
}
尝试编译这段代码时,出现以下错误:
"invalid type argument of unary ‘*’ (have ‘unsigned int’)
*(cell->type) = 0;
“
这些是我使用的结构:
单元格结构:
typedef struct{
celltype type;
unsigned int owner;
} cell;
世界地图结构:
typedef struct
{
cell* map;
unsigned int rows;
unsigned int cols;
int players;
int* score;
int* playerturns;
} worldmap;
单元格结构保持不变,世界地图结构之前仅由cell* map
、unsigned int rows
和unsigned int cols
.
组成
编辑
index_map代码:
cell* index_map(worldmap* w, int x, int y)
{
cell* place;
place = w->map + x*w->cols + y;
return place;
}
cell->type = malloc(sizeof(celltype);
类型不是指针。你为 cell
本身分配内存吗?什么是 index_max
?
cell* cell
对类型和变量使用相同的名称并不是一个好主意。
*(cell->type)
是废话。使用 cell->type
或 (*cell).type
(前者更具可读性)。
- 总的来说,您在几个似乎没有任何意义的地方使用了 malloc,您可以改用普通变量。
- 你在哪里
free()
这一切?如果您不这样做,Valgrind 可能会变得不高兴。
以此类推
valgrind 错误基本上是说您访问的内存超出了您分配的映射范围。现在您已经包含了 index_map
函数,原因就很清楚了。
想象一下,如果您的地图是 5 列 x 2 行 - 那么大小为 10 个单元格。这意味着最多 x 和 y 可能是 4 和 1。你的函数计算 4*5+1 到 return 第 21 个单元格......计算出来的代码应该是这个
place = w->map + x*w->rows + y;
或
place = w->map + x + y*w->cols;
这会给你 4*2+1 或 4+1*5 = 第 9 个单元格。
至于您提到的其他问题,您不需要为这些值分配内存,因为它们不是指针。例如
cell->owner = malloc(sizeof(int);
cell->owner
是一个无符号整数,因此您只需 cell->owner = 10;
即可为其赋值。
此外,您也不需要取消引用它们两次来使用它们 - *(cell->owner)
太过分了,只需要 cell->owner
。
对于学校,我必须用单元格初始化地图。 在使用 Valgrind 分析我的代码时,我 运行 遇到了一些问题。 我使用的初始化函数之前工作,但在添加两个额外的整数指针和一个整数后停止运行。内存是动态分配的,错误出现在之前也存在的部分,这让我很困惑。发生的错误如下:
==4877== Invalid write of size 4
==4877== at 0x401723: initialize_map (list.c:312)
==4877== by 0x400B99: main (initialization.c:14)
==4877== Address 0x550deb8 is 0 bytes after a block of size 2,584 alloc'd
==4877== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4877== by 0x4016EA: initialize_map (list.c:306)
==4877== by 0x400B99: main (initialization.c:14)
==4877==
==4877== Invalid write of size 4
==4877== at 0x40172D: initialize_map (list.c:313)
==4877== by 0x400B99: main (initialization.c:14)
==4877== Address 0x550debc is 4 bytes after a block of size 2,584 alloc'd
==4877== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4877== by 0x4016EA: initialize_map (list.c:306)
==4877== by 0x400B99: main (initialization.c:14)
==4877==
valgrind: m_mallocfree.c:277 (mk_plain_bszB): Assertion 'bszB != 0' failed.
valgrind: This is probably caused by your program erroneously writing past the
end of a heap block and corrupting heap metadata. If you fix any
invalid writes reported by Memcheck, this assertion failure will
probably go away. Please try that before reporting this as a bug.
初始化代码如下:
worldmap* initialize_map(game_settings* settings)
{
int maxplayers = 10;
int rows = settings->rows;
int cols = settings->cols;
worldmap* world = malloc(sizeof(worldmap)); //free in cleanup_map
if(world != NULL)
{
world->rows = rows;
world->cols = cols;
world->map = malloc(sizeof(cell)*rows*cols); //free in cleanup_map
for(int i = 0; i < rows;i++)
{
for(int j = 0; j < cols;j++)
{
cell* cell = index_map(world, j, i); //cell* is world->map + offset
cell->type = CELL_DIRT;
cell->owner = 0;
}
}
world->players = 0;
world->score = NULL; //NULL pointer, since this pointer set in a later function
world->playerturns = NULL; //NULL pointer, since this pointer set in a later function
return world;
}
else{printf("No world found.\n");}
}
此 initialize_map()
代码的新增内容是:int maxplayers
、world->players
、world->score
和 world->playerturns
,其余代码在 运行 它在 valgrind 中,没有这些添加。在这段代码中 index_map()
returns a cell* w->map+y_offset + x_offset
我在其他几篇文章中读到,这可能与像这样再次单独分配整数值和整数指针有关(我试图在出现无效写入错误的部分执行此操作):
world->map = malloc(sizeof(cell)*rows*cols);
for(int i = 0; i < rows;i++)
{
for(int j = 0; j < cols;j++)
{
cell* cell = index_map(world, j, i); //cell8 is world->map + offset
cell->type = malloc(sizeof(celltype);
*(cell->type) = CELL_DIRT;
cell->owner = malloc(sizeof(int);
*(cell->type) = 0;
}
}
尝试编译这段代码时,出现以下错误:
"invalid type argument of unary ‘*’ (have ‘unsigned int’)
*(cell->type) = 0;
“
这些是我使用的结构:
单元格结构:
typedef struct{
celltype type;
unsigned int owner;
} cell;
世界地图结构:
typedef struct
{
cell* map;
unsigned int rows;
unsigned int cols;
int players;
int* score;
int* playerturns;
} worldmap;
单元格结构保持不变,世界地图结构之前仅由cell* map
、unsigned int rows
和unsigned int cols
.
编辑 index_map代码:
cell* index_map(worldmap* w, int x, int y)
{
cell* place;
place = w->map + x*w->cols + y;
return place;
}
cell->type = malloc(sizeof(celltype);
类型不是指针。你为cell
本身分配内存吗?什么是index_max
?cell* cell
对类型和变量使用相同的名称并不是一个好主意。*(cell->type)
是废话。使用cell->type
或(*cell).type
(前者更具可读性)。- 总的来说,您在几个似乎没有任何意义的地方使用了 malloc,您可以改用普通变量。
- 你在哪里
free()
这一切?如果您不这样做,Valgrind 可能会变得不高兴。
以此类推
valgrind 错误基本上是说您访问的内存超出了您分配的映射范围。现在您已经包含了 index_map
函数,原因就很清楚了。
想象一下,如果您的地图是 5 列 x 2 行 - 那么大小为 10 个单元格。这意味着最多 x 和 y 可能是 4 和 1。你的函数计算 4*5+1 到 return 第 21 个单元格......计算出来的代码应该是这个
place = w->map + x*w->rows + y;
或
place = w->map + x + y*w->cols;
这会给你 4*2+1 或 4+1*5 = 第 9 个单元格。
至于您提到的其他问题,您不需要为这些值分配内存,因为它们不是指针。例如
cell->owner = malloc(sizeof(int);
cell->owner
是一个无符号整数,因此您只需 cell->owner = 10;
即可为其赋值。
此外,您也不需要取消引用它们两次来使用它们 - *(cell->owner)
太过分了,只需要 cell->owner
。