Changeset 218316 in webkit


Ignore:
Timestamp:
Jun 14, 2017 10:57:27 PM (7 years ago)
Author:
mitz@apple.com
Message:

[Cocoa] Objective-C class whose name begins with an underscore can’t be exported to JavaScript
https://bugs.webkit.org/show_bug.cgi?id=168578

Reviewed by Geoff Garen.

  • API/JSWrapperMap.mm:

(allocateConstructorForCustomClass): Updated for change to forEachProtocolImplementingProtocol.
(-[JSObjCClassInfo allocateConstructorAndPrototype]): Ditto.
(-[JSWrapperMap classInfoForClass:]): If the class name begins with an underscore, check if

it defines conformance to a JSExport-derived protocol and if so, avoid using the
superclass as a substitute as we’d normally do.

  • API/ObjcRuntimeExtras.h:

(forEachProtocolImplementingProtocol): Added a "stop" argument to the block to let callers

bail out.

  • API/tests/JSExportTests.mm:

(+[JSExportTests classNamePrefixedWithUnderscoreTest]): New test for this.
(runJSExportTests): Run new test.

Location:
trunk/Source/JavaScriptCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/API/JSWrapperMap.mm

    r217240 r218316  
    11/*
    2  * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
     2 * Copyright (C) 2013-2015, 2017 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    413413    Protocol *exportProtocol = getJSExportProtocol();
    414414    for (Class currentClass = cls; currentClass; currentClass = class_getSuperclass(currentClass)) {
    415         forEachProtocolImplementingProtocol(currentClass, exportProtocol, ^(Protocol *protocol) {
     415        forEachProtocolImplementingProtocol(currentClass, exportProtocol, ^(Protocol *protocol, bool&) {
    416416            forEachMethodInProtocol(protocol, YES, YES, ^(SEL selector, const char*) {
    417417                const char* name = sel_getName(selector);
     
    491491
    492492        Protocol *exportProtocol = getJSExportProtocol();
    493         forEachProtocolImplementingProtocol(m_class, exportProtocol, ^(Protocol *protocol){
     493        forEachProtocolImplementingProtocol(m_class, exportProtocol, ^(Protocol *protocol, bool&){
    494494            copyPrototypeProperties(context, m_class, protocol, prototype);
    495495            copyMethodsToObject(context, m_class, protocol, NO, constructor);
     
    588588
    589589    // Skip internal classes beginning with '_' - just copy link to the parent class's info.
    590     if ('_' == *class_getName(cls))
    591         return m_classMap[cls] = [self classInfoForClass:class_getSuperclass(cls)];
     590    if ('_' == *class_getName(cls)) {
     591        bool conformsToExportProtocol = false;
     592        forEachProtocolImplementingProtocol(cls, getJSExportProtocol(), [&conformsToExportProtocol](Protocol *, bool& stop) {
     593            conformsToExportProtocol = true;
     594            stop = true;
     595        });
     596
     597        if (!conformsToExportProtocol)
     598            return m_classMap[cls] = [self classInfoForClass:class_getSuperclass(cls)];
     599    }
    592600
    593601    return m_classMap[cls] = [[[JSObjCClassInfo alloc] initForClass:cls] autorelease];
  • trunk/Source/JavaScriptCore/API/ObjcRuntimeExtras.h

    r185122 r218316  
    11/*
    2  * Copyright (C) 2013 Apple Inc. All rights reserved.
     2 * Copyright (C) 2013, 2017 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    4343}
    4444
    45 inline void forEachProtocolImplementingProtocol(Class cls, Protocol *target, void (^callback)(Protocol *))
     45inline void forEachProtocolImplementingProtocol(Class cls, Protocol *target, void (^callback)(Protocol *, bool& stop))
    4646{
    4747    ASSERT(cls);
     
    5757    free(protocols);
    5858
     59    bool stop = false;
    5960    while (!worklist.isEmpty()) {
    6061        Protocol *protocol = worklist.last();
     
    6667
    6768        // If it implements the protocol, make the callback.
    68         if (protocolImplementsProtocol(protocol, target))
    69             callback(protocol);
     69        if (protocolImplementsProtocol(protocol, target)) {
     70            callback(protocol, stop);
     71            if (stop)
     72                break;
     73        }
    7074
    7175        // Add incorporated protocols to the worklist.
  • trunk/Source/JavaScriptCore/API/tests/JSExportTests.mm

    r217517 r218316  
    11/*
    2  * Copyright (C) 2014 Apple Inc. All rights reserved.
     2 * Copyright (C) 2014, 2017 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    8181@end
    8282
     83@interface NoUnderscorePrefix : NSObject
     84@end
     85
     86@implementation NoUnderscorePrefix
     87@end
     88
     89@interface _UnderscorePrefixNoExport : NoUnderscorePrefix
     90@end
     91
     92@implementation _UnderscorePrefixNoExport
     93@end
     94
     95@protocol Initializing <JSExport>
     96- (instancetype)init;
     97@end
     98
     99@interface _UnderscorePrefixWithExport : NoUnderscorePrefix <Initializing>
     100@end
     101
     102@implementation _UnderscorePrefixWithExport
     103@end
     104
    83105@implementation JSExportTests
    84106+ (void) exportInstanceMethodWithIdProtocolTest
     
    124146    checkResult(@"Dynamically generated JSExport-ed protocols are ignored", [value isUndefined] && !!context.exception);
    125147}
     148
     149+ (void)classNamePrefixedWithUnderscoreTest
     150{
     151    JSContext *context = [[JSContext alloc] init];
     152
     153    context[@"_UnderscorePrefixNoExport"] = [_UnderscorePrefixNoExport class];
     154    context[@"_UnderscorePrefixWithExport"] = [_UnderscorePrefixWithExport class];
     155
     156    checkResult(@"Non-underscore-prefixed ancestor class used when there are no exports", [context[@"_UnderscorePrefixNoExport"] toObject] == [NoUnderscorePrefix class]);
     157    checkResult(@"Underscore-prefixed class used when there are exports", [context[@"_UnderscorePrefixWithExport"] toObject] == [_UnderscorePrefixWithExport class]);
     158
     159    JSValue *withExportInstance = [context evaluateScript:@"new _UnderscorePrefixWithExport()"];
     160    checkResult(@"Exports present on underscore-prefixed class", !context.exception && !withExportInstance.isUndefined);
     161}
     162
    126163@end
    127164
     
    172209        [JSExportTests exportInstanceMethodWithClassProtocolTest];
    173210        [JSExportTests exportDynamicallyGeneratedProtocolTest];
     211        [JSExportTests classNamePrefixedWithUnderscoreTest];
    174212    }
    175213    wrapperLifetimeIsTiedToGlobalObject();
  • trunk/Source/JavaScriptCore/ChangeLog

    r218312 r218316  
     12017-06-14  Dan Bernstein  <mitz@apple.com>
     2
     3        [Cocoa] Objective-C class whose name begins with an underscore can’t be exported to JavaScript
     4        https://bugs.webkit.org/show_bug.cgi?id=168578
     5
     6        Reviewed by Geoff Garen.
     7
     8        * API/JSWrapperMap.mm:
     9        (allocateConstructorForCustomClass): Updated for change to forEachProtocolImplementingProtocol.
     10        (-[JSObjCClassInfo allocateConstructorAndPrototype]): Ditto.
     11        (-[JSWrapperMap classInfoForClass:]): If the class name begins with an underscore, check if
     12          it defines conformance to a JSExport-derived protocol and if so, avoid using the
     13          superclass as a substitute as we’d normally do.
     14
     15        * API/ObjcRuntimeExtras.h:
     16        (forEachProtocolImplementingProtocol): Added a "stop" argument to the block to let callers
     17          bail out.
     18
     19        * API/tests/JSExportTests.mm:
     20        (+[JSExportTests classNamePrefixedWithUnderscoreTest]): New test for this.
     21        (runJSExportTests): Run new test.
     22
    1232017-06-14  Yusuke Suzuki  <utatane.tea@gmail.com>
    224
Note: See TracChangeset for help on using the changeset viewer.