[Bf-blender-cvs] [fa0fcbe4d6c] blender2.8: Fix T56374, T57066, T58037: crash on startup on macOS when using translation.

Brecht Van Lommel noreply at git.blender.org
Sat Nov 24 20:08:14 CET 2018


Commit: fa0fcbe4d6ca3f183f02395fe9ba18fb5ea87748
Author: Brecht Van Lommel
Date:   Sat Nov 24 19:21:35 2018 +0100
Branches: blender2.8
https://developer.blender.org/rBfa0fcbe4d6ca3f183f02395fe9ba18fb5ea87748

Fix T56374, T57066, T58037: crash on startup on macOS when using translation.

===================================================================

M	intern/locale/boost_locale_wrapper.cpp
M	source/blender/blenkernel/intern/customdata.c

===================================================================

diff --git a/intern/locale/boost_locale_wrapper.cpp b/intern/locale/boost_locale_wrapper.cpp
index 058b6e9f5d9..36fbcda4874 100644
--- a/intern/locale/boost_locale_wrapper.cpp
+++ b/intern/locale/boost_locale_wrapper.cpp
@@ -35,6 +35,40 @@ static std::string messages_path;
 static std::string default_domain;
 static std::string locale_str;
 
+/* Note: We cannot use short stuff like boost::locale::gettext, because those return
+ * std::basic_string objects, which c_ptr()-returned char* is no more valid
+ * once deleted (which happens as soons they are out of scope of this func). */
+typedef boost::locale::message_format<char> char_message_facet;
+static std::locale locale_global;
+static char_message_facet const *facet_global = NULL;
+
+static void bl_locale_global_cache()
+{
+	/* Cache facet in global variable. Not only is it better for performance,
+	 * it also fixes crashes on macOS when doing translation from threads other
+	 * than main. Likely because of some internal thread local variables. */
+	try {
+		/* facet_global reference is valid as long as local_global exists,
+		 * so we store both. */
+		locale_global = std::locale();
+		facet_global = &std::use_facet<char_message_facet>(locale_global);
+	}
+	catch(const std::bad_cast &e) { /* if std::has_facet<char_message_facet>(l) == false, LC_ALL = "C" case */
+#ifndef NDEBUG
+		std::cout << "bl_locale_global_cache:" << e.what() << " \n";
+#endif
+		(void)e;
+		facet_global = NULL;
+	}
+	catch(const std::exception &e) {
+#ifndef NDEBUG
+		std::cout << "bl_locale_global_cache:" << e.what() << " \n";
+#endif
+		(void)e;
+		facet_global = NULL;
+	}
+}
+
 void bl_locale_init(const char *_messages_path, const char *_default_domain)
 {
 	// Avoid using ICU backend, we do not need its power and it's rather heavy!
@@ -74,6 +108,8 @@ void bl_locale_set(const char *locale)
 		std::locale::global(_locale);
 		// Note: boost always uses "C" LC_NUMERIC by default!
 
+		bl_locale_global_cache();
+
 		// Generate the locale string (useful to know which locale we are actually using in case of "default" one).
 #define LOCALE_INFO std::use_facet<boost::locale::info>(_locale)
 
@@ -100,30 +136,12 @@ const char *bl_locale_get(void)
 
 const char *bl_locale_pgettext(const char *msgctxt, const char *msgid)
 {
-	// Note: We cannot use short stuff like boost::locale::gettext, because those return
-	//       std::basic_string objects, which c_ptr()-returned char* is no more valid
-	//       once deleted (which happens as soons they are out of scope of this func).
-	typedef boost::locale::message_format<char> char_message_facet;
-	try {
-		std::locale l;
-		char_message_facet const &facet = std::use_facet<char_message_facet>(l);
-		char const *r = facet.get(0, msgctxt, msgid);
-		if (r)
+	if (facet_global) {
+		char const *r = facet_global->get(0, msgctxt, msgid);
+		if (r) {
 			return r;
-		return msgid;
-	}
-	catch(const std::bad_cast &e) { /* if std::has_facet<char_message_facet>(l) == false, LC_ALL = "C" case */
-#ifndef NDEBUG
-		std::cout << "bl_locale_pgettext(" << msgctxt << ", " << msgid << "): " << e.what() << " \n";
-#endif
-		(void)e;
-		return msgid;
-	}
-	catch(const std::exception &e) {
-#ifndef NDEBUG
-		std::cout << "bl_locale_pgettext(" << msgctxt << ", " << msgid << "): " << e.what() << " \n";
-#endif
-		(void)e;
-		return msgid;
+		}
 	}
+
+	return msgid;
 }
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index a0fa08708b1..e841832f51c 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -1874,7 +1874,14 @@ static CustomDataLayer *customData_add_layer__internal(
 	data->layers[index].flag = flag;
 	data->layers[index].data = newlayerdata;
 
-	if (name || (name = DATA_(typeInfo->defaultname))) {
+	/* Set default name if none exists. Note we only call DATA_()  once
+	 * we know there is a default name, to avoid overhead of locale lookups
+	 * in the depsgraph. */
+	if (!name && typeInfo->defaultname) {
+		name = DATA_(typeInfo->defaultname);
+	}
+
+	if (name) {
 		BLI_strncpy(data->layers[index].name, name, sizeof(data->layers[index].name));
 		CustomData_set_layer_unique_name(data, index);
 	}
@@ -3440,11 +3447,17 @@ void CustomData_set_layer_unique_name(CustomData *data, int index)
 	data_arg.type = nlayer->type;
 	data_arg.index = index;
 
-	if (!typeInfo->defaultname)
+	if (!typeInfo->defaultname) {
 		return;
+	}
+
+	/* Set default name if none specified. Note we only call DATA_() when
+	 * needed to avoid overhead of locale lookups in the depsgraph. */
+	if (nlayer->name[0] == '\0') {
+		STRNCPY(nlayer->name, DATA_(typeInfo->defaultname));
+	}
 
-	BLI_uniquename_cb(customdata_unique_check, &data_arg, DATA_(typeInfo->defaultname), '.', nlayer->name,
-	                  sizeof(nlayer->name));
+	BLI_uniquename_cb(customdata_unique_check, &data_arg, NULL, '.', nlayer->name, sizeof(nlayer->name));
 }
 
 void CustomData_validate_layer_name(const CustomData *data, int type, const char *name, char *outname)



More information about the Bf-blender-cvs mailing list