Changeset 101813 in webkit


Ignore:
Timestamp:
Dec 2, 2011 9:42:54 AM (12 years ago)
Author:
Darin Adler
Message:

[Mac] Reference count threading violation in FormDataStreamMac.mm
https://bugs.webkit.org/show_bug.cgi?id=73627

Reviewed by Sam Weinig.

Shows up as a crash during existing layout test runs so no new tests are required.

  • platform/network/mac/FormDataStreamMac.mm:

(WebCore::streamFieldsMap): Replaced getStreamFormDataMap with this.
Use an NSMapTable instead of a HashMap because we need to remove items from this
on a non-main thread.
(WebCore::associateStreamWithResourceHandle): Use NSMapGet instead of
HashMap::contains here.
(WebCore::formCreate): FormStreamFields now stores a RefPtr to the form data.
Added the code to fill that in. Did it in a more modern way to avoid the leakRef
and adoptRef that were used before. Replaced the code that set up the stream
form data map entry with code that sets an entry in the streamFieldsMap.
(WebCore::formFinishFinalizationOnMainThread): Added. Contains the work of
finalization that must be done on the main thread, specifically, destroying the
fields structure that contains objects with RefPtr in them. We can't touch these
reference counts on non-main threads.
(WebCore::formFinalize): Changed this to use NSMapRemove on the streamFieldsMap.
Added a callOnMainThread to finish the finalization.
(WebCore::setHTTPBody): Removed the leakRef, no longer needed, that used to be
balanced by an adoptRef in formCreate.
(WebCore::httpBodyFromStream): Changed to use NSMapGet.

