Hi, Here's a similar ticket in another OSS. https://github.com/bellard/quickjs/issues/225#issuecomment-1908279228
> QuickJS may pass NULL pointers to memcpy with zero size. The C spec tells it is an undefined behavior but most C code do it, so the spec should be fixed instead. On Wed, Jan 24, 2024 at 4:57 PM Maxim Dounin <mdou...@mdounin.ru> wrote: > Hello! > > On Wed, Jan 24, 2024 at 12:09:02AM +0000, Ben Kallus wrote: > > > > As already pointed out previously, there are no known cases > > > when memcpy(p, NULL, 0) can result in miscompilation of nginx > > > code, ... If you think there are cases when the code can be > > > miscompiled in practice, and not theoretically, please share. > > > > There is no such thing as "miscompilation" of code that executes > > undefined behavior. The behavior is undefined; literally any > > instructions that the compiler emits is correct compilation. This is > > the definition of undefined behavior. > > While it is certainly true, this is purely theoretical. In > practice, real things happen: the code is compiled even to > something that is either correct or not. In all known cases so > far the compiled code is correct even if GCC with relevant > (mis)optimizations enabled is used. > > > You want me to cite a line in nginx that you would consider > > "miscompiled in practice." I'm not going to spend hours combing > > through assembly to convince you that undefined behavior is worth > > avoiding. Sorry! > > There is no need to convince me that undefined behaviour worth > avoiding. The point is that patching it in the particular place > you are trying to patch will make things worse by reducing > pressure on developers, not better. And there is no immediate > need to patch this particular place. > > Instead, we should ensure that a safe coding pattern is used > across the code - either by patching ngx_memcpy() and other > functions to check for length 0, or by reviewing and fixing all > the affected calls we are able to find, or by explicitly asking > GCC to avoid such misoptimizations (such as with > -fno-delete-null-pointer-check like Linux kernel does), or by > fixing the standard. > > [...] > > > > as nginx usually does not checks string data pointers > > > against NULL (and instead checks length, if needed). In > > > particular, ngx_pstrdup() you are trying to patch doesn't. That > > > is, this is exactly the "no direct impact" situation as assumed > > > above. > > > > It is non-obvious that checks against NULL will be optimized away > > after calls to ngx_memcpy. Whether a function even calls ngx_memcpy on > > a given pointer may not always be obvious, especially if that call > > happens many layers down the stack. > > In the particular place you are trying to patch, it is quite > obvious, even assuming link-time optimizations, since > ngx_pstrdup() is called in very few places. And this can be > easily verified at least for a particular compiler and compiler > options. > > For other places, that's indeed might not be obvious (but see > below), and that's why I asking you to share cases of the nginx > code miscompiled if you know any. The point is, however, that the > change you suggests with patching just ngx_pstrdup() won't fix > these other places. Instead, it will rather ensure these other > places are never fixed. > > OTOH, gcc13 with -O2 removes very few NULL pointer checks across > nginx codebase. In my tests (with "-S" added to compilation to > obtain assembler output), -fno-delete-null-pointer-check affects > only 31 files, and files I checked only have few pointer checks > removed (restored with -fno-delete-null-pointer-check): > > $ diff -urN objs.o2/src/ objs.o2fnodelete/src/ | diffstat > core/ngx_inet.o | 703 +-- > core/ngx_log.o | 555 +-- > core/ngx_open_file_cache.o | 581 +-- > core/ngx_output_chain.o | 771 ++-- > core/ngx_palloc.o | 153 > core/ngx_radix_tree.o | 327 - > core/ngx_resolver.o | 2252 ++++++------ > event/ngx_event.o | 850 ++-- > event/ngx_event_openssl.o | 3576 ++++++++++--------- > event/ngx_event_openssl_stapling.o | 6 > event/ngx_event_timer.o | 18 > event/ngx_event_udp.o | 127 > http/modules/ngx_http_auth_basic_module.o | 12 > http/modules/ngx_http_charset_filter_module.o | 7 > http/modules/ngx_http_fastcgi_module.o | 2134 +++++------ > http/modules/ngx_http_geo_module.o | 136 > http/modules/ngx_http_image_filter_module.o | 186 - > http/modules/ngx_http_limit_conn_module.o | 103 > http/modules/ngx_http_log_module.o | 948 ++--- > http/modules/ngx_http_secure_link_module.o | 34 > http/modules/ngx_http_slice_filter_module.o | 77 > http/modules/ngx_http_sub_filter_module.o | 126 > http/ngx_http_file_cache.o | 118 > http/ngx_http_parse.o | 842 ++-- > http/ngx_http_script.o | 16 > http/ngx_http_upstream.o | 4673 > +++++++++++++------------- > stream/ngx_stream_geo_module.o | 134 > stream/ngx_stream_limit_conn_module.o | 105 > stream/ngx_stream_log_module.o | 872 ++-- > stream/ngx_stream_proxy_module.o | 749 ++-- > stream/ngx_stream_script.o | 16 > 31 files changed, 10658 insertions(+), 10549 deletions(-) > > In particular, in the only real change in ngx_palloc.o assembler > is as follows: > > @@ -452,16 +452,19 @@ ngx_reset_pool: > testl %ebx, %ebx > jne .L99 .L97: > + testl %esi, %esi > + je .L100 > movl %esi, %eax > .p2align 4,,10 > .p2align 3 > > Which corresponds to restored with -fno-delete-null-pointer-check > initial "p" check on the first iteration of the second loop, due > to "pool->large" being used in the first loop initialization: > > for (l = pool->large; l; l = l->next) { > if (l->alloc) { > ngx_free(l->alloc); > } > } > > for (p = pool; p; p = p->d.next) { > p->d.last = (u_char *) p + sizeof(ngx_pool_t); > p->d.failed = 0; > } > > Many other cases, such as multiple changes in ngx_inet.o, one of > the two changes in ngx_open_file_cache.o, and one change > ngx_http_parse.o, correspond to ngx_strlchr() calls, where > subsequent result check is omitted because no-match is directly > handled by the inlined ngx_strlchr() code: > > p = ngx_strlchr(uri->data, last, '?'); > > if (p) { ... } > > And there seems to be no real changes in ngx_http_script.o and > ngx_stream_script.o, just some minor instructions reordering. > > Overall, it might be feasible to review all the differences to > ensure there are no real issues introduced by various compiler > optimizations. > > [...] > > > There is a proposal for C2y to define memcpy(NULL,NULL,0): > > > https://docs.google.com/document/d/1guH_HgibKrX7t9JfKGfWX2UCPyZOTLsnRfR6UleD1F8/edit > > If you feel strongly that memcpy from NULL should be defined, feel > > free to contribute to it :) > > Interesting, thanks. This would be the best solution and will > eliminate the need for any changes by defining the behaviour, as > it should. > > -- > Maxim Dounin > http://mdounin.ru/ > _______________________________________________ > nginx-devel mailing list > nginx-devel@nginx.org > https://mailman.nginx.org/mailman/listinfo/nginx-devel >
_______________________________________________ nginx-devel mailing list nginx-devel@nginx.org https://mailman.nginx.org/mailman/listinfo/nginx-devel