Changeset 204245 in webkit


Ignore:
Timestamp:
Aug 7, 2016, 1:50:43 PM (10 years ago)
Author:
mitz@apple.com
Message:

[Cocoa] Reply block leaks if the remote object doesn’t call it
https://bugs.webkit.org/show_bug.cgi?id=160642

Reviewed by Sam Weinig.

Source/WebKit2:

  • Shared/API/Cocoa/RemoteObjectRegistry.h: Declared new member functions.
  • Shared/API/Cocoa/RemoteObjectRegistry.messages.in: Added ReleaseUnusedReplyBlock message.
  • Shared/API/Cocoa/RemoteObjectRegistry.mm:

(WebKit::RemoteObjectRegistry::sendUnusedReply): Send the ReleaseUnusedReplyBlock message.
(WebKit::RemoteObjectRegistry::releaseUnusedReplyBlock): Message receiver that call through

to -_releaseReplyWithID:.

  • Shared/API/Cocoa/_WKRemoteObjectRegistry.mm:

(-[_WKRemoteObjectRegistry _invokeMethod:]): Define a ReplyBlockCallChecker object and

capture an instance of it in the reply block we pass to the exported object. Have that
block set a flag on the checker when it’s called. If the checker gets destroyed without
the block having been called, which means that the block got destroyed without being
called, call sendUnusedReply to let the other side know that the block will not be invoked.

(-[_WKRemoteObjectRegistry _releaseReplyWithID:]): Added. Removed the pending reply from the

map, which release the block.

  • Shared/API/Cocoa/_WKRemoteObjectRegistryInternal.h:

Tools:

  • TestWebKitAPI/Tests/WebKit2Cocoa/RemoteObjectRegistry.h: Declared a new method.
  • TestWebKitAPI/Tests/WebKit2Cocoa/RemoteObjectRegistry.mm:

(TEST): Added a test case that checks that the reply block is released even when it’s not

called.

  • TestWebKitAPI/Tests/WebKit2Cocoa/RemoteObjectRegistryPlugIn.mm:

(-[RemoteObjectRegistryPlugIn doNotCallCompletionHandler:]): Implement new method by not

calling the completion handler.

