https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=276eb28273f3dae420ff27bdb3baaca6964b5ed7
commit 276eb28273f3dae420ff27bdb3baaca6964b5ed7 Author: Jeremy Drake <cyg...@jdrake.com> Date: Fri Aug 1 11:03:00 2025 -0700 Cygwin: add api version check to c++ malloc struct override. This prevents memory corruption if a newer app or dll is used with an older cygwin dll. This is an unsupported scenario, but it's still a good idea to avoid corrupting memory if possible. Fixes: 7d5c55faa1 ("Cygwin: add wrappers for newer new/delete overloads") Co-authored-by: Corinna Vinschen <cori...@vinschen.de> Signed-off-by: Jeremy Drake <cyg...@jdrake.com> Diff: --- winsup/cygwin/globals.cc | 4 ++-- winsup/cygwin/include/cygwin/version.h | 3 +++ winsup/cygwin/lib/_cygwin_crt0_common.cc | 38 ++++++++++++++++++-------------- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/winsup/cygwin/globals.cc b/winsup/cygwin/globals.cc index d8e058f19..86b0c2718 100644 --- a/winsup/cygwin/globals.cc +++ b/winsup/cygwin/globals.cc @@ -173,8 +173,8 @@ extern "C" { /* unused */ {}, /* cxx_malloc */ &default_cygwin_cxx_malloc, /* hmodule */ NULL, - /* api_major */ 0, - /* api_minor */ 0, + /* api_major */ CYGWIN_VERSION_API_MAJOR, + /* api_minor */ CYGWIN_VERSION_API_MINOR, /* unused2 */ {}, /* posix_memalign */ posix_memalign, /* pseudo_reloc_start */ NULL, diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index f3321020f..00eedeb27 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -36,6 +36,9 @@ details. */ #define CYGWIN_VERSION_CHECK_FOR_EXTRA_TM_MEMBERS \ (CYGWIN_VERSION_USER_API_VERSION_COMBINED >= 272) +#define CYGWIN_VERSION_CHECK_FOR_CXX17_OVERLOADS(u) \ + (CYGWIN_VERSION_PER_PROCESS_API_VERSION_COMBINED (u) >= 359) + /* API_MAJOR 0.0: Initial version. API_MINOR changes: 1: Export cygwin32_ calls as cygwin_ as well. 2: Export j1, jn, y1, yn. diff --git a/winsup/cygwin/lib/_cygwin_crt0_common.cc b/winsup/cygwin/lib/_cygwin_crt0_common.cc index 5900e6315..a22528ab4 100644 --- a/winsup/cygwin/lib/_cygwin_crt0_common.cc +++ b/winsup/cygwin/lib/_cygwin_crt0_common.cc @@ -124,6 +124,8 @@ _cygwin_crt0_common (MainFunc f, per_process *u) { per_process *newu = (per_process *) cygwin_internal (CW_USER_DATA); bool uwasnull; + bool new_dll_with_additional_operators = + CYGWIN_VERSION_CHECK_FOR_CXX17_OVERLOADS (newu); /* u is non-NULL if we are in a DLL, and NULL in the main exe. newu is the Cygwin DLL's internal per_process and never NULL. */ @@ -176,12 +178,13 @@ _cygwin_crt0_common (MainFunc f, per_process *u) /* Likewise for the C++ memory operators, if any, but not if we were dlopen()'d, as we might get dlclose()'d and that would leave stale function pointers behind. */ - if (newu && newu->cxx_malloc && !__dynamically_loaded) + if (!__dynamically_loaded) { /* Inherit what we don't override. */ #define CONDITIONALLY_OVERRIDE(MEMBER) \ - if (!__cygwin_cxx_malloc.MEMBER) \ - __cygwin_cxx_malloc.MEMBER = newu->cxx_malloc->MEMBER; + if (__cygwin_cxx_malloc.MEMBER) \ + newu->cxx_malloc->MEMBER = __cygwin_cxx_malloc.MEMBER; + CONDITIONALLY_OVERRIDE(oper_new); CONDITIONALLY_OVERRIDE(oper_new__); CONDITIONALLY_OVERRIDE(oper_delete); @@ -190,20 +193,21 @@ _cygwin_crt0_common (MainFunc f, per_process *u) CONDITIONALLY_OVERRIDE(oper_new___nt); CONDITIONALLY_OVERRIDE(oper_delete_nt); CONDITIONALLY_OVERRIDE(oper_delete___nt); - CONDITIONALLY_OVERRIDE(oper_delete_sz); - CONDITIONALLY_OVERRIDE(oper_delete___sz); - CONDITIONALLY_OVERRIDE(oper_new_al); - CONDITIONALLY_OVERRIDE(oper_new___al); - CONDITIONALLY_OVERRIDE(oper_delete_al); - CONDITIONALLY_OVERRIDE(oper_delete___al); - CONDITIONALLY_OVERRIDE(oper_delete_sz_al); - CONDITIONALLY_OVERRIDE(oper_delete___sz_al); - CONDITIONALLY_OVERRIDE(oper_new_al_nt); - CONDITIONALLY_OVERRIDE(oper_new___al_nt); - CONDITIONALLY_OVERRIDE(oper_delete_al_nt); - CONDITIONALLY_OVERRIDE(oper_delete___al_nt); - /* Now update the resulting set into the global redirectors. */ - *newu->cxx_malloc = __cygwin_cxx_malloc; + if (new_dll_with_additional_operators) + { + CONDITIONALLY_OVERRIDE(oper_delete_sz); + CONDITIONALLY_OVERRIDE(oper_delete___sz); + CONDITIONALLY_OVERRIDE(oper_new_al); + CONDITIONALLY_OVERRIDE(oper_new___al); + CONDITIONALLY_OVERRIDE(oper_delete_al); + CONDITIONALLY_OVERRIDE(oper_delete___al); + CONDITIONALLY_OVERRIDE(oper_delete_sz_al); + CONDITIONALLY_OVERRIDE(oper_delete___sz_al); + CONDITIONALLY_OVERRIDE(oper_new_al_nt); + CONDITIONALLY_OVERRIDE(oper_new___al_nt); + CONDITIONALLY_OVERRIDE(oper_delete_al_nt); + CONDITIONALLY_OVERRIDE(oper_delete___al_nt); + } } /* Setup the module handle so fork can get the path name. */