Bug 1444571 - Prevent IIIM module from being unloaded with grabbing GtkIMContextIIIM class with static variable r=karlt

IIIMF is really old IME framework.  In these days, it's not used as default IM
module of any major distributions.  However, ATOK X which is old proprietary
IME requires IIIMF and it's still used by some Japanese IME users.  Therefore,
we need to take back the hack to prevent crash caused by IIIMF.

We did increment refcount of GtkIMContextIIIM class to prevent IIIM module
from being unloaded.  However, it was not ported when we changed default
toolkit from GTK2 to GTK3.  So, this is doing the porting.

Unfortunately, the instance of GtkIMContextIIIM is wrapped by opacity struct.
So, it's not safe to access the pointer with declaring a mimic struct.
Therefore, we should directly get GType from the name with calling
g_type_from_name("GtkIMContextIIIM") instead of using G_TYPE_FROM_INSTANCE()
and g_type_name().

MozReview-Commit-ID: GCZaSUtPiS9

--HG--
extra : rebase_source : 3b959023bf47fa26393fc04e722c9da79a50991d
This commit is contained in:
Masayuki Nakano 2018-03-12 22:32:43 +09:00
Родитель e3b03845cc
Коммит 7744988cce
1 изменённых файлов: 30 добавлений и 31 удалений

Просмотреть файл

@ -584,40 +584,39 @@ IMContextWrapper::OnDestroyWindow(nsWindow* aWindow)
this)); this));
} }
// Work around gtk bug http://bugzilla.gnome.org/show_bug.cgi?id=483223:
// (and the similar issue of GTK+ IIIM)
// The GTK+ XIM and IIIM modules register handlers for the "closed" signal
// on the display, but:
// * The signal handlers are not disconnected when the module is unloaded.
//
// The GTK+ XIM module has another problem:
// * When the signal handler is run (with the module loaded) it tries
// XFree (and fails) on a pointer that did not come from Xmalloc.
//
// To prevent these modules from being unloaded, use static variables to
// hold ref of GtkIMContext class.
// For GTK+ XIM module, to prevent the signal handler from being run,
// find the signal handlers and remove them.
//
// GtkIMContextXIMs share XOpenIM connections and display closed signal
// handlers (where possible).
void void
IMContextWrapper::PrepareToDestroyContext(GtkIMContext* aContext) IMContextWrapper::PrepareToDestroyContext(GtkIMContext* aContext)
{ {
GtkIMContext *slave = nullptr; //TODO GTK3 if (mIMContextID == IMContextID::eIIIMF) {
if (!slave) { // IIIM module registers handlers for the "closed" signal on the
return; // display, but the signal handler is not disconnected when the module
} // is unloaded. To prevent the module from being unloaded, use static
// variable to hold reference of slave context class declared by IIIM.
GType slaveType = G_TYPE_FROM_INSTANCE(slave); // Note that this does not grab any instance, it grabs the "class".
const gchar *im_type_name = g_type_name(slaveType); static gpointer sGtkIIIMContextClass = nullptr;
if (strcmp(im_type_name, "GtkIMContextIIIM") == 0) { if (!sGtkIIIMContextClass) {
// Add a reference to prevent the IIIM module from being unloaded // We retrieved slave context class with g_type_name() and actual
static gpointer gtk_iiim_context_class = // slave context instance when our widget was GTK2. That must be
g_type_class_ref(slaveType); // _GtkIMContext::priv::slave in GTK3. However, _GtkIMContext::priv
// Mute unused variable warning: // is an opacity struct named _GtkIMMulticontextPrivate, i.e., it's
(void)gtk_iiim_context_class; // not exposed by GTK3. Therefore, we cannot access the instance
// safely. So, we need to retrieve the slave context class with
// g_type_from_name("GtkIMContextIIIM") directly (anyway, we needed
// to compare the class name with "GtkIMContextIIIM").
GType IIMContextType = g_type_from_name("GtkIMContextIIIM");
if (IIMContextType) {
sGtkIIIMContextClass = g_type_class_ref(IIMContextType);
MOZ_LOG(gGtkIMLog, LogLevel::Info,
("0x%p PrepareToDestroyContext(), added to reference to "
"GtkIMContextIIIM class to prevent it from being unloaded",
this));
} else {
MOZ_LOG(gGtkIMLog, LogLevel::Error,
("0x%p PrepareToDestroyContext(), FAILED to prevent the "
"IIIM module from being uploaded",
this));
}
}
} }
} }