[PATCH] msvcrt: Duplicate the secondary structs in _get_current_locale().

Chip Davis cdavis at codeweavers.com
Sun Jan 26 20:18:13 CST 2020


Otherwise, the returned _locale_t will reflect the state after a
setlocale() call, and not before.

Respect the refcount pointers now; this is necessary to share malloc'd
stuff between _locale_t instances.

Signed-off-by: Chip Davis <cdavis at codeweavers.com>
---
 dlls/msvcr90/tests/msvcr90.c |  27 +++++++
 dlls/msvcrt/locale.c         | 146 ++++++++++++++++++++++++++---------
 2 files changed, 137 insertions(+), 36 deletions(-)

diff --git a/dlls/msvcr90/tests/msvcr90.c b/dlls/msvcr90/tests/msvcr90.c
index c8a49f25492d..07403c6b2fc7 100644
--- a/dlls/msvcr90/tests/msvcr90.c
+++ b/dlls/msvcr90/tests/msvcr90.c
@@ -139,6 +139,7 @@ static int (__cdecl *p_swscanf)(const wchar_t *str, const wchar_t* format, ...);
 static int (__cdecl *p____mb_cur_max_l_func)(_locale_t locale);
 static _locale_t (__cdecl *p__create_locale)(int, const char*);
 static void (__cdecl *p__free_locale)(_locale_t);
+static _locale_t (__cdecl *p__get_current_locale)(void);
 
 /* make sure we use the correct errno */
 #undef errno
@@ -408,6 +409,7 @@ static BOOL init(void)
     SET(p____mb_cur_max_l_func, "___mb_cur_max_l_func");
     SET(p__create_locale, "_create_locale");
     SET(p__free_locale, "_free_locale");
+    SET(p__get_current_locale, "_get_current_locale");
 
     if (sizeof(void *) == 8)
     {
@@ -1961,6 +1963,30 @@ static void test____mb_cur_max_l_func(void)
     p__free_locale(l);
 }
 
+static void test__get_current_locale(void)
+{
+    _locale_t l = p__get_current_locale();
+#define lc_str(lc, s) \
+    ok(!strcmp(l->locinfo->lc_category[lc].locale, s), #lc " = \"%s\"\n", \
+        l->locinfo->lc_category[lc].locale)
+    lc_str(LC_COLLATE, "C");
+    lc_str(LC_CTYPE, "C");
+    lc_str(LC_MONETARY, "C");
+    lc_str(LC_NUMERIC, "C");
+    lc_str(LC_TIME, "C");
+
+    p_setlocale(LC_ALL, "english");
+    lc_str(LC_COLLATE, "C");
+    lc_str(LC_CTYPE, "C");
+    lc_str(LC_MONETARY, "C");
+    lc_str(LC_NUMERIC, "C");
+    lc_str(LC_TIME, "C");
+#undef lc_str
+
+    p__free_locale(l);
+    p_setlocale(LC_ALL, "C");
+}
+    
 START_TEST(msvcr90)
 {
     if(!init())
@@ -2001,4 +2027,5 @@ START_TEST(msvcr90)
     test___strncnt();
     test_swscanf();
     test____mb_cur_max_l_func();
+    test__get_current_locale();
 }
