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

Changeset 280900 in webkit


Ignore:
Timestamp:
Aug 11, 2021, 3:43:09 AM (5 years ago)
Author:
Adrian Perez de Castro
Message:

Merge r274776 - Better validate JSArrays in AudioWorkletProcessor
https://bugs.webkit.org/show_bug.cgi?id=223548

Reviewed by Geoffrey Garen.

Better validate JSArrays in AudioWorkletProcessor. Replaces debug assertions with runtime
checks for robustness.

  • Modules/webaudio/AudioWorkletProcessor.cpp:

(WebCore::copyDataFromBusesToJSArray):
(WebCore::copyDataFromParameterMapToJSObject):
(WebCore::zeroJSArray):
(WebCore::AudioWorkletProcessor::buildJSArguments):

Location:
releases/WebKitGTK/webkit-2.32/Source/WebCore
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • releases/WebKitGTK/webkit-2.32/Source/WebCore/ChangeLog

    r280899 r280900  
     12021-03-22  Chris Dumez  <cdumez@apple.com>
     2
     3        Better validate JSArrays in AudioWorkletProcessor
     4        https://bugs.webkit.org/show_bug.cgi?id=223548
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        Better validate JSArrays in AudioWorkletProcessor. Replaces debug assertions with runtime
     9        checks for robustness.
     10
     11        * Modules/webaudio/AudioWorkletProcessor.cpp:
     12        (WebCore::copyDataFromBusesToJSArray):
     13        (WebCore::copyDataFromParameterMapToJSObject):
     14        (WebCore::zeroJSArray):
     15        (WebCore::AudioWorkletProcessor::buildJSArguments):
     16
    1172021-03-19  Rob Buis  <rbuis@igalia.com>
    218
  • releases/WebKitGTK/webkit-2.32/Source/WebCore/Modules/webaudio/AudioWorkletProcessor.cpp

    r268560 r280900  
    6666}
    6767
    68 static void forEachChannelDataJSArray(JSGlobalObject& globalObject, JSArray& jsArray, const Function<void(unsigned busIndex, unsigned channelIndex, JSFloat32Array& channelData)>& apply)
    69 {
    70     for (unsigned busIndex = 0, busCount = jsArray.length(); busIndex < busCount; ++busIndex) {
    71         auto* channelsArray = jsCast<JSArray*>(jsArray.getIndex(&globalObject, busIndex));
    72         for (unsigned channelIndex = 0, channelCount = channelsArray->length(); channelIndex < channelCount; ++channelIndex)
    73             apply(busIndex, channelIndex, *jsCast<JSFloat32Array*>(channelsArray->getIndex(&globalObject, channelIndex)));
    74     }
    75 }
    76 
    7768static JSFloat32Array* constructJSFloat32Array(JSGlobalObject& globalObject, unsigned length, const float* data = nullptr)
    7869{
     
    144135}
    145136
    146 static void copyDataFromBusesToJSArray(JSGlobalObject& globalObject, const Vector<RefPtr<AudioBus>>& buses, JSArray& jsArray)
    147 {
    148     forEachChannelDataJSArray(globalObject, jsArray, [&](unsigned busIndex, unsigned channelIndex, JSFloat32Array& channelData) {
    149         auto* channel = buses[busIndex]->channel(channelIndex);
    150         ASSERT(channelData.length() == channel->length());
    151         memcpy(channelData.typedVector(), channel->mutableData(), sizeof(float) * channel->length());
    152     });
    153 }
    154 
    155 static void copyDataFromParameterMapToJSObject(VM& vm, JSGlobalObject& globalObject, const HashMap<String, std::unique_ptr<AudioFloatArray>>& paramValuesMap, JSObject& jsObject)
    156 {
     137static bool copyDataFromBusesToJSArray(VM& vm, JSGlobalObject& globalObject, const Vector<RefPtr<AudioBus>>& buses, JSArray* jsArray)
     138{
     139    if (!jsArray)
     140        return false;
     141
     142    for (size_t busIndex = 0; busIndex < buses.size(); ++busIndex) {
     143        auto& bus = buses[busIndex];
     144        auto* jsChannelsArray = jsDynamicCast<JSArray*>(vm, jsArray->getIndex(&globalObject, busIndex));
     145        unsigned numberOfChannels = busChannelCount(bus.get());
     146        if (!jsChannelsArray || jsChannelsArray->length() != numberOfChannels)
     147            return false;
     148        for (unsigned channelIndex = 0; channelIndex < numberOfChannels; ++channelIndex) {
     149            auto* channel = bus->channel(channelIndex);
     150            auto* jsChannelArray = jsDynamicCast<JSFloat32Array*>(vm, jsChannelsArray->getIndex(&globalObject, channelIndex));
     151            if (!jsChannelArray || jsChannelArray->length() != channel->length())
     152                return false;
     153            memcpy(jsChannelArray->typedVector(), channel->mutableData(), sizeof(float) * jsChannelArray->length());
     154        }
     155    }
     156    return true;
     157}
     158
     159static bool copyDataFromParameterMapToJSObject(VM& vm, JSGlobalObject& globalObject, const HashMap<String, std::unique_ptr<AudioFloatArray>>& paramValuesMap, JSObject* jsObject)
     160{
     161    if (!jsObject)
     162        return false;
     163
    157164    for (auto& pair : paramValuesMap) {
    158         auto* jsTypedArray = jsCast<JSFloat32Array*>(jsObject.get(&globalObject, Identifier::fromString(vm, pair.key)));
    159         ASSERT(pair.value->size() >= jsTypedArray->length());
    160         memcpy(jsTypedArray->typedVector(), pair.value->data(), sizeof(float) * jsTypedArray->length());
    161     }
    162 }
    163 
    164 template<typename T>
    165 static bool busTopologyMatchesJSArray(JSGlobalObject& globalObject, const Vector<T>& buses, JSArray* jsArray)
    166 {
    167     if (!jsArray)
    168         return false;
    169 
    170     ASSERT_WITH_MESSAGE(jsArray->length() == buses.size(), "Number of inputs/outputs cannot change after construction");
    171 
    172     for (unsigned i = 0; i < buses.size(); ++i) {
    173         auto& bus = buses[i];
    174         auto* channelsArray = jsCast<JSArray*>(jsArray->getIndex(&globalObject, i));
    175         unsigned numberOfChannels = busChannelCount(bus.get());
    176         if (channelsArray->length() != numberOfChannels)
    177             return false;
    178 
    179         for (unsigned j = 0; j < numberOfChannels; ++j) {
    180             auto* channel = bus->channel(j);
    181             auto* jsChannelData = jsCast<JSFloat32Array*>(channelsArray->getIndex(&globalObject, j));
    182             if (jsChannelData->length() != channel->length())
    183                 return false;
    184         }
    185     }
    186 
    187     return true;
    188 }
    189 
    190 static bool parameterMapTopologyMatchesJSObject(VM& vm, JSGlobalObject& globalObject, const HashMap<String, std::unique_ptr<AudioFloatArray>>& paramValuesMap, JSObject* jsObject)
    191 {
    192     if (!jsObject)
    193         return false;
    194 
    195     for (auto& pair : paramValuesMap) {
    196         auto* jsTypedArray = jsCast<JSFloat32Array*>(jsObject->get(&globalObject, Identifier::fromString(vm, pair.key)));
     165        auto* jsTypedArray = jsDynamicCast<JSFloat32Array*>(vm, jsObject->get(&globalObject, Identifier::fromString(vm, pair.key)));
     166        if (!jsTypedArray)
     167            return false;
    197168        unsigned expectedLength = pair.value->containsConstantValue() ? 1 : pair.value->size();
    198169        if (jsTypedArray->length() != expectedLength)
    199170            return false;
    200     }
    201 
     171        memcpy(jsTypedArray->typedVector(), pair.value->data(), sizeof(float) * jsTypedArray->length());
     172    }
    202173    return true;
    203174}
    204175
    205 static void zeroJSArray(JSGlobalObject& globalObject, JSArray& jsArray)
    206 {
    207     forEachChannelDataJSArray(globalObject, jsArray, [](unsigned, unsigned, JSFloat32Array& channelData) {
    208         memset(channelData.typedVector(), 0, sizeof(float) * channelData.length());
    209     });
     176static bool zeroJSArray(VM& vm, JSGlobalObject& globalObject, const Vector<Ref<AudioBus>>& outputs, JSArray* jsArray)
     177{
     178    if (!jsArray)
     179        return false;
     180
     181    for (size_t busIndex = 0; busIndex < outputs.size(); ++busIndex) {
     182        auto& bus = outputs[busIndex];
     183        auto* jsChannelsArray = jsDynamicCast<JSArray*>(vm, jsArray->getIndex(&globalObject, busIndex));
     184        unsigned numberOfChannels = busChannelCount(bus.get());
     185        if (!jsChannelsArray || jsChannelsArray->length() != numberOfChannels)
     186            return false;
     187        for (unsigned channelIndex = 0; channelIndex < numberOfChannels; ++channelIndex) {
     188            auto* channel = bus->channel(channelIndex);
     189            auto* jsChannelArray = jsDynamicCast<JSFloat32Array*>(vm, jsChannelsArray->getIndex(&globalObject, channelIndex));
     190            if (!jsChannelArray || jsChannelArray->length() != channel->length())
     191                return false;
     192            memset(jsChannelArray->typedVector(), 0, sizeof(float) * jsChannelArray->length());
     193        }
     194    }
     195    return true;
    210196}
    211197
     
    231217{
    232218    // For performance reasons, we cache the arrays passed to JS and reconstruct them only when the topology changes.
    233     if (busTopologyMatchesJSArray(globalObject, inputs, toJSArray(m_jsInputs)))
    234         copyDataFromBusesToJSArray(globalObject, inputs, *toJSArray(m_jsInputs));
    235     else
     219    if (!copyDataFromBusesToJSArray(vm, globalObject, inputs, toJSArray(m_jsInputs)))
    236220        m_jsInputs = { constructFrozenJSArray(vm, globalObject, inputs, ShouldPopulateWithBusData::Yes) };
    237221    args.append(m_jsInputs);
    238222
    239     if (busTopologyMatchesJSArray(globalObject, outputs, toJSArray(m_jsOutputs)))
    240         zeroJSArray(globalObject, *toJSArray(m_jsOutputs));
    241     else
     223    if (!zeroJSArray(vm, globalObject, outputs, toJSArray(m_jsOutputs)))
    242224        m_jsOutputs = { constructFrozenJSArray(vm, globalObject, outputs, ShouldPopulateWithBusData::No) };
    243225    args.append(m_jsOutputs);
    244226
    245     if (parameterMapTopologyMatchesJSObject(vm, globalObject, paramValuesMap, toJSObject(m_jsParamValues)))
    246         copyDataFromParameterMapToJSObject(vm, globalObject, paramValuesMap, *toJSObject(m_jsParamValues));
    247     else
     227    if (!copyDataFromParameterMapToJSObject(vm, globalObject, paramValuesMap, toJSObject(m_jsParamValues)))
    248228        m_jsParamValues = { constructFrozenKeyValueObject(vm, globalObject, paramValuesMap) };
    249229    args.append(m_jsParamValues);
Note: See TracChangeset for help on using the changeset viewer.