Location:
trunk/Source/WebCore
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r101812 r101813  
     12011-12-01  Darin Adler  <darin@apple.com>
     2
     3        [Mac] Reference count threading violation in FormDataStreamMac.mm
     4        https://bugs.webkit.org/show_bug.cgi?id=73627
     5
     6        Reviewed by Sam Weinig.
     7
     8        Shows up as a crash during existing layout test runs so no new tests are required.
     9
     10        * platform/network/mac/FormDataStreamMac.mm:
     11        (WebCore::streamFieldsMap): Replaced getStreamFormDataMap with this.
     12        Use an NSMapTable instead of a HashMap because we need to remove items from this
     13        on a non-main thread.
     14        (WebCore::associateStreamWithResourceHandle): Use NSMapGet instead of
     15        HashMap::contains here.
     16        (WebCore::formCreate): FormStreamFields now stores a RefPtr to the form data.
     17        Added the code to fill that in. Did it in a more modern way to avoid the leakRef
     18        and adoptRef that were used before. Replaced the code that set up the stream
     19        form data map entry with code that sets an entry in the streamFieldsMap.
     20        (WebCore::formFinishFinalizationOnMainThread): Added. Contains the work of
     21        finalization that must be done on the main thread, specifically, destroying the
     22        fields structure that contains objects with RefPtr in them. We can't touch these
     23        reference counts on non-main threads.
     24        (WebCore::formFinalize): Changed this to use NSMapRemove on the streamFieldsMap.
     25        Added a callOnMainThread to finish the finalization.
     26        (WebCore::setHTTPBody): Removed the leakRef, no longer needed, that used to be
     27        balanced by an adoptRef in formCreate.
     28        (WebCore::httpBodyFromStream): Changed to use NSMapGet.
     29
    1302011-12-02  Antti Koivisto  <antti@apple.com>
    231
  • trunk/Source/WebCore/platform/network/mac/FormDataStreamMac.mm

    r89283 r101813  
    11/*
    2  * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
     2 * Copyright (C) 2005, 2006, 2008, 2011 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    5757namespace WebCore {
    5858
    59 typedef HashMap<CFReadStreamRef, RefPtr<FormData> > StreamFormDataMap;
    60 static StreamFormDataMap& getStreamFormDataMap()
    61 {
    62     DEFINE_STATIC_LOCAL(StreamFormDataMap, streamFormDataMap, ());
    63     return streamFormDataMap;
     59// We need to use NSMapTable instead of HashMap since this needs to be accessed from more than one thread.
     60static NSMapTable *streamFieldsMap()
     61{
     62    static NSMapTable *streamFieldsMap = NSCreateMapTable(NSNonRetainedObjectMapKeyCallBacks, NSNonOwnedPointerMapValueCallBacks, 1);
     63    return streamFieldsMap;
    6464}
    6565
     
    8080        return;
    8181
    82     if (!getStreamFormDataMap().contains((CFReadStreamRef)stream))
     82    if (!NSMapGet(streamFieldsMap(), stream))
    8383        return;
    8484
     
    126126
    127127struct FormContext {
    128     FormData* formData;
     128    RefPtr<FormData> formData;
    129129    unsigned long long streamLength;
    130130};
    131131
    132132struct FormStreamFields {
     133    RefPtr<FormData> formData;
    133134    SchedulePairHashSet scheduledRunLoopPairs;
    134135    Vector<FormDataElement> remainingElements; // in reverse order
     
    231232
    232233    FormStreamFields* newInfo = new FormStreamFields;
     234    newInfo->formData = formContext->formData.release();
    233235    newInfo->currentStream = NULL;
    234236#if ENABLE(BLOB)
     
    240242    newInfo->bytesSent = 0;
    241243
    242     FormData* formData = formContext->formData;
    243 
    244244    // Append in reverse order since we remove elements from the end.
    245     size_t size = formData->elements().size();
     245    size_t size = newInfo->formData->elements().size();
    246246    newInfo->remainingElements.reserveInitialCapacity(size);
    247247    for (size_t i = 0; i < size; ++i)
    248         newInfo->remainingElements.append(formData->elements()[size - i - 1]);
    249 
    250     getStreamFormDataMap().set(stream, adoptRef(formData));
     248        newInfo->remainingElements.append(newInfo->formData->elements()[size - i - 1]);
     249
     250    ASSERT(!NSMapGet(streamFieldsMap(), stream));
     251    NSMapInsertKnownAbsent(streamFieldsMap(), stream, newInfo);
    251252
    252253    return newInfo;
    253254}
    254255
     256static void formFinishFinalizationOnMainThread(void* context)
     257{
     258    OwnPtr<FormStreamFields> form = adoptPtr(static_cast<FormStreamFields*>(context));
     259
     260    closeCurrentStream(form.get());
     261}
     262
    255263static void formFinalize(CFReadStreamRef stream, void* context)
    256264{
    257     OwnPtr<FormStreamFields> form = adoptPtr(static_cast<FormStreamFields*>(context));
    258 
    259     getStreamFormDataMap().remove(stream);
    260 
    261     closeCurrentStream(form.get());
     265    FormStreamFields* form = static_cast<FormStreamFields*>(context);
     266
     267    ASSERT(form->formStream == stream);
     268    ASSERT(NSMapGet(streamFieldsMap(), stream) == context);
     269
     270    // Do this right away because the CFReadStreamRef is being deallocated.
     271    // We can't wait to remove this from the map until we finish finalizing
     272    // on the main thread because in theory the freed memory could be reused
     273    // for a new CFReadStream before that runs.
     274    NSMapRemove(streamFieldsMap(), stream);
     275
     276    callOnMainThread(formFinishFinalizationOnMainThread, form);
    262277}
    263278
     
    472487
    473488    // Pass the length along with the formData so it does not have to be recomputed.
    474     FormContext formContext = { formData.release().leakRef(), length };
     489    FormContext formContext = { formData.release(), length };
    475490
    476491    RetainPtr<CFReadStreamRef> stream(AdoptCF, wkCreateCustomCFReadStream(formCreate, formFinalize,
     
    482497FormData* httpBodyFromStream(NSInputStream* stream)
    483498{
    484     return getStreamFormDataMap().get((CFReadStreamRef)stream).get();
     499    FormStreamFields* formStream = static_cast<FormStreamFields*>(NSMapGet(streamFieldsMap(), stream));
     500    if (!formStream)
     501        return 0;
     502    return formStream->formData.get();
    485503}
    486504
Note: See TracChangeset for help on using the changeset viewer.