Changeset 280900 in webkit
- Timestamp:
- Aug 11, 2021, 3:43:09 AM (5 years ago)
- Location:
- releases/WebKitGTK/webkit-2.32/Source/WebCore
- Files:
-
- 2 edited
-
ChangeLog (modified) (1 diff)
-
Modules/webaudio/AudioWorkletProcessor.cpp (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
releases/WebKitGTK/webkit-2.32/Source/WebCore/ChangeLog
r280899 r280900 1 2021-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 1 17 2021-03-19 Rob Buis <rbuis@igalia.com> 2 18 -
releases/WebKitGTK/webkit-2.32/Source/WebCore/Modules/webaudio/AudioWorkletProcessor.cpp
r268560 r280900 66 66 } 67 67 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 77 68 static JSFloat32Array* constructJSFloat32Array(JSGlobalObject& globalObject, unsigned length, const float* data = nullptr) 78 69 { … … 144 135 } 145 136 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 { 137 static 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 159 static bool copyDataFromParameterMapToJSObject(VM& vm, JSGlobalObject& globalObject, const HashMap<String, std::unique_ptr<AudioFloatArray>>& paramValuesMap, JSObject* jsObject) 160 { 161 if (!jsObject) 162 return false; 163 157 164 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; 197 168 unsigned expectedLength = pair.value->containsConstantValue() ? 1 : pair.value->size(); 198 169 if (jsTypedArray->length() != expectedLength) 199 170 return false; 200 }201 171 memcpy(jsTypedArray->typedVector(), pair.value->data(), sizeof(float) * jsTypedArray->length()); 172 } 202 173 return true; 203 174 } 204 175 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 }); 176 static 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; 210 196 } 211 197 … … 231 217 { 232 218 // 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))) 236 220 m_jsInputs = { constructFrozenJSArray(vm, globalObject, inputs, ShouldPopulateWithBusData::Yes) }; 237 221 args.append(m_jsInputs); 238 222 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))) 242 224 m_jsOutputs = { constructFrozenJSArray(vm, globalObject, outputs, ShouldPopulateWithBusData::No) }; 243 225 args.append(m_jsOutputs); 244 226 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))) 248 228 m_jsParamValues = { constructFrozenKeyValueObject(vm, globalObject, paramValuesMap) }; 249 229 args.append(m_jsParamValues);
Note:
See TracChangeset
for help on using the changeset viewer.