传递有效Vector指针至PostMessage后解引用触发段错误排查
指针地址一致但解引用触发段错误问题
我有一个指向Vector的指针,传入函数前后指针地址完全一致,但在函数内解引用时触发了段错误。
发送端代码
/* . . . */ const Vector commands = EndLayout(); printf("About to post commands at 0x%16X\r\n", &commands); PostMessageW(handle, WM_PAINT, (WPARAM)&commands, ((long long unsigned int)&commands >> 32)); free(commands->data); return 0; }
处理函数代码
CALLBACK LRESULT handlePaint(HWND handle, WPARAM wParam, LPARAM lParam) { /* . . . */ const Vector *commands = (Vector *)((long long unsigned int)wParam | ((long long unsigned int)lParam << 32)); printf("Recieved command array at 0x%16X; about to paint\r\n", commands); for (unsigned int i = 0; i < commands->length; i++) { // Segmentation fault
日志输出
About to post commands at 0x 5B5FFC20 Recieved command array at 0x 5B5FFC20; about to paint * crash *
我猜测可能是线程差异导致,但不清楚具体原因。补充说明:使用Win32的PostMessageW向同一程序的窗口处理函数传递消息,处理函数调用handlePaint时参数一致,地址空间应相同,希望得到替代方案。
问题根源
这和线程地址空间无关,核心问题是局部变量的生命周期不匹配:
commands是栈上的局部变量,发送端函数执行到return 0后,当前栈帧被销毁,&commands指向的内存会被系统回收或覆盖。PostMessageW是异步消息机制,发送消息后发送端函数直接返回,窗口处理函数要到后续消息循环时才会执行。此时原来的commands内存已经失效,虽然地址显示一致,但内存内容已经不是有效的Vector数据,解引用必然触发段错误。- 另外你提前调用了
free(commands->data),就算commands内存没被销毁,其内部的data指针也已经变成野指针,同样会引发错误。
解决方案
方案1:动态分配堆内存
使用malloc在堆上分配Vector,堆内存不会随栈帧销毁而失效,窗口处理函数使用完后再手动释放:
// 发送端修改 Vector *commands = malloc(sizeof(Vector)); *commands = EndLayout(); printf("About to post commands at 0x%16X\r\n", commands); PostMessageW(handle, WM_PAINT, (WPARAM)commands, ((long long unsigned int)commands >> 32)); // 不要在这里释放内存,留到处理函数中执行 return 0; }
处理函数中完成逻辑后释放内存:
CALLBACK LRESULT handlePaint(HWND handle, WPARAM wParam, LPARAM lParam) { const Vector *commands = (Vector *)((long long unsigned int)wParam | ((long long unsigned int)lParam << 32)); printf("Recieved command array at 0x%16X; about to paint\r\n", commands); for (unsigned int i = 0; i < commands->length; i++) { // 你的处理逻辑 } free(commands->data); // 先释放内部数据 free(commands); // 再释放Vector本身 // 后续逻辑 }
方案2:改用同步消息发送
如果不需要异步处理,改用SendMessageW,它会等待窗口处理函数执行完成后才返回,此时局部变量commands的生命周期还未结束:
// 发送端修改 const Vector commands = EndLayout(); printf("About to send commands at 0x%16X\r\n", &commands); SendMessageW(handle, WM_PAINT, (WPARAM)&commands, ((long long unsigned int)&commands >> 32)); free(commands->data); // 此时处理函数已执行完毕,可安全释放 return 0; }
注意:SendMessageW会阻塞当前线程直到消息处理完成,要确保处理函数不会长时间阻塞主线程,避免程序假死。
内容的提问来源于stack exchange,提问作者Coarse Rosinflower
相关产品推荐
相关产品推荐

