You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用WriteConsoleW后释放宽字符串内存致崩溃,是否需释放?

控制台宽字符串释放崩溃问题分析

崩溃原因

程序崩溃的核心原因是内存分配与释放函数不匹配:

  • 你的CHARtoWCHAR函数使用Windows API的LocalAlloc(LPTR)分配宽字符串内存
  • 但在console_print中却用C标准库的free()释放这块内存
  • C标准库的内存管理函数(malloc/free等)和Windows本地堆函数(LocalAlloc/LocalFree等)属于不同的堆管理体系,混用会直接导致堆结构损坏,触发程序崩溃。

另外,WriteConsoleW不会自动释放传入的缓冲区,你必须自行负责内存的释放工作,但必须保证分配和释放函数的匹配性。

解决方案

将释放ws的代码从free(ws);替换为Windows API的LocalFree(ws);,同时可以补充一些健壮性检查:

修正后的console_print函数

void console_print(const char *fmt, ...) {
    va_list args;

    va_start(args, fmt);
    char *buf = smprintf(fmt, args);
    va_end(args);

    if (buf == NULL) {
        return;
    }

    DWORD cCharsWritten; // 用于接收实际写入的字符数
    HANDLE std_out = GetStdHandle(STD_OUTPUT_HANDLE);
    LPWSTR ws = CHARtoWCHAR(buf, CP_ACP);
    
    if (ws != NULL) { // 检查宽字符串分配是否成功
        WriteConsoleW(std_out, ws, wcslen(ws), &cCharsWritten, NULL);
        LocalFree(ws); // 使用LocalFree匹配LocalAlloc的分配
    }

    free(buf);
}

额外注意事项

  1. 始终检查CHARtoWCHAR的返回值:如果LocalAlloc分配失败,会返回NULL,此时调用wcslen或WriteConsoleW会引发新的错误
  2. WriteConsoleW的第四个参数如果传NULL,虽然函数可以正常执行,但无法获取实际写入控制台的字符数;传入有效的DWORD变量可以帮助调试或处理写入异常的情况

原函数代码参考

CHARtoWCHAR函数

LPWSTR CHARtoWCHAR(LPSTR str, UINT codePage) {
    size_t len = strlen(str) + 1;
    int size_needed = MultiByteToWideChar(codePage, 0, str, len, NULL, 0);
    LPWSTR wstr = (LPWSTR) LocalAlloc(LPTR, sizeof(WCHAR) * size_needed);
    if (wstr != NULL) { // 补充分配成功检查
        MultiByteToWideChar(codePage, 0, str, len, wstr, size_needed);
    }
    return wstr;
}

smprintf函数

// Creates a buffer and fills it with a string formatted with the specified
// format and arguments. Caller must free the buffer after usage.
char *smprintf(const char *fmt, ...) {
    va_list args;

    // 1. Measure the required size of buffer.
    va_start(args, fmt);
    int len = vsnprintf(NULL, 0, fmt, args);
    va_end(args);

    // 2. Create the buffer.
    char *buf = malloc(++len);
    if (buf == NULL) {
        return NULL;
    }

    // 3. Fill the buffer.
    va_start(args, fmt);
    vsnprintf(buf, len, fmt, args);
    va_end(args);

    return buf; // Do not forget to use: free(x).
}

内容的提问来源于stack exchange,提问作者user17471643

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 05:28:31