Skip to content

Commit

Permalink
Cherry-pick 265870.534@safari-7616-branch (3be7816). https://bugs.web…
Browse files Browse the repository at this point in the history
…kit.org/show_bug.cgi?id=261289

    Bad jsCast<>() in copyDataFromJSArrayToBuses() in AudioWorkletProcessor.cpp
    https://bugs.webkit.org/show_bug.cgi?id=261289
    rdar://115042475

    Reviewed by Ryosuke Niwa.

    Use jsDynamicCast<>() instead of jsCast<>() in AudioWorkletProcessor.cpp for
    safety.

    * LayoutTests/webaudio/audioworklet-bad-array-type-expected.txt: Added.
    * LayoutTests/webaudio/audioworklet-bad-array-type.html: Added.
    * LayoutTests/webaudio/bad-array-type-processor.js: Added.
    (CustomProcessor.prototype.process):
    (CustomProcessor):
    * Source/WebCore/Modules/webaudio/AudioWorkletProcessor.cpp:
    (WebCore::toJSArray):
    (WebCore::toJSObject):
    (WebCore::copyDataFromJSArrayToBuses):
    (WebCore::AudioWorkletProcessor::process):

    Canonical link: https://commits.webkit.org/265870.534@safari-7616-branch
  • Loading branch information
cdumez authored and aperezdc committed Oct 20, 2023
1 parent a305325 commit e0e6399
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This test passes if it does not crash.
31 changes: 31 additions & 0 deletions LayoutTests/webaudio/audioworklet-bad-array-type.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<body>
<p>This test passes if it does not crash.</p>
<script>
if (window.testRunner) {
testRunner.waitUntilDone();
testRunner.dumpAsText();
}

async function runTest() {
const audio_context = new OfflineAudioContext(2, 1, 44100);
await audio_context.audioWorklet.addModule('bad-array-type-processor.js?' + Math.random());

const node1 = new AudioWorkletNode(audio_context, 'bad-array-type-processor');
const node2 = new AudioWorkletNode(audio_context, 'bad-array-type-processor', {
numberOfOutputs: 2,
outputChannelCount: [1, 1]
});

const buffer_source = audio_context.createBufferSource();
buffer_source.buffer = audio_context.createBuffer(1, 1, 44100);
buffer_source.connect(node1).connect(node2).connect(audio_context.destination);
buffer_source.start();

await audio_context.startRendering();
if (window.testRunner)
testRunner.notifyDone();
}

runTest();
</script>
</body>
22 changes: 22 additions & 0 deletions LayoutTests/webaudio/bad-array-type-processor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Array.prototype[1] = [new Float32Array(0x80)];

let count = 0;
class CustomProcessor extends AudioWorkletProcessor {
process(inputs, outputs, parameters) {
count++;

if (count === 2) {
Array.prototype[1] = 0x1234;
}

return true;
}
}

let processor = null;
registerProcessor('bad-array-type-processor', function (options) {
if (processor !== null)
return processor;

return processor = new CustomProcessor(options);
});
35 changes: 21 additions & 14 deletions Source/WebCore/Modules/webaudio/AudioWorkletProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,12 @@ static unsigned busChannelCount(const AudioBus* bus)

static JSArray* toJSArray(JSValueInWrappedObject& wrapper)
{
return wrapper ? jsCast<JSArray*>(wrapper.getValue()) : nullptr;
return wrapper ? jsDynamicCast<JSArray*>(wrapper.getValue()) : nullptr;
}

static JSObject* toJSObject(JSValueInWrappedObject& wrapper)
{
return wrapper ? jsCast<JSObject*>(wrapper.getValue()) : nullptr;
return wrapper ? jsDynamicCast<JSObject*>(wrapper.getValue()) : nullptr;
}

static JSFloat32Array* constructJSFloat32Array(JSGlobalObject& globalObject, unsigned length, const float* data = nullptr)
Expand Down Expand Up @@ -127,11 +127,15 @@ static void copyDataFromJSArrayToBuses(JSGlobalObject& globalObject, const JSArr
// We can safely make assumptions about the structure of the JSArray since we use frozen arrays.
for (unsigned i = 0; i < buses.size(); ++i) {
auto& bus = buses[i];
auto* channelsArray = jsCast<JSArray*>(jsArray.getIndex(&globalObject, i));
auto* channelsArray = jsDynamicCast<JSArray*>(jsArray.getIndex(&globalObject, i));
if (UNLIKELY(!channelsArray)) {
bus->zero();
continue;
}
for (unsigned j = 0; j < bus->numberOfChannels(); ++j) {
auto* channel = bus->channel(j);
auto* jsChannelData = jsCast<JSFloat32Array*>(channelsArray->getIndex(&globalObject, j));
if (jsChannelData->length() == channel->length())
auto* jsChannelData = jsDynamicCast<JSFloat32Array*>(channelsArray->getIndex(&globalObject, j));
if (LIKELY(jsChannelData && jsChannelData->length() == channel->length()))
memcpy(channel->mutableData(), jsChannelData->typedVector(), sizeof(float) * channel->length());
else
channel->zero();
Expand Down Expand Up @@ -243,28 +247,31 @@ bool AudioWorkletProcessor::process(const Vector<RefPtr<AudioBus>>& inputs, Vect
DisableMallocRestrictionsForCurrentThreadScope disableMallocRestrictions;

ASSERT(wrapper());
auto& globalObject = *jsCast<JSDOMGlobalObject*>(m_globalScope.globalObject());
ASSERT(globalObject.scriptExecutionContext());
ASSERT(globalObject.scriptExecutionContext()->isContextThread());
auto* globalObject = jsDynamicCast<JSDOMGlobalObject*>(m_globalScope.globalObject());
if (UNLIKELY(!globalObject))
return false;

ASSERT(globalObject->scriptExecutionContext());
ASSERT(globalObject->scriptExecutionContext()->isContextThread());

auto& vm = globalObject.vm();
auto& vm = globalObject->vm();
JSLockHolder lock(vm);

MarkedArgumentBuffer args;
buildJSArguments(vm, globalObject, args, inputs, outputs, paramValuesMap);
buildJSArguments(vm, *globalObject, args, inputs, outputs, paramValuesMap);
ASSERT(!args.hasOverflowed());

NakedPtr<JSC::Exception> returnedException;
auto result = JSCallbackData::invokeCallback(globalObject, wrapper(), jsUndefined(), args, JSCallbackData::CallbackType::Object, Identifier::fromString(vm, "process"_s), returnedException);
auto result = JSCallbackData::invokeCallback(*globalObject, wrapper(), jsUndefined(), args, JSCallbackData::CallbackType::Object, Identifier::fromString(vm, "process"_s), returnedException);
if (returnedException) {
reportException(&globalObject, returnedException);
reportException(globalObject, returnedException);
threwException = true;
return false;
}

copyDataFromJSArrayToBuses(globalObject, *toJSArray(m_jsOutputs), outputs);
copyDataFromJSArrayToBuses(*globalObject, *toJSArray(m_jsOutputs), outputs);

return result.toBoolean(&globalObject);
return result.toBoolean(globalObject);
}

WebCoreOpaqueRoot root(AudioWorkletProcessor* processor)
Expand Down

0 comments on commit e0e6399

Please sign in to comment.