[PATCH 03 of 12] Win32: non-ASCII directory names support in ngx_getcwd()

Maxim Dounin mdounin at mdounin.ru
Sun Feb 19 17:23:23 UTC 2023


Hello!

On Fri, Feb 17, 2023 at 07:04:04PM +0400, Sergey Kandaurov wrote:

> > On 13 Jan 2023, at 01:35, Maxim Dounin <mdounin at mdounin.ru> wrote:
> > 
> > # HG changeset patch
> > # User Maxim Dounin <mdounin at mdounin.ru>
> > # Date 1673548916 -10800
> > #      Thu Jan 12 21:41:56 2023 +0300
> > # Node ID 7cf820c46860796cff91f53a5d2db669bb5b5a6c
> > # Parent  d05c0adf5890aecc68ce8906ef19ca07502ed071
> > Win32: non-ASCII directory names support in ngx_getcwd().
> > 
> > This makes it possible to start nginx without a prefix explicitly set
> > in a directory with non-ASCII characters in it.
> > 
> > diff -r d05c0adf5890 -r 7cf820c46860 src/os/win32/ngx_files.c
> > --- a/src/os/win32/ngx_files.c	Thu Jan 12 21:41:39 2023 +0300
> > +++ b/src/os/win32/ngx_files.c	Thu Jan 12 21:41:56 2023 +0300
> > @@ -428,6 +428,30 @@ ngx_realpath(u_char *path, u_char *resol
> > }
> > 
> > 
> > +size_t
> > +ngx_getcwd(u_char *buf, size_t size)
> > +{
> > +    u_char   *p;
> > +    size_t    n;
> > +    u_short   utf16[NGX_MAX_PATH];
> > +
> > +    n = GetCurrentDirectoryW(NGX_MAX_PATH, utf16);
> > +
> > +    if (n == 0) {
> > +        return 0;
> > +    }

Re-reading the documentation, I tend to think this might worth an 
additional test for "(n > NGX_MAX_PATH)"
(https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getcurrentdirectory):

: If the function succeeds, the return value specifies the number 
: of characters that are written to the buffer, not including the 
: terminating null character.

: If the function fails, the return value is zero. To get extended 
: error information, call GetLastError.

: If the buffer that is pointed to by lpBuffer is not large 
: enough, the return value specifies the required size of the 
: buffer, in characters, including the null-terminating character.

That is, there will be no explicit error (n == 0) if the buffer 
will happen to be insufficient.  On the other hand, this probably 
can happen with long paths enabled (see 
https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=registry), 
so it might be a good idea to add an explicit handling while here.

> > +
> > +    p = ngx_utf16_to_utf8(buf, utf16, &size, NULL);
> > +
> 
> No error check may result in double-free, first freed
> after (re-)allocation on NGX_EILSEQ, then as below.

Free on NGX_EILSEQ after reallocation only frees the memory 
allocated by the ngx_utf16_to_utf8() itself.  The incorrect free() 
was before reallocation, and is now fixed.

Since on errors ngx_utf16_to_utf8() returns NULL, it is matched by 
the "if (p != buf)" test, and processed identically to 
reallocations.  The only questionable part is ngx_free(NULL), 
though as per C standard (starting at least with C89; and also 
win32 documentation) this is guaranteed to be a nop.

> > +    if (p != buf) {
> > +        ngx_free(p);
> > +        return 0;
> 
> Why return an error if (re-)allocation happened?
> Sizes (calculated in 1-byte units) above NGX_MAX_PATH
> seem perfectly valid with multibyte UTF-8.

The ngx_getcwd() interface does not provide a way to return a new 
pointer.  Rather, it is strictly limited to the buffer provided by 
the caller, and can only return an error if the buffer is not 
large enough.

One possible improvement here is to explicitly set the errno to a 
reasonable value if this happens.  This would require an explicit 
handling of other errors though.

Combined with the above:

diff -r 6705dd675ace src/os/win32/ngx_files.c
--- a/src/os/win32/ngx_files.c	Sat Feb 18 16:01:20 2023 +0300
+++ b/src/os/win32/ngx_files.c	Sun Feb 19 03:22:48 2023 +0300
@@ -442,10 +442,20 @@ ngx_getcwd(u_char *buf, size_t size)
         return 0;
     }
 
+    if (n > NGX_MAX_PATH) {
+        ngx_set_errno(ERROR_INSUFFICIENT_BUFFER);
+        return 0;
+    }
+
     p = ngx_utf16_to_utf8(buf, utf16, &size, NULL);
 
+    if (p == NULL) {
+        return 0;
+    }
+
     if (p != buf) {
         ngx_free(p);
+        ngx_set_errno(ERROR_INSUFFICIENT_BUFFER);
         return 0;
     }
 

[...]


-- 
Maxim Dounin
http://mdounin.ru/


More information about the nginx-devel mailing list