diff --git a/dlls/msvcrt/locale.c b/dlls/msvcrt/locale.c
index 04a808d6b9c4..21e155d452c1 100644
--- a/dlls/msvcrt/locale.c
+++ b/dlls/msvcrt/locale.c
@@ -876,6 +876,9 @@ void free_locinfo(MSVCRT_pthreadlocinfo locinfo)
         return;
 
     for(i=MSVCRT_LC_MIN+1; i<=MSVCRT_LC_MAX; i++) {
+        if(!locinfo->lc_category[i].refcount ||
+            InterlockedDecrement(locinfo->lc_category[i].refcount))
+            continue;
         MSVCRT_free(locinfo->lc_category[i].locale);
         MSVCRT_free(locinfo->lc_category[i].refcount);
 #if _MSVCR_VER >= 110
@@ -884,37 +887,51 @@ void free_locinfo(MSVCRT_pthreadlocinfo locinfo)
     }
 
     if(locinfo->lconv) {
-        MSVCRT_free(locinfo->lconv->decimal_point);
-        MSVCRT_free(locinfo->lconv->thousands_sep);
-        MSVCRT_free(locinfo->lconv->grouping);
-        MSVCRT_free(locinfo->lconv->int_curr_symbol);
-        MSVCRT_free(locinfo->lconv->currency_symbol);
-        MSVCRT_free(locinfo->lconv->mon_decimal_point);
-        MSVCRT_free(locinfo->lconv->mon_thousands_sep);
-        MSVCRT_free(locinfo->lconv->mon_grouping);
-        MSVCRT_free(locinfo->lconv->positive_sign);
-        MSVCRT_free(locinfo->lconv->negative_sign);
+        if(locinfo->lconv_num_refcount &&
+            !InterlockedDecrement(locinfo->lconv_num_refcount)) {
+            MSVCRT_free(locinfo->lconv->decimal_point);
+            MSVCRT_free(locinfo->lconv->thousands_sep);
+            MSVCRT_free(locinfo->lconv->grouping);
 #if _MSVCR_VER >= 100
-        MSVCRT_free(locinfo->lconv->_W_decimal_point);
-        MSVCRT_free(locinfo->lconv->_W_thousands_sep);
-        MSVCRT_free(locinfo->lconv->_W_int_curr_symbol);
-        MSVCRT_free(locinfo->lconv->_W_currency_symbol);
-        MSVCRT_free(locinfo->lconv->_W_mon_decimal_point);
-        MSVCRT_free(locinfo->lconv->_W_mon_thousands_sep);
-        MSVCRT_free(locinfo->lconv->_W_positive_sign);
-        MSVCRT_free(locinfo->lconv->_W_negative_sign);
+            MSVCRT_free(locinfo->lconv->_W_decimal_point);
+            MSVCRT_free(locinfo->lconv->_W_thousands_sep);
 #endif
+            MSVCRT_free(locinfo->lconv_num_refcount);
+        }
+        if(locinfo->lconv_mon_refcount &&
+            !InterlockedDecrement(locinfo->lconv_mon_refcount)) {
+            MSVCRT_free(locinfo->lconv->int_curr_symbol);
+            MSVCRT_free(locinfo->lconv->currency_symbol);
+            MSVCRT_free(locinfo->lconv->mon_decimal_point);
+            MSVCRT_free(locinfo->lconv->mon_thousands_sep);
+            MSVCRT_free(locinfo->lconv->mon_grouping);
+            MSVCRT_free(locinfo->lconv->positive_sign);
+            MSVCRT_free(locinfo->lconv->negative_sign);
+#if _MSVCR_VER >= 100
+            MSVCRT_free(locinfo->lconv->_W_int_curr_symbol);
+            MSVCRT_free(locinfo->lconv->_W_currency_symbol);
+            MSVCRT_free(locinfo->lconv->_W_mon_decimal_point);
+            MSVCRT_free(locinfo->lconv->_W_mon_thousands_sep);
+            MSVCRT_free(locinfo->lconv->_W_positive_sign);
+            MSVCRT_free(locinfo->lconv->_W_negative_sign);
+#endif
+            MSVCRT_free(locinfo->lconv_mon_refcount);
+        }
+        if(locinfo->lconv_intl_refcount &&
+            !InterlockedDecrement(locinfo->lconv_intl_refcount)) {
+            MSVCRT_free(locinfo->lconv_intl_refcount);
+            MSVCRT_free(locinfo->lconv);
+        }
     }
-    MSVCRT_free(locinfo->lconv_intl_refcount);
-    MSVCRT_free(locinfo->lconv_num_refcount);
-    MSVCRT_free(locinfo->lconv_mon_refcount);
-    MSVCRT_free(locinfo->lconv);
 
