c: get-output-string + write-char honor binary data on string ports
Two pre-existing defects in c/builtins.c made (open-output-string) unusable for binary emit: - bi_get_output_string ran the buffer through make_string_from_cstr, which calls strlen. Any 0x00 in the payload truncated body at that byte. Use port's known str_len directly via make_string. - bi_write_char ignored string-port destinations entirely — it pulled AS_PORT(p)->fp (NULL for string ports), fell back to stdout, and silently routed gate bytes to terminal output instead of the port buffer. Route to port_write_str when target port kind is PORT_STRING, matching bi_write_string's behavior. Surfaced while validating the precise-GC fix against ecdsa's Phase B emit (writes 56-byte op records full of embedded nulls through a string-output port, get-output-string at the end). With these fixes ecdsa's n+1=64 emit drops a 333 MB binary in 42.6 seconds — pre-fix it timed out at 600 s with a 17-byte header-only file (strlen truncated body at byte 1; the visible gate bytes had been escaping to stdout the whole time). Binary roundtrip test (write n bytes alternating x / 0x00 to output-string port, read back via get-output-string): n=10 len=10 ok n=1000 len=1000 ok n=100000 len=100000 ok All upstream tests still pass (88/88 c-test, 4/4 regression, 205/205 functional, zoe across tiers).
This commit is contained in:
parent
b841b30bc4
commit
269d3be756
1 changed files with 15 additions and 4 deletions
19
c/builtins.c
19
c/builtins.c
|
|
@ -1957,10 +1957,13 @@ static Value bi_open_output_string(Value *a, int n, Env *e) {
|
|||
}
|
||||
static Value bi_get_output_string(Value *a, int n, Env *e) {
|
||||
(void)e; CHECK_ARITY("get-output-string", 1);
|
||||
char *s = port_get_output_string(AS_PORT(a[0]));
|
||||
Value r = make_string_from_cstr(s);
|
||||
ul_free(s);
|
||||
return r;
|
||||
/* Use port's known str_len, not strlen — emitter writes binary
|
||||
* (op bytes with embedded 0x00). strlen truncates at first null. */
|
||||
ULPort *p = AS_PORT(a[0]);
|
||||
if (p->kind != PORT_STRING || p->dir != PORT_OUTPUT) {
|
||||
return make_string("", 0, false);
|
||||
}
|
||||
return make_string(p->str_buf, p->str_len, false);
|
||||
}
|
||||
static Value bi_close_port(Value *a, int n, Env *e) {
|
||||
(void)e; CHECK_ARITY("close-port", 1);
|
||||
|
|
@ -2360,6 +2363,14 @@ static Value bi_write_string(Value *a, int n, Env *e) {
|
|||
|
||||
static Value bi_write_char(Value *a, int n, Env *e) {
|
||||
(void)e; CHECK_MIN_ARITY("write-char", 1);
|
||||
/* Route to string-port buffer when target is a string port — without
|
||||
* this, write-char ignored string ports and wrote to stdout, breaking
|
||||
* binary emit through (open-output-string) accumulators. */
|
||||
if (n > 1 && IS_PORT(a[1]) && AS_PORT(a[1])->kind == PORT_STRING) {
|
||||
char ch = (char)AS_CHAR(a[0]);
|
||||
port_write_str(AS_PORT(a[1]), &ch, 1);
|
||||
return VAL_VOID;
|
||||
}
|
||||
FILE *out = n > 1 && IS_PORT(a[1]) ? AS_PORT(a[1])->fp : stdout;
|
||||
fputc(AS_CHAR(a[0]), out ? out : stdout);
|
||||
fflush(out ? out : stdout);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue