Skip to content

Commit 564641e

Browse files
Merge pull request #916 from SceneTech/fix/writable-stream-closed-915
Reject writable file commands after close or abort
2 parents 8c90c5c + 01b8cd4 commit 564641e

2 files changed

Lines changed: 40 additions & 6 deletions

File tree

‎experiments/WebScene.NativeEngine.Probe/native/webscene_v8_runtime_file_system_access.inc‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1563,10 +1563,14 @@
15631563
}
15641564
};
15651565
const queueWriterCommand = (stream, command) => {
1566-
if (!writerStates.has(stream)) {
1566+
const state = writerStates.get(stream);
1567+
if (!state) {
15671568
)JS",
15681569
R"JS( return Promise.reject(new TypeError('Illegal invocation'));
15691570
}
1571+
if (!state.transaction) {
1572+
return Promise.reject(new TypeError('Writer is closed'));
1573+
}
15701574
let writer;
15711575
try { writer = WritableStream.prototype.getWriter.call(stream); }
15721576
catch (error) { return Promise.reject(error); }

‎experiments/WebScene.NativeEngine.Probe/tests/native_file_system_access_tests.inc‎

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1683,11 +1683,23 @@ void test_native_file_system_access_picker_and_handle_contract()
16831683
&& write_state.find("\"instance\":true") != std::string::npos
16841684
&& write_state.find("\"closed\":true") != std::string::npos,
16851685
"createWritable stream identity or close changed: " + write_state);
1686-
require(evaluate(engine.get(), R"JS((async()=>{
1687-
try { await __writeStream.write('late'); return 'unexpected'; }
1688-
catch (error) { return error.name; }
1689-
})())JS", "file-handle-write-after-close.js") == "\"TypeError\"",
1690-
"write after close did not reject TypeError");
1686+
execute(engine.get(), R"JS(globalThis.__closedCommandState = 'pending'; (async()=>{
1687+
const errors = [];
1688+
for (const command of [
1689+
() => __writeStream.write('late'),
1690+
() => __writeStream.seek(0),
1691+
() => __writeStream.truncate(0)]) {
1692+
try { await command(); errors.push('resolved'); }
1693+
catch (error) { errors.push(error.name); }
1694+
}
1695+
globalThis.__closedCommandState = errors.join(',');
1696+
})())JS", "file-handle-command-after-close.js");
1697+
const auto closed_command_state = evaluate_until_equals(engine.get(),
1698+
"__closedCommandState", "file-handle-command-after-close-result.js",
1699+
"\"TypeError,TypeError,TypeError\"");
1700+
require(closed_command_state == "\"TypeError,TypeError,TypeError\"",
1701+
"write/seek/truncate after close did not reject TypeError: "
1702+
+ closed_command_state);
16911703

16921704
activate_file_picker(engine.get(), 50005U);
16931705
execute(engine.get(), R"JS(
@@ -1770,6 +1782,7 @@ void test_native_file_system_access_picker_and_handle_contract()
17701782
execute(engine.get(), R"JS(
17711783
globalThis.__abortedWrite='pending';
17721784
__saveHandle.createWritable().then(async stream => {
1785+
globalThis.__abortedStream = stream;
17731786
await stream.abort('discard');
17741787
__abortedWrite='aborted';
17751788
}, error => { __abortedWrite=error.name; });
@@ -1795,6 +1808,23 @@ void test_native_file_system_access_picker_and_handle_contract()
17951808
require(evaluate(engine.get(), "__abortedWrite",
17961809
"file-handle-create-writable-abort-result.js") == "\"aborted\"",
17971810
"stream abort did not preserve terminal state");
1811+
execute(engine.get(), R"JS(globalThis.__abortedCommandState = 'pending'; (async()=>{
1812+
const errors = [];
1813+
for (const command of [
1814+
() => __abortedStream.write('late'),
1815+
() => __abortedStream.seek(0),
1816+
() => __abortedStream.truncate(0)]) {
1817+
try { await command(); errors.push('resolved'); }
1818+
catch (error) { errors.push(error.name); }
1819+
}
1820+
globalThis.__abortedCommandState = errors.join(',');
1821+
})())JS", "file-handle-command-after-abort.js");
1822+
const auto aborted_command_state = evaluate_until_equals(engine.get(),
1823+
"__abortedCommandState", "file-handle-command-after-abort-result.js",
1824+
"\"TypeError,TypeError,TypeError\"");
1825+
require(aborted_command_state == "\"TypeError,TypeError,TypeError\"",
1826+
"write/seek/truncate after abort did not reject TypeError: "
1827+
+ aborted_command_state);
17981828

17991829
execute(engine.get(), R"JS(
18001830
globalThis.__writeFailure='pending';

0 commit comments

Comments
 (0)