-    MSVCRT_free(locinfo->ctype1_refcount);
-    MSVCRT_free(locinfo->ctype1);
+    if(locinfo->ctype1_refcount &&
+        !InterlockedDecrement(locinfo->ctype1_refcount)) {
+        MSVCRT_free(locinfo->ctype1_refcount);
+        MSVCRT_free(locinfo->ctype1);
 
-    MSVCRT_free(locinfo->pclmap);
-    MSVCRT_free(locinfo->pcumap);
+        MSVCRT_free(locinfo->pclmap);
+        MSVCRT_free(locinfo->pcumap);
+    }
 
     if(locinfo->lc_time_curr != &cloc_time_data)
         MSVCRT_free(locinfo->lc_time_curr);
@@ -939,14 +956,34 @@ void free_mbcinfo(MSVCRT_pthreadmbcinfo mbcinfo)
  */
 MSVCRT__locale_t CDECL MSVCRT__get_current_locale(void)
 {
+    int i;
     MSVCRT__locale_t loc = MSVCRT_malloc(sizeof(MSVCRT__locale_tstruct));
     if(!loc)
         return NULL;
 
-    loc->locinfo = get_locinfo();
-    loc->mbcinfo = get_mbcinfo();
-    InterlockedIncrement(&loc->locinfo->refcount);
-    InterlockedIncrement(&loc->mbcinfo->refcount);
+    loc->locinfo = MSVCRT_malloc(sizeof(MSVCRT_threadlocinfo));
+    loc->mbcinfo = MSVCRT_malloc(sizeof(MSVCRT_threadmbcinfo));
+    if (!loc->locinfo || !loc->mbcinfo) {
+        MSVCRT_free(loc->locinfo);
+        MSVCRT_free(loc->mbcinfo);
+        MSVCRT_free(loc);
+        return NULL;
+    }
+    memcpy(loc->locinfo, get_locinfo(), sizeof(MSVCRT_threadlocinfo));
+    memcpy(loc->mbcinfo, get_mbcinfo(), sizeof(MSVCRT_threadmbcinfo));
+    loc->locinfo->refcount = 1;
+    loc->mbcinfo->refcount = 1;
+    for(i = 1; i <= (MSVCRT_LC_MAX - MSVCRT_LC_MIN); i++)
+        if(loc->locinfo->lc_category[i].refcount)
+            InterlockedIncrement(loc->locinfo->lc_category[i].refcount);
+    if(loc->locinfo->lconv_intl_refcount)
+        InterlockedIncrement(loc->locinfo->lconv_intl_refcount);
+    if(loc->locinfo->lconv_num_refcount)
+        InterlockedIncrement(loc->locinfo->lconv_num_refcount);
+    if(loc->locinfo->lconv_mon_refcount)
+        InterlockedIncrement(loc->locinfo->lconv_mon_refcount);
+    if(loc->locinfo->ctype1_refcount)
+        InterlockedIncrement(loc->locinfo->ctype1_refcount);
     return loc;
 }
 
@@ -1213,8 +1250,12 @@ static MSVCRT_pthreadlocinfo create_locinfo(int category,
             free_locinfo(locinfo);
             return NULL;
         }
