[英]My dynamic array has a SIGSEGV when free()'d, but can be accessed?
最近,我一直难以跟踪细分错误。 奇怪的是,它使我可以很好地访问数组,但是由于某种原因,它不允许我释放它而不引起错误。 我测试了所有内容以确保没有其他内容,因此我可以100%肯定地说它仅出现在空闲线路上。 令人困惑的是,崩溃是非常有选择性的。 同样,它仅在我按下游戏菜单上的“帮助”按钮后发生,否则没有任何问题。 访问帮助部分后,它仍然允许访问,这使错误更加奇怪。 对于分段错误,我可能有一个错误的主意,但是我可以肯定,即使不是重大错误,它们也通常不允许访问。 我知道他们通常不适合我。 我会将代码发布在这里,但是我的项目很大。 我将尝试发布重要部分。
这是我分配数组的方法:
static void zero_array( void * memory, int elements, size_t element_size )
{
memset( memory, 0, elements * element_size );
return;
}
/* ******************************************************** */
static void fill_array_with_ones( void * memory, int elements, size_t element_size )
{
memset( memory, 1, elements * element_size );
return;
}
/* ******************************************************** */
static void * create_array( int elements, size_t element_size, t_setter setter )
{
void * temp = NULL;
if ( !( temp = malloc( elements * element_size ) ) )
{
perror( "malloc" );
exit( 1 );
}
if ( setter )
setter( temp, elements, element_size );
return temp;
}
我已经多次测试了,没有问题。 我主要将其用于菜单API,以便更轻松地在位图图像上跟踪SDL中的按钮事件。
我针对问题区域的设置代码如下所示:
extern void setup_mdata( game_data * game, menu * tmenu, const char * menu_image_path, int max_buttons, bool default_handling, t_handle_var_mdata handle_mdata )
{
int width = 0;
int height = 0;
tmenu->max_buttons = max_buttons;
tmenu->allocation_size = sizeof( bool ) * game->game_menu.max_buttons;
tmenu->hover_over_button = ( bool * )create_array( max_buttons, sizeof( bool ), zero_array );
tmenu->is_clicked = ( bool * )create_array( max_buttons, sizeof( bool ), zero_array );
if ( !default_handling )
tmenu->is_enabled = ( bool * )create_array( max_buttons, sizeof( bool ), fill_array_with_ones );
tmenu->button_shape = ( SDL_Rect * )create_array( max_buttons, sizeof( SDL_Rect ), zero_array );
tmenu->menu_image = load_texture( game->renderer, ( char * )menu_image_path, true, 255, 0, 255 );
SDL_QueryTexture( game->game_menu.menu_image, NULL, NULL, &width, &height );
handle_mdata( game, tmenu, width, height );
return;
}
再一次,我已经多次测试了此代码,并且在任何其他菜单上都从未失败过。 这使问题对我很奇怪。
这是我为标题屏幕的主菜单和帮助菜单调用此函数的方式:
setup_mdata( game, &game->title_menu, "bitmaps//title_menu.bmp", 3, true, setup_title_menu );
setup_mdata( game, &game->title_help_menu, "bitmaps//title_help_menu.bmp", 3, true, setup_title_help_menu );
我认为这无关紧要,但是如果您想知道,这是使用附加数据实际设置菜单的代码。
static void setup_title_menu( game_data * game, menu * tmenu, int width, int height )
{
int nbutton = 0;
tmenu->button_highlight = ( SDL_Texture ** )create_array( 1, sizeof( SDL_Texture * ), zero_array );
*tmenu->button_highlight = load_texture( game->renderer, ( char * )"bitmaps//button4_highlight.bmp", true, 255, 255, 255 );
for ( ; nbutton < tmenu->max_buttons; nbutton++ )
{
MB_SHAPE.h = TITLE_BUTTON_HEIGHT;
MB_SHAPE.w = TITLE_BUTTON_WIDTH;
MB_SHAPE.x = menu_shape.x + FIRST_TITLE_BUTTON_X;
MB_SHAPE.y = menu_shape.y + FIRST_TITLE_BUTTON_Y + ( ( TITLE_BUTTON_HEIGHT + TITLE_BUTTON_DIVIDER_HEIGHT ) * nbutton );
}
return;
}
/* ******************************************************** */
static void setup_title_help_page_shape( game_data * game )
{
game->title_screen_data.help_page_shape.h = HELP_PAGE_HEIGHT;
game->title_screen_data.help_page_shape.w = HELP_PAGE_WIDTH;
game->title_screen_data.help_page_shape.x = menu_shape.x + 59;
game->title_screen_data.help_page_shape.y = menu_shape.y + 192;
return;
}
/* ******************************************************** */
static void setup_title_help_menu( game_data * game, menu * tmenu, int width, int height )
{
int nbutton = 0;
tmenu->button_highlight = ( SDL_Texture ** )create_array( 2, sizeof( SDL_Texture * ), zero_array );
tmenu->button_highlight[0] = load_texture( game->renderer, ( char * )"bitmaps//button2_highlight.bmp", true, 255, 255, 255 );
tmenu->button_highlight[1] = load_texture( game->renderer, ( char * )"bitmaps//triangle_highlight.bmp", true, 255, 255, 255 );
setup_title_help_page_shape( game );
for ( ; nbutton < tmenu->max_buttons; nbutton++ )
{
switch ( nbutton )
{
case GO_BACK :
tmenu->button_shape[GO_BACK].h = 50;
tmenu->button_shape[GO_BACK].w = 120;
tmenu->button_shape[GO_BACK].x = menu_shape.x + 329;
tmenu->button_shape[GO_BACK].y = menu_shape.y + 61;
break;
case ARROW_RIGHT :
tmenu->button_shape[ARROW_RIGHT].h = 34;
tmenu->button_shape[ARROW_RIGHT].w = 17;
tmenu->button_shape[ARROW_RIGHT].x = menu_shape.x + 432;
tmenu->button_shape[ARROW_RIGHT].y = menu_shape.y + 473;
break;
case ARROW_LEFT :
tmenu->button_shape[ARROW_LEFT].h = 34;
tmenu->button_shape[ARROW_LEFT].w = 17;
tmenu->button_shape[ARROW_LEFT].x = menu_shape.x + 390;
tmenu->button_shape[ARROW_LEFT].y = menu_shape.y + 473;
break;
}
}
return;
}
它实际中断的部分是当我尝试执行此操作时:
free( game->title_help_menu.is_clicked );
free( game->title_help_menu.hover_over_button );
如果您想知道,无论出于何种原因,它都不会中断帮助菜单数组。 这让我更加困惑。 我通过删除这些功能确保没有其他问题,并且没有抛出SIGSEGV。 我认为是导致此问题的一些细微问题,但我不知道这是什么。 我很高兴你们中的任何人比我更了解调试,并且至少可以提出一些建议。
奇怪的是,它使我可以很好地访问数组,但是由于某种原因,它不允许我释放它而不引起错误。
这是不奇怪的 。
大多数UNIX malloc
实现不会立即将free
d内存释放到OS。 取而代之的是,他们将其保留在空闲列表中,以希望应用程序再次请求它,并且可以在不执行系统调用的情况下轻松使用它(这很昂贵)。
令人困惑的是,崩溃是非常有选择性的。
对于堆损坏问题,这也非常典型。 当您破坏堆时(例如,通过分配的缓冲区溢出或free
两次),崩溃可能会晚得多,并且当您更改无关的东西时可能会消失。
好消息: Valgrind和Address Sanitizer之类的工具通常可以帮助您快速有效地发现堆损坏问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.