cwindowsconsolecharwidechar

Do I need to free memory after call to WriteConsoleW?


I am writing a function which prints a formatted string in a Windows console. It takes a simple C string which is a single byte string, converts it into a wide string for the Windows O.S., sends it to the console and frees both buffers. The buffer of a single-byte string is freed normally, but when I free the wide string, the program crashes.

When I free the allocated memory right after the call to WriteConsoleW, the application crashes.

Why does it crash ?

Do I need to free that ws buffer, supplied to the WriteConsoleW function, or does it free it internally and automagically ?

Here is my function:

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;
    }

    PDWORD cChars = NULL;
    HANDLE std_out = GetStdHandle(STD_OUTPUT_HANDLE);
    LPWSTR ws = CHARtoWCHAR(buf, CP_ACP);
    WriteConsoleW(std_out, ws, wcslen(ws), cChars, NULL);

    free(ws); // This line crashes the program.
    free(buf);
}

The second buffer for a wide string, the ws, is allocated inside the CHARtoWCHAR function:

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);
    MultiByteToWideChar(codePage, 0, str, len, wstr, size_needed);
    return wstr;
}

The smprintf function creates a C formatted string.

// 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).
}

Thank you.


Solution

  • Thanks to Jabberwocky.
    I forgot to use the LocalFree.

    LocalFree(ws);
    free(buf);