-    } else
-        locinfo->lc_category[MSVCRT_LC_COLLATE].locale = MSVCRT__strdup("C");
+    } else {
+        if(!init_category_name("C", 1, locinfo, MSVCRT_LC_COLLATE)) {
+            free_locinfo(locinfo);
+            return NULL;
+        }
+    }
 
     if(locale_name[MSVCRT_LC_CTYPE] &&
             !init_category_name(locale_name[MSVCRT_LC_CTYPE],
@@ -1291,7 +1332,10 @@ static MSVCRT_pthreadlocinfo create_locinfo(int category,
         locinfo->lc_clike = 1;
         locinfo->mb_cur_max = 1;
         locinfo->pctype = MSVCRT__ctype+1;
-        locinfo->lc_category[MSVCRT_LC_CTYPE].locale = MSVCRT__strdup("C");
+        if(!init_category_name("C", 1, locinfo, MSVCRT_LC_CTYPE)) {
+            free_locinfo(locinfo);
+            return NULL;
+        }
 
         for(i=0; i<256; i++) {
             if(locinfo->pctype[i] & MSVCRT__LEADBYTE)
@@ -1528,6 +1572,16 @@ static MSVCRT_pthreadlocinfo create_locinfo(int category,
             return NULL;
         }
     } else {
+        locinfo->lconv_intl_refcount = MSVCRT_malloc(sizeof(int));
+        locinfo->lconv_mon_refcount = MSVCRT_malloc(sizeof(int));
+        if(!locinfo->lconv_intl_refcount || !locinfo->lconv_mon_refcount) {
+            free_locinfo(locinfo);
+            return NULL;
+        }
+
+        *locinfo->lconv_intl_refcount = 1;
+        *locinfo->lconv_mon_refcount = 1;
+
         locinfo->lconv->int_curr_symbol = MSVCRT_malloc(sizeof(char));
         locinfo->lconv->currency_symbol = MSVCRT_malloc(sizeof(char));
         locinfo->lconv->mon_decimal_point = MSVCRT_malloc(sizeof(char));
@@ -1583,7 +1637,10 @@ static MSVCRT_pthreadlocinfo create_locinfo(int category,
         locinfo->lconv->_W_negative_sign[0] = '\0';
 #endif
 
-        locinfo->lc_category[MSVCRT_LC_MONETARY].locale = MSVCRT__strdup("C");
+        if(!init_category_name("C", 1, locinfo, MSVCRT_LC_MONETARY)) {
+            free_locinfo(locinfo);
+            return NULL;
+        }
     }
 
     if(locale_name[MSVCRT_LC_NUMERIC] &&
@@ -1673,6 +1730,17 @@ static MSVCRT_pthreadlocinfo create_locinfo(int category,
             return NULL;
         }
     } else {
+        if(!locinfo->lconv_intl_refcount)
+            locinfo->lconv_intl_refcount = MSVCRT_malloc(sizeof(int));
+        locinfo->lconv_num_refcount = MSVCRT_malloc(sizeof(int));
+        if(!locinfo->lconv_intl_refcount || !locinfo->lconv_num_refcount) {
+            free_locinfo(locinfo);
+            return NULL;
+        }
+
+        *locinfo->lconv_intl_refcount = 1;
+        *locinfo->lconv_num_refcount = 1;
+
         locinfo->lconv->decimal_point = MSVCRT_malloc(sizeof(char[2]));
         locinfo->lconv->thousands_sep = MSVCRT_malloc(sizeof(char));
         locinfo->lconv->grouping = MSVCRT_malloc(sizeof(char));
@@ -1701,7 +1769,10 @@ static MSVCRT_pthreadlocinfo create_locinfo(int category,
         locinfo->lconv->_W_thousands_sep[0] = '\0';
 #endif
 
-        locinfo->lc_category[MSVCRT_LC_NUMERIC].locale = MSVCRT__strdup("C");
+        if (!init_category_name("C", 1, locinfo, MSVCRT_LC_NUMERIC)) {
+            free_locinfo(locinfo);
+            return NULL;
+        }
     }
 
     if(locale_name[MSVCRT_LC_TIME] &&
@@ -1733,7 +1804,10 @@ static MSVCRT_pthreadlocinfo create_locinfo(int category,
             return NULL;
         }
     } else {
-        locinfo->lc_category[MSVCRT_LC_TIME].locale = MSVCRT__strdup("C");
+        if(!init_category_name("C", 1, locinfo, MSVCRT_LC_TIME)) {
+            free_locinfo(locinfo);
+            return NULL;
+        }
         locinfo->lc_time_curr = &cloc_time_data;
     }
 
-- 
2.24.0




More information about the wine-devel mailing list