mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-30 07:14:39 +08:00
Open a WriteStream's file when its encoding throws
Node's WriteStream constructor calls setDefaultEncoding after the Writable constructor has scheduled _construct, so with encoding: 'buffer' it throws ERR_UNKNOWN_ENCODING but the unreachable stream still opens its file on a later tick, creating it, and with the default 'w' flags truncating it. The runtime threw before scheduling the open; it now constructs the stream first, as Node does. Corpus 5547 ran that check on the file its other blocks write, so the late truncation raced with the fd block's write and Node's own output changed with the timing (it printed an empty file on macOS). The check now uses its own file, and the program prints that the file was created.
This commit is contained in:
@@ -557,23 +557,19 @@ static ScrStream *scr_fss_new(const ScrDyn *path, const ScrDyn *opts_in, bool re
|
||||
scr_dyn_release(eo);
|
||||
}
|
||||
if (!s) goto fail;
|
||||
bool unknown_encoding = false;
|
||||
if (!readable) {
|
||||
/* setDefaultEncoding(options.encoding) after the Writable constructor:
|
||||
* 'buffer' is not an encoding there; utf8 is the default */
|
||||
ScrDyn *enc = scr_fss_get(o, "encoding");
|
||||
bool buffer = enc && enc->kind == SCR_DYN_STR && enc->v.str->len == 6 &&
|
||||
unknown_encoding = enc && enc->kind == SCR_DYN_STR && enc->v.str->len == 6 &&
|
||||
memcmp(enc->v.str->data, "buffer", 6) == 0;
|
||||
bool other = enc && enc->kind == SCR_DYN_STR && enc->v.str->len > 0 && !buffer &&
|
||||
bool other = enc && enc->kind == SCR_DYN_STR && enc->v.str->len > 0 && !unknown_encoding &&
|
||||
!(enc->v.str->len == 4 && memcmp(enc->v.str->data, "utf8", 4) == 0) &&
|
||||
!(enc->v.str->len == 5 && memcmp(enc->v.str->data, "utf-8", 5) == 0);
|
||||
if (enc) scr_dyn_release(enc);
|
||||
if (buffer) {
|
||||
static const char m[] = "Unknown encoding: buffer";
|
||||
scr_throw_error_msg_code(SCR_ERR_TYPE, m, sizeof m - 1, "ERR_UNKNOWN_ENCODING");
|
||||
} else if (other) {
|
||||
if (other) {
|
||||
scr_fss_unsupported("the WriteStream option 'encoding' is not supported yet (utf8, the default, is the write-side string encoding)");
|
||||
}
|
||||
if (buffer || other) {
|
||||
scr_stream_release(s);
|
||||
s = NULL;
|
||||
goto fail;
|
||||
@@ -592,6 +588,15 @@ static ScrStream *scr_fss_new(const ScrDyn *path, const ScrDyn *opts_in, bool re
|
||||
}
|
||||
scr_stream_set_destroy(s, scr_fss_hook((void *)&scr_fss_destroy), &scr_fss_destroy);
|
||||
scr_stream_construct(s, scr_fss_hook((void *)&scr_fss_construct), &scr_fss_construct);
|
||||
if (unknown_encoding) {
|
||||
/* Node's constructor has already scheduled _construct when
|
||||
* setDefaultEncoding throws, so the unreachable stream still opens
|
||||
* (and with the default 'w' flags truncates) its file. */
|
||||
static const char m[] = "Unknown encoding: buffer";
|
||||
scr_throw_error_msg_code(SCR_ERR_TYPE, m, sizeof m - 1, "ERR_UNKNOWN_ENCODING");
|
||||
scr_stream_release(s);
|
||||
s = NULL;
|
||||
}
|
||||
fail:
|
||||
if (f) scr_fss_free(f);
|
||||
if (owner) owner_ops->release(owner);
|
||||
|
||||
@@ -114,7 +114,9 @@ function check(label, fn) {
|
||||
check("start negative", () => fs.createWriteStream(file, { start: -1 }));
|
||||
check("path null", () => fs.createWriteStream(null));
|
||||
check("fd string", () => fs.createWriteStream(file, { fd: "3" }));
|
||||
check("encoding buffer", () => fs.createWriteStream(file, { encoding: "buffer" }));
|
||||
// Node's constructor throws here after scheduling the open, so the
|
||||
// stream still opens (and truncates) its file later: keep it off `file`.
|
||||
check("encoding buffer", () => fs.createWriteStream(path.join(dir, "unknown-encoding.txt"), { encoding: "buffer" }));
|
||||
check("hwm string", () => fs.createWriteStream(file, { highWaterMark: "4" }));
|
||||
{
|
||||
const log = [];
|
||||
@@ -134,5 +136,6 @@ function check(label, fn) {
|
||||
await new Promise((resolve) => ws.on("close", () => resolve(report("pipe", [], ws.bytesWritten, ws.pending))));
|
||||
console.log("piped", fs.statSync(file).size);
|
||||
}
|
||||
console.log("unknown-encoding stream opened its file", fs.existsSync(path.join(dir, "unknown-encoding.txt")));
|
||||
fs.rmSync(dir, { recursive: true });
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user