Location:
trunk
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebKit2/ChangeLog

    r204243 r204245  
     12016-08-07  Dan Bernstein  <mitz@apple.com>
     2
     3        [Cocoa] Reply block leaks if the remote object doesn’t call it
     4        https://bugs.webkit.org/show_bug.cgi?id=160642
     5
     6        Reviewed by Sam Weinig.
     7
     8        * Shared/API/Cocoa/RemoteObjectRegistry.h: Declared new member functions.
     9        * Shared/API/Cocoa/RemoteObjectRegistry.messages.in: Added ReleaseUnusedReplyBlock message.
     10        * Shared/API/Cocoa/RemoteObjectRegistry.mm:
     11        (WebKit::RemoteObjectRegistry::sendUnusedReply): Send the ReleaseUnusedReplyBlock message.
     12        (WebKit::RemoteObjectRegistry::releaseUnusedReplyBlock): Message receiver that call through
     13          to -_releaseReplyWithID:.
     14
     15        * Shared/API/Cocoa/_WKRemoteObjectRegistry.mm:
     16        (-[_WKRemoteObjectRegistry _invokeMethod:]): Define a ReplyBlockCallChecker object and
     17          capture an instance of it in the reply block we pass to the exported object. Have that
     18          block set a flag on the checker when it’s called. If the checker gets destroyed without
     19          the block having been called, which means that the block got destroyed without being
     20          called, call sendUnusedReply to let the other side know that the block will not be invoked.
     21        (-[_WKRemoteObjectRegistry _releaseReplyWithID:]): Added. Removed the pending reply from the
     22          map, which release the block.
     23        * Shared/API/Cocoa/_WKRemoteObjectRegistryInternal.h:
     24
    1252016-08-07  Chris Dumez  <cdumez@apple.com>
    226
  • trunk/Source/WebKit2/Shared/API/Cocoa/RemoteObjectRegistry.h

    r197563 r204245  
    4747    void sendInvocation(const RemoteObjectInvocation&);
    4848    void sendReplyBlock(uint64_t replyID, const UserData& blockInvocation);
     49    void sendUnusedReply(uint64_t replyID);
    4950
    5051private:
     
    5556    void invokeMethod(const RemoteObjectInvocation&);
    5657    void callReplyBlock(uint64_t replyID, const UserData& blockInvocation);
     58    void releaseUnusedReplyBlock(uint64_t replyID);
    5759
    5860    _WKRemoteObjectRegistry *m_remoteObjectRegistry;
  • trunk/Source/WebKit2/Shared/API/Cocoa/RemoteObjectRegistry.messages.in

    r192185 r204245  
    2424    InvokeMethod(WebKit::RemoteObjectInvocation invocation)
    2525    CallReplyBlock(uint64_t replyID, WebKit::UserData blockInvocation);
     26    ReleaseUnusedReplyBlock(uint64_t replyID);
    2627}
  • trunk/Source/WebKit2/Shared/API/Cocoa/RemoteObjectRegistry.mm

    r192189 r204245  
    5555}
    5656
     57void RemoteObjectRegistry::sendUnusedReply(uint64_t replyID)
     58{
     59    m_messageSender.send(Messages::RemoteObjectRegistry::ReleaseUnusedReplyBlock(replyID));
     60}
     61
    5762void RemoteObjectRegistry::invokeMethod(const RemoteObjectInvocation& invocation)
    5863{
     
    6974}
    7075
     76void RemoteObjectRegistry::releaseUnusedReplyBlock(uint64_t replyID)
     77{
     78#if WK_API_ENABLED
     79    [m_remoteObjectRegistry _releaseReplyWithID:replyID];
     80#endif
     81}
    7182} // namespace WebKit
  • trunk/Source/WebKit2/Shared/API/Cocoa/_WKRemoteObjectRegistry.mm

    r204232 r204245  
    217217            RetainPtr<_WKRemoteObjectRegistry> remoteObjectRegistry = self;
    218218            uint64_t replyID = replyInfo->replyID;
    219             id replyBlock = __NSMakeSpecialForwardingCaptureBlock(wireBlockSignature._typeString.UTF8String, [interface, remoteObjectRegistry, replyID](NSInvocation *invocation) {
     219
     220            class ReplyBlockCallChecker : public WTF::ThreadSafeRefCounted<ReplyBlockCallChecker> {
     221            public:
     222                static Ref<ReplyBlockCallChecker> create(_WKRemoteObjectRegistry *registry, uint64_t replyID) { return adoptRef(*new ReplyBlockCallChecker(registry, replyID)); }
     223
     224                ~ReplyBlockCallChecker()
     225                {
     226                    if (!m_didCallReplyBlock)
     227                        m_remoteObjectRegistry->_remoteObjectRegistry->sendUnusedReply(m_replyID);
     228                }
     229
     230                void didCallReplyBlock() { m_didCallReplyBlock = true; }
     231
     232            private:
     233                ReplyBlockCallChecker(_WKRemoteObjectRegistry *registry, uint64_t replyID)
     234                    : m_remoteObjectRegistry(registry)
     235                    , m_replyID(replyID)
     236                {
     237                }
     238
     239                RetainPtr<_WKRemoteObjectRegistry> m_remoteObjectRegistry;
     240                uint64_t m_replyID = 0;
     241                bool m_didCallReplyBlock = false;
     242            };
     243
     244            RefPtr<ReplyBlockCallChecker> checker = ReplyBlockCallChecker::create(self, replyID);
     245            id replyBlock = __NSMakeSpecialForwardingCaptureBlock(wireBlockSignature._typeString.UTF8String, [interface, remoteObjectRegistry, replyID, checker](NSInvocation *invocation) {
    220246                auto encoder = adoptNS([[WKRemoteObjectEncoder alloc] init]);
    221247                [encoder encodeObject:invocation forKey:invocationKey];
    222248
    223249                remoteObjectRegistry->_remoteObjectRegistry->sendReplyBlock(replyID, UserData([encoder rootObjectDictionary]));
     250                checker->didCallReplyBlock();
    224251            });
    225252
     
    271298}
    272299
     300- (void)_releaseReplyWithID:(uint64_t)replyID
     301{
     302    _pendingReplies.remove(replyID);
     303}
     304
    273305@end
    274306
  • trunk/Source/WebKit2/Shared/API/Cocoa/_WKRemoteObjectRegistryInternal.h

    r192185 r204245  
    4949
    5050- (void)_callReplyWithID:(uint64_t)replyID blockInvocation:(const WebKit::UserData&)blockInvocation;
     51- (void)_releaseReplyWithID:(uint64_t)replyID;
    5152
    5253@end
  • trunk/Tools/ChangeLog

    r204243 r204245  
     12016-08-07  Dan Bernstein  <mitz@apple.com>
     2
     3        [Cocoa] Reply block leaks if the remote object doesn’t call it
     4        https://bugs.webkit.org/show_bug.cgi?id=160642
     5
     6        Reviewed by Sam Weinig.
     7
     8        * TestWebKitAPI/Tests/WebKit2Cocoa/RemoteObjectRegistry.h: Declared a new method.
     9        * TestWebKitAPI/Tests/WebKit2Cocoa/RemoteObjectRegistry.mm:
     10        (TEST): Added a test case that checks that the reply block is released even when it’s not
     11          called.
     12        * TestWebKitAPI/Tests/WebKit2Cocoa/RemoteObjectRegistryPlugIn.mm:
     13        (-[RemoteObjectRegistryPlugIn doNotCallCompletionHandler:]): Implement new method by not
     14          calling the completion handler.
     15
    1162016-08-07  Chris Dumez  <cdumez@apple.com>
    217
  • trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/RemoteObjectRegistry.h

    r204188 r204245  
    3636- (void)selectionAndClickInformationForClickAtPoint:(NSValue *)pointValue completionHandler:(void (^)(NSDictionary *))completionHandler;
    3737- (void)takeRange:(NSRange)range completionHandler:(void (^)(NSUInteger location, NSUInteger length))completionHandler;
     38- (void)doNotCallCompletionHandler:(void (^)())completionHandler;
    3839
    3940@end
  • trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/RemoteObjectRegistry.mm

    r204188 r204245  
    3636#import <WebKit/_WKRemoteObjectInterface.h>
    3737#import <WebKit/_WKRemoteObjectRegistry.h>
     38#import <wtf/RefCounted.h>
    3839#import <wtf/RetainPtr.h>
    3940
     
    8384        }];
    8485        TestWebKitAPI::Util::run(&isDone);
     86
     87        isDone = false;
     88
     89        class DoneWhenDestroyed : public RefCounted<DoneWhenDestroyed> {
     90        public:
     91            ~DoneWhenDestroyed() { isDone = true; }
     92        };
     93
     94        {
     95            RefPtr<DoneWhenDestroyed> doneWhenDestroyed = adoptRef(*new DoneWhenDestroyed);
     96            [object doNotCallCompletionHandler:[doneWhenDestroyed]() {
     97            }];
     98        }
     99
     100        TestWebKitAPI::Util::run(&isDone);
    85101    }
    86102}
  • trunk/Tools/TestWebKitAPI/Tests/WebKit2Cocoa/RemoteObjectRegistryPlugIn.mm

    r204188 r204245  
    8282}
    8383
     84- (void)doNotCallCompletionHandler:(void (^)())completionHandler
     85{
     86}
     87
    8488@end
    8589
Note: See TracChangeset for help on using the changeset viewer.