]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
idn: clarify null-termination on Windows
authorViktor Szakats <commit@vsz.me>
Mon, 15 Dec 2025 15:49:04 +0000 (16:49 +0100)
committerViktor Szakats <commit@vsz.me>
Tue, 16 Dec 2025 15:30:43 +0000 (16:30 +0100)
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

lib/idn.c

index 083be1d53f88ee3559e68f0173a7661bca076056..ae781d3ca611aff5d87bed561a4148a64c3a8f56 100644 (file)
--- 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 */