Tcl Source Code

Artifact [dd247811e9]
Login

Artifact dd247811e9f1c6cdbc811787596f3772598ece2b5a2793083769ecde2fc6f9a4:

Attachment "tcl9.1.0-locale-init-lock.patch" to ticket [c35e347c6f] added by gustafn3 2026-10-07 09:22:20.
--- a/unix/tclUnixInit.c
+++ b/unix/tclUnixInit.c
@@ -584,25 +584,43 @@
      */
 
 #ifdef HAVE_LANGINFO
-    if (
+    {
+	Tcl_DString ds;
+	int haveLocale;
+
+	Tcl_DStringInit(&ds);
+
+	/*
+	 * setlocale() changes process-global state and need not be thread-safe.
+	 * Use the initialization lock, which also protects the initial locale
+	 * setup in Tcl_InitSubsystems(). Copy the codeset while holding the
+	 * lock, since nl_langinfo() can return storage owned by libc.
+	 */
+
+	TclpInitLock();
+	haveLocale =
 #ifdef WEAK_IMPORT_NL_LANGINFO
-	    nl_langinfo != NULL &&
+		nl_langinfo != NULL &&
 #endif
-	    setlocale(LC_CTYPE, "") != NULL) {
-	Tcl_DString ds;
+		setlocale(LC_CTYPE, "") != NULL;
+	if (haveLocale) {
+	    Tcl_DStringAppend(&ds, nl_langinfo(CODESET), TCL_INDEX_NONE);
+	}
+	TclpInitUnlock();
 
 	/*
-	 * Use a DString so we can modify case.
+	 * Resolve the copied encoding name after releasing the locale lock.
 	 */
 
-	Tcl_DStringInit(&ds);
-	encoding = Tcl_DStringAppend(&ds, nl_langinfo(CODESET), TCL_INDEX_NONE);
-	Tcl_UtfToLower(Tcl_DStringValue(&ds));
-	knownEncoding = SearchKnownEncodings(encoding);
-	if (knownEncoding != NULL) {
-	    Tcl_DStringAppend(bufPtr, knownEncoding, TCL_INDEX_NONE);
-	} else if (NULL != Tcl_GetEncoding(NULL, encoding)) {
-	    Tcl_DStringAppend(bufPtr, encoding, TCL_INDEX_NONE);
+	if (haveLocale) {
+	    encoding = Tcl_DStringValue(&ds);
+	    Tcl_UtfToLower(Tcl_DStringValue(&ds));
+	    knownEncoding = SearchKnownEncodings(encoding);
+	    if (knownEncoding != NULL) {
+		Tcl_DStringAppend(bufPtr, knownEncoding, TCL_INDEX_NONE);
+	    } else if (NULL != Tcl_GetEncoding(NULL, encoding)) {
+		Tcl_DStringAppend(bufPtr, encoding, TCL_INDEX_NONE);
+	    }
 	}
 	Tcl_DStringFree(&ds);
 	if (Tcl_DStringLength(bufPtr)) {