Fix crashes in swig_connect_director during director class construction.
Occurs when using the director class from multiple threads - a race condition initialising block scope static variables. Block scope static variables are guaranteed to be thread safe in C++11, so the fix is guaranteed when using C++11. However, most modern compilers also fix it when using C++03/C++98. Closes #1862
This commit is contained in:
parent
70e78d4125
commit
b018c32f9d
3 changed files with 30 additions and 21 deletions
|
|
@ -7,6 +7,12 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
|
||||||
Version 4.1.0 (in progress)
|
Version 4.1.0 (in progress)
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
|
2020-08-28: wsfulton
|
||||||
|
[Java] #1862 Fix crashes in swig_connect_director during director class construction
|
||||||
|
when using the director class from multiple threads - a race condition initialising
|
||||||
|
block scope static variables. The fix is guaranteed when using C++11, but most
|
||||||
|
compilers also fix it when using C++03/C++98.
|
||||||
|
|
||||||
2020-08-16: wsfulton
|
2020-08-16: wsfulton
|
||||||
[Python] Add missing initializer for member ‘_heaptypeobject::ht_module’ when using
|
[Python] Add missing initializer for member ‘_heaptypeobject::ht_module’ when using
|
||||||
-builtin to complete Python 3.9 support.
|
-builtin to complete Python 3.9 support.
|
||||||
|
|
|
||||||
|
|
@ -215,6 +215,15 @@ namespace Swig {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SwigDirectorMethod {
|
||||||
|
const char *name;
|
||||||
|
const char *desc;
|
||||||
|
jmethodID methid;
|
||||||
|
SwigDirectorMethod(JNIEnv *jenv, jclass baseclass, const char *name, const char *desc) : name(name), desc(desc) {
|
||||||
|
methid = jenv->GetMethodID(baseclass, name, desc);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/* Java object wrapper */
|
/* Java object wrapper */
|
||||||
JObjectWrapper swig_self_;
|
JObjectWrapper swig_self_;
|
||||||
|
|
||||||
|
|
@ -238,6 +247,11 @@ namespace Swig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jclass swig_new_global_ref(JNIEnv *jenv, const char *classname) {
|
||||||
|
jclass clz = jenv->FindClass(classname);
|
||||||
|
return clz ? (jclass)jenv->NewGlobalRef(clz) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Director(JNIEnv *jenv) : swig_jvm_((JavaVM *) NULL), swig_self_() {
|
Director(JNIEnv *jenv) : swig_jvm_((JavaVM *) NULL), swig_self_() {
|
||||||
/* Acquire the Java VM pointer */
|
/* Acquire the Java VM pointer */
|
||||||
|
|
|
||||||
|
|
@ -4835,34 +4835,27 @@ public:
|
||||||
// .'s to delimit namespaces, so we need to replace those with /'s
|
// .'s to delimit namespaces, so we need to replace those with /'s
|
||||||
Replace(internal_classname, NSPACE_SEPARATOR, "/", DOH_REPLACE_ANY);
|
Replace(internal_classname, NSPACE_SEPARATOR, "/", DOH_REPLACE_ANY);
|
||||||
|
|
||||||
Wrapper_add_localv(w, "baseclass", "static jclass baseclass", "= 0", NIL);
|
|
||||||
Printf(w->def, "void %s::swig_connect_director(JNIEnv *jenv, jobject jself, jclass jcls, bool swig_mem_own, bool weak_global) {", director_classname);
|
Printf(w->def, "void %s::swig_connect_director(JNIEnv *jenv, jobject jself, jclass jcls, bool swig_mem_own, bool weak_global) {", director_classname);
|
||||||
|
|
||||||
|
Printf(w->def, "static jclass baseclass = swig_new_global_ref(jenv, \"%s\");\n", internal_classname);
|
||||||
|
Printf(w->def, "if (!baseclass) return;\n");
|
||||||
|
|
||||||
if (first_class_dmethod != curr_class_dmethod) {
|
if (first_class_dmethod != curr_class_dmethod) {
|
||||||
Printf(w->def, "static struct {\n");
|
Printf(w->def, "static SwigDirectorMethod methods[] = {\n");
|
||||||
Printf(w->def, "const char *mname;\n");
|
|
||||||
Printf(w->def, "const char *mdesc;\n");
|
|
||||||
Printf(w->def, "jmethodID base_methid;\n");
|
|
||||||
Printf(w->def, "} methods[] = {\n");
|
|
||||||
|
|
||||||
for (int i = first_class_dmethod; i < curr_class_dmethod; ++i) {
|
for (int i = first_class_dmethod; i < curr_class_dmethod; ++i) {
|
||||||
UpcallData *udata = Getitem(dmethods_seq, i);
|
UpcallData *udata = Getitem(dmethods_seq, i);
|
||||||
|
|
||||||
Printf(w->def, "{ \"%s\", \"%s\", NULL }", Getattr(udata, "method"), Getattr(udata, "fdesc"));
|
Printf(w->def, "SwigDirectorMethod(jenv, baseclass, \"%s\", \"%s\")", Getattr(udata, "method"), Getattr(udata, "fdesc"));
|
||||||
if (i != curr_class_dmethod - 1)
|
if (i != curr_class_dmethod - 1)
|
||||||
Putc(',', w->def);
|
Putc(',', w->def);
|
||||||
Putc('\n', w->def);
|
Putc('\n', w->def);
|
||||||
}
|
}
|
||||||
|
|
||||||
Printf(w->def, "};\n");
|
Printf(w->def, "};");
|
||||||
}
|
}
|
||||||
|
|
||||||
Printf(w->code, "if (swig_set_self(jenv, jself, swig_mem_own, weak_global)) {\n");
|
Printf(w->code, "if (swig_set_self(jenv, jself, swig_mem_own, weak_global)) {\n");
|
||||||
Printf(w->code, "if (!baseclass) {\n");
|
|
||||||
Printf(w->code, "baseclass = jenv->FindClass(\"%s\");\n", internal_classname);
|
|
||||||
Printf(w->code, "if (!baseclass) return;\n");
|
|
||||||
Printf(w->code, "baseclass = (jclass) jenv->NewGlobalRef(baseclass);\n");
|
|
||||||
Printf(w->code, "}\n");
|
|
||||||
|
|
||||||
int n_methods = curr_class_dmethod - first_class_dmethod;
|
int n_methods = curr_class_dmethod - first_class_dmethod;
|
||||||
|
|
||||||
|
|
@ -4877,12 +4870,8 @@ public:
|
||||||
|
|
||||||
/* Emit the code to look up the class's methods, initialize the override array */
|
/* Emit the code to look up the class's methods, initialize the override array */
|
||||||
|
|
||||||
Printf(w->code, "bool derived = (jenv->IsSameObject(baseclass, jcls) ? false : true);\n");
|
Printf(w->code, " bool derived = (jenv->IsSameObject(baseclass, jcls) ? false : true);\n");
|
||||||
Printf(w->code, "for (int i = 0; i < %d; ++i) {\n", n_methods);
|
Printf(w->code, " for (int i = 0; i < %d; ++i) {\n", n_methods);
|
||||||
Printf(w->code, " if (!methods[i].base_methid) {\n");
|
|
||||||
Printf(w->code, " methods[i].base_methid = jenv->GetMethodID(baseclass, methods[i].mname, methods[i].mdesc);\n");
|
|
||||||
Printf(w->code, " if (!methods[i].base_methid) return;\n");
|
|
||||||
Printf(w->code, " }\n");
|
|
||||||
// Generally, derived classes have a mix of overridden and
|
// Generally, derived classes have a mix of overridden and
|
||||||
// non-overridden methods and it is worth making a GetMethodID
|
// non-overridden methods and it is worth making a GetMethodID
|
||||||
// check during initialization to determine if each method is
|
// check during initialization to determine if each method is
|
||||||
|
|
@ -4902,8 +4891,8 @@ public:
|
||||||
} else {
|
} else {
|
||||||
Printf(w->code, " swig_override[i] = false;\n");
|
Printf(w->code, " swig_override[i] = false;\n");
|
||||||
Printf(w->code, " if (derived) {\n");
|
Printf(w->code, " if (derived) {\n");
|
||||||
Printf(w->code, " jmethodID methid = jenv->GetMethodID(jcls, methods[i].mname, methods[i].mdesc);\n");
|
Printf(w->code, " jmethodID methid = jenv->GetMethodID(jcls, methods[i].name, methods[i].desc);\n");
|
||||||
Printf(w->code, " swig_override[i] = (methid != methods[i].base_methid);\n");
|
Printf(w->code, " swig_override[i] = methods[i].methid && (methid != methods[i].methid);\n");
|
||||||
Printf(w->code, " jenv->ExceptionClear();\n");
|
Printf(w->code, " jenv->ExceptionClear();\n");
|
||||||
Printf(w->code, " }\n");
|
Printf(w->code, " }\n");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue