From: Viktor Szakats Date: Mon, 15 Dec 2025 15:49:04 +0000 (+0100) Subject: idn: clarify null-termination on Windows X-Git-Tag: rc-8_18_0-3~96 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=be76b32aed8ba5ee96bbd924a3e3fdbe959b321b;p=thirdparty%2Fcurl.git idn: clarify null-termination on Windows Add comments to clarify that a terminating null is always present in the buffers returned to the caller. The curl APIs `win32_idn_to_ascii()` or `win32_ascii_to_idn()` receive a null-terminated UTF-8 string as input. They first convert it to wide chars by first asking `MultiByteToWideChar()` to calculate the length, by passing -1. This API returns the length with the null char included (= `strlen() + 1`), does the conversion, with the output also null-terminated. `IdnTo*()` preserve this null character as documented. Then we pass this null-terminated, fixed-length buffer ito `WideCharToMultiByte()`, which keeps preserving the null, ending up in the buffer returned to the caller. Refs: https://learn.microsoft.com/windows/win32/api/stringapiset/nf-stringapiset-multibytetowidechar https://learn.microsoft.com/windows/win32/api/stringapiset/nf-stringapiset-widechartomultibyte https://learn.microsoft.com/windows/win32/api/winnls/nf-winnls-idntoascii https://learn.microsoft.com/windows/win32/api/winnls/nf-winnls-idntounicode WINE source code: https://gitlab.winehq.org/wine/wine/-/blob/wine-10.20/dlls/kernelbase/locale.c https://gitlab.winehq.org/wine/wine/-/blob/wine-10.20/dlls/ntdll/locale.c https://gitlab.winehq.org/wine/wine/-/blob/wine-10.20/dlls/ntdll/locale_private.h Ref: https://github.com/curl/curl/pull/19976#issuecomment-3656005765 Follow-up to 6694a42aa0e820a6fe1e59d85ff8597b6d768d8d #19798 Closes #19980 --- diff --git a/lib/idn.c b/lib/idn.c index 083be1d53f..ae781d3ca6 100644 --- a/lib/idn.c +++ b/lib/idn.c @@ -185,6 +185,9 @@ static CURLcode win32_idn_to_ascii(const char *in, char **out) wchar_t in_w[IDN_MAX_LENGTH]; int in_w_len; *out = NULL; + /* Returned in_w_len includes the null-terminator, which then gets + preserved across the calls that follow, ending up terminating + the buffer returned to the caller. */ in_w_len = MultiByteToWideChar(CP_UTF8, 0, in, -1, in_w, IDN_MAX_LENGTH); if(in_w_len) { wchar_t punycode[IDN_MAX_LENGTH]; @@ -208,6 +211,9 @@ static CURLcode win32_ascii_to_idn(const char *in, char **out) wchar_t in_w[IDN_MAX_LENGTH]; int in_w_len; *out = NULL; + /* Returned in_w_len includes the null-terminator, which then gets + preserved across the calls that follow, ending up terminating + the buffer returned to the caller. */ in_w_len = MultiByteToWideChar(CP_UTF8, 0, in, -1, in_w, IDN_MAX_LENGTH); if(in_w_len) { WCHAR idn[IDN_MAX_LENGTH]; /* stores a UTF-16 string */