⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 243289 in webkit


Ignore:
Timestamp:
Mar 21, 2019, 7:36:12 AM (7 years ago)
Author:
commit-queue@webkit.org
Message:

[GLIB] User data not correctly passed to callback of functions and constructors with no parameters
https://bugs.webkit.org/show_bug.cgi?id=196073

Patch by Carlos Garcia Campos <cgarcia@igalia.com> on 2019-03-21
Reviewed by Michael Catanzaro.

Source/JavaScriptCore:

This is because GClosure always expects a first parameter as instance. In case of functions or constructors with
no parameters we insert a fake instance which is just a null pointer that is ignored by the callback. But
if the function/constructor has user data the callback will expect one parameter for the user data. In that case
we can simply swap instance/user data so that the fake instance will be the second argument and user data the
first one.

  • API/glib/JSCClass.cpp:

(jscClassCreateConstructor): Use g_cclosure_new_swap() if parameters is empty and user data was provided.

  • API/glib/JSCValue.cpp:

(jscValueFunctionCreate): Ditto.

Tools:

Add test cases to check functions and constructors with no arguments but receiving user data.

  • TestWebKitAPI/Tests/JavaScriptCore/glib/TestJSC.cpp:

(checkUserData):
(testJSCFunction):
(fooCreateWithUserData):
(testJSCClass):

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/API/glib/JSCClass.cpp

    r243283 r243289  
    555555static GRefPtr<JSCValue> jscClassCreateConstructor(JSCClass* jscClass, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, Optional<Vector<GType>>&& parameters)
    556556{
     557    // If the constructor doesn't have arguments, we need to swap the fake instance and user data to ensure
     558    // user data is the first parameter and fake instance ignored.
     559    GRefPtr<GClosure> closure;
     560    if (parameters && parameters->isEmpty() && userData)
     561        closure = adoptGRef(g_cclosure_new_swap(callback, userData, reinterpret_cast<GClosureNotify>(reinterpret_cast<GCallback>(destroyNotify))));
     562    else
     563        closure = adoptGRef(g_cclosure_new(callback, userData, reinterpret_cast<GClosureNotify>(reinterpret_cast<GCallback>(destroyNotify))));
    557564    JSCClassPrivate* priv = jscClass->priv;
    558     GRefPtr<GClosure> closure = adoptGRef(g_cclosure_new(callback, userData, reinterpret_cast<GClosureNotify>(reinterpret_cast<GCallback>(destroyNotify))));
    559565    JSC::ExecState* exec = toJS(jscContextGetJSContext(priv->context));
    560566    JSC::VM& vm = exec->vm();
  • trunk/Source/JavaScriptCore/API/glib/JSCValue.cpp

    r243283 r243289  
    11411141static GRefPtr<JSCValue> jscValueFunctionCreate(JSCContext* context, const char* name, GCallback callback, gpointer userData, GDestroyNotify destroyNotify, GType returnType, Optional<Vector<GType>>&& parameters)
    11421142{
    1143     GRefPtr<GClosure> closure = adoptGRef(g_cclosure_new(callback, userData, reinterpret_cast<GClosureNotify>(reinterpret_cast<GCallback>(destroyNotify))));
     1143    GRefPtr<GClosure> closure;
     1144    // If the function doesn't have arguments, we need to swap the fake instance and user data to ensure
     1145    // user data is the first parameter and fake instance ignored.
     1146    if (parameters && parameters->isEmpty() && userData)
     1147        closure = adoptGRef(g_cclosure_new_swap(callback, userData, reinterpret_cast<GClosureNotify>(reinterpret_cast<GCallback>(destroyNotify))));
     1148    else
     1149        closure = adoptGRef(g_cclosure_new(callback, userData, reinterpret_cast<GClosureNotify>(reinterpret_cast<GCallback>(destroyNotify))));
    11441150    JSC::ExecState* exec = toJS(jscContextGetJSContext(context));
    11451151    JSC::VM& vm = exec->vm();
  • trunk/Source/JavaScriptCore/ChangeLog

    r243286 r243289  
     12019-03-21  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        [GLIB] User data not correctly passed to callback of functions and constructors with no parameters
     4        https://bugs.webkit.org/show_bug.cgi?id=196073
     5
     6        Reviewed by Michael Catanzaro.
     7
     8        This is because GClosure always expects a first parameter as instance. In case of functions or constructors with
     9        no parameters we insert a fake instance which is just a null pointer that is ignored by the callback. But
     10        if the function/constructor has user data the callback will expect one parameter for the user data. In that case
     11        we can simply swap instance/user data so that the fake instance will be the second argument and user data the
     12        first one.
     13
     14        * API/glib/JSCClass.cpp:
     15        (jscClassCreateConstructor): Use g_cclosure_new_swap() if parameters is empty and user data was provided.
     16        * API/glib/JSCValue.cpp:
     17        (jscValueFunctionCreate): Ditto.
     18
    1192019-03-21  Pablo Saavedra  <psaavedra@igalia.com>
    220
  • trunk/Tools/ChangeLog

    r243288 r243289  
     12019-03-21  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        [GLIB] User data not correctly passed to callback of functions and constructors with no parameters
     4        https://bugs.webkit.org/show_bug.cgi?id=196073
     5
     6        Reviewed by Michael Catanzaro.
     7
     8        Add test cases to check functions and constructors with no arguments but receiving user data.
     9
     10        * TestWebKitAPI/Tests/JavaScriptCore/glib/TestJSC.cpp:
     11        (checkUserData):
     12        (testJSCFunction):
     13        (fooCreateWithUserData):
     14        (testJSCClass):
     15
    1162019-03-21  Carlos Garcia Campos  <cgarcia@igalia.com>
    217
  • trunk/Tools/TestWebKitAPI/Tests/JavaScriptCore/glib/TestJSC.cpp

    r243283 r243289  
    848848}
    849849
     850static gboolean checkUserData(GFile* file)
     851{
     852    return G_IS_FILE(file);
     853}
     854
    850855static void testJSCFunction()
    851856{
     
    10931098        g_assert_cmpint(jsc_value_to_int32(value.get()), ==, 0);
    10941099    }
     1100
     1101    {
     1102        LeakChecker checker;
     1103        GRefPtr<JSCContext> context = adoptGRef(jsc_context_new());
     1104        checker.watch(context.get());
     1105        ExceptionHandler exceptionHandler(context.get());
     1106
     1107        GFile* file = g_file_new_for_path(".");
     1108        checker.watch(file);
     1109        GRefPtr<JSCValue> function = adoptGRef(jsc_value_new_function(context.get(), "checkUserData", G_CALLBACK(checkUserData),
     1110            file, g_object_unref, G_TYPE_BOOLEAN, 0, G_TYPE_NONE));
     1111        checker.watch(function.get());
     1112        jsc_context_set_value(context.get(), "checkUserData", function.get());
     1113
     1114        GRefPtr<JSCValue> value = adoptGRef(jsc_context_evaluate(context.get(), "checkUserData()", -1));
     1115        checker.watch(value.get());
     1116        g_assert_true(jsc_value_is_boolean(value.get()));
     1117        g_assert_true(jsc_value_to_boolean(value.get()));
     1118
     1119        value = adoptGRef(jsc_value_function_call(function.get(), G_TYPE_NONE));
     1120        checker.watch(value.get());
     1121        g_assert_true(jsc_value_is_boolean(value.get()));
     1122        g_assert_true(jsc_value_to_boolean(value.get()));
     1123    }
    10951124}
    10961125
     
    13961425    }, f);
    13971426    return f;
     1427}
     1428
     1429static Foo* fooCreateWithUserData(GFile* file)
     1430{
     1431    g_assert_true(G_IS_FILE(file));
     1432    return fooCreate();
    13981433}
    13991434
     
    17991834        g_assert_true(jsc_value_is_number(value.get()));
    18001835        g_assert_cmpint(jsc_value_to_int32(value.get()), ==, 0);
     1836
     1837        GFile* file = g_file_new_for_path(".");
     1838        checker.watch(file);
     1839        GRefPtr<JSCValue> constructorUserData = adoptGRef(jsc_class_add_constructor(jscClass, "CreateWithUserData", G_CALLBACK(fooCreateWithUserData),
     1840            file, g_object_unref, G_TYPE_POINTER, 0, G_TYPE_NONE));
     1841        checker.watch(constructorUserData.get());
     1842        g_assert_true(jsc_value_is_constructor(constructorUserData.get()));
     1843        jsc_value_object_set_property(constructor.get(), "CreateWithUserData", constructorUserData.get());
     1844
     1845        GRefPtr<JSCValue> foo5 = adoptGRef(jsc_context_evaluate(context.get(), "f5 = new Foo.CreateWithUserData();", -1));
     1846        checker.watch(foo5.get());
     1847        g_assert_true(jsc_value_is_object(foo5.get()));
     1848        g_assert_true(jsc_value_object_is_instance_of(foo5.get(), jsc_class_get_name(jscClass)));
    18011849
    18021850        JSCClass* otherClass = jsc_context_register_class(context.get(), "Baz", nullptr, nullptr, g_free);
Note: See TracChangeset for help on using the changeset viewer.