feat: replace M4 callback writers with safe handles
This commit is contained in:
+6
-15
@@ -375,9 +375,8 @@ static void check_format_call(FeCheckerState *s, FeNode *n)
|
||||
if (offset) {
|
||||
if (!fmt_node) { err(s->c,n->loc,"@fprint requires a writer"); return; }
|
||||
t=check_expr(s,fmt_node);
|
||||
if (!(t && t->kind==FE_TYPE_REF && t->ref_mut &&
|
||||
format_is_writer_type(t->elem)))
|
||||
err(s->c,fmt_node->loc,"@fprint requires &mut io.Writer");
|
||||
if (!format_is_writer_type(t))
|
||||
err(s->c,fmt_node->loc,"@fprint requires io.Writer");
|
||||
fmt_node=fmt_node->next;
|
||||
}
|
||||
if (strcmp(n->text,"@sprint")==0) {
|
||||
@@ -679,18 +678,9 @@ static FeType *check_expr(FeCheckerState *s, FeNode *n)
|
||||
if (n->a && n->a->kind==FE_N_MEMBER && n->a->a &&
|
||||
n->a->a->kind==FE_N_IDENT && n->a->a->text &&
|
||||
strcmp(n->a->a->text,"io")==0 && n->a->b && n->a->b->text &&
|
||||
(strcmp(n->a->b->text,"buf_writer")==0 ||
|
||||
strcmp(n->a->b->text,"null_writer")==0)) {
|
||||
strcmp(n->a->b->text,"null_writer")==0) {
|
||||
FeNode *arg=n->children;
|
||||
if (strcmp(n->a->b->text,"buf_writer")==0) {
|
||||
if (!arg) err(c,n->loc,"io.buf_writer requires a buffer");
|
||||
else {
|
||||
a=check_expr(s,arg);
|
||||
if (!(a && a->kind==FE_TYPE_REF && a->ref_mut &&
|
||||
format_is_slice_u8(a->elem)))
|
||||
err(c,arg->loc,"io.buf_writer requires &mut []u8 buffer");
|
||||
}
|
||||
} else if (arg) err(c,n->loc,"io.null_writer takes no arguments");
|
||||
if (arg) err(c,n->loc,"io.null_writer takes no arguments");
|
||||
n->sem_type=fe_type_intern(&c->types,"io.Writer");
|
||||
return n->sem_type;
|
||||
}
|
||||
@@ -760,7 +750,8 @@ static FeType *check_expr(FeCheckerState *s, FeNode *n)
|
||||
if (n->kind == FE_N_MEMBER) {
|
||||
if (n->a && n->a->kind==FE_N_IDENT && n->a->text &&
|
||||
strcmp(n->a->text,"io")==0 && n->b && n->b->text &&
|
||||
strcmp(n->b->text,"stdout")==0) {
|
||||
(strcmp(n->b->text,"stdout")==0 ||
|
||||
strcmp(n->b->text,"stderr")==0)) {
|
||||
n->sem_type=fe_type_intern(&c->types,"io.Writer");
|
||||
return n->sem_type;
|
||||
}
|
||||
|
||||
+12
-21
@@ -251,22 +251,20 @@ static void emit_type_helpers(FeEmitter *e)
|
||||
static void emit_m4_runtime(FeEmitter *e)
|
||||
{
|
||||
fputs("typedef struct { unsigned char *p; unsigned long n; } fe_m4_slice;\n",e->out);
|
||||
fputs("typedef struct { void *ctx; unsigned short (*write_fn)(void *, const unsigned char *, unsigned long); } fe_writer;\n",e->out);
|
||||
fputs("typedef struct { unsigned char tag; unsigned short handle; } fe_writer;\n",e->out);
|
||||
fputs("unsigned short fe_m4_error;\n",e->out);
|
||||
fputs("unsigned short fe_m4_stdout_write(void *ctx, const unsigned char *p, unsigned long n) { (void)ctx; return fwrite(p,1,(size_t)n,stdout)==(size_t)n ? 0 : 1; }\n",e->out);
|
||||
fputs("unsigned short fe_m4_null_write(void *ctx, const unsigned char *p, unsigned long n) { (void)ctx; (void)p; (void)n; return 0; }\n",e->out);
|
||||
fputs("unsigned short fe_m4_buf_write(void *ctx, const unsigned char *p, unsigned long n) { fe_m4_slice *b=(fe_m4_slice*)ctx; unsigned long k=n<b->n?n:b->n; if(k) memcpy(b->p,p,(size_t)k); b->p+=k; b->n-=k; return 0; }\n",e->out);
|
||||
fputs("fe_writer fe_m4_stdout_writer(void) { fe_writer w; w.ctx=0; w.write_fn=fe_m4_stdout_write; return w; }\n",e->out);
|
||||
fputs("fe_writer fe_m4_null_writer(void) { fe_writer w; w.ctx=0; w.write_fn=fe_m4_null_write; return w; }\n",e->out);
|
||||
fputs("fe_writer fe_m4_buf_writer(fe_m4_slice *b) { fe_writer w; w.ctx=b; w.write_fn=fe_m4_buf_write; return w; }\n",e->out);
|
||||
fputs("fe_writer fe_m4_writer(unsigned char tag, unsigned short handle) { fe_writer w; w.tag=tag; w.handle=handle; return w; }\n",e->out);
|
||||
fputs("fe_writer fe_m4_stdout_writer(void) { return fe_m4_writer(0,1); }\n",e->out);
|
||||
fputs("fe_writer fe_m4_stderr_writer(void) { return fe_m4_writer(1,2); }\n",e->out);
|
||||
fputs("fe_writer fe_m4_null_writer(void) { return fe_m4_writer(3,0); }\n",e->out);
|
||||
fputs("/* bounded sprint stack; overflow traps instead of corrupting an outer call */\n#define FE_M4_SPRINT_DEPTH 8\n",e->out);
|
||||
fputs("typedef struct { fe_m4_slice b; unsigned long start_n; } fe_m4_sprint_frame;\n",e->out);
|
||||
fputs("static fe_m4_sprint_frame fe_m4_sprint_stack[FE_M4_SPRINT_DEPTH];\n",e->out);
|
||||
fputs("static unsigned fe_m4_sprint_depth;\n",e->out);
|
||||
fputs("void fe_m4_sprint_begin(fe_m4_slice *b) { if (fe_m4_sprint_depth>=FE_M4_SPRINT_DEPTH) abort(); fe_m4_sprint_stack[fe_m4_sprint_depth].b=*b; fe_m4_sprint_stack[fe_m4_sprint_depth].start_n=b->n; ++fe_m4_sprint_depth; }\n",e->out);
|
||||
fputs("fe_writer fe_m4_sprint_writer(void) { return fe_m4_buf_writer(&fe_m4_sprint_stack[fe_m4_sprint_depth-1].b); }\n",e->out);
|
||||
fputs("fe_writer fe_m4_sprint_writer(void) { return fe_m4_writer(4,(unsigned short)(fe_m4_sprint_depth-1)); }\n",e->out);
|
||||
fputs("unsigned long fe_m4_sprint_finish(void) { unsigned long result; if (!fe_m4_sprint_depth) abort(); --fe_m4_sprint_depth; result=fe_m4_sprint_stack[fe_m4_sprint_depth].start_n-fe_m4_sprint_stack[fe_m4_sprint_depth].b.n; return result; }\n",e->out);
|
||||
fputs("unsigned short fe_m4_write_bytes(fe_writer w, const unsigned char *p, unsigned long n) { return w.write_fn ? w.write_fn(w.ctx,p,n) : 1; }\n",e->out);
|
||||
fputs("unsigned short fe_m4_write_bytes(fe_writer w, const unsigned char *p, unsigned long n) { if(w.tag==0) return fwrite(p,1,(size_t)n,stdout)==(size_t)n?0:1; if(w.tag==1) return fwrite(p,1,(size_t)n,stderr)==(size_t)n?0:1; if(w.tag==3) return 0; if(w.tag==4 && w.handle<FE_M4_SPRINT_DEPTH) { fe_m4_slice *b=&fe_m4_sprint_stack[w.handle].b; unsigned long k=n<b->n?n:b->n; if(k) memcpy(b->p,p,(size_t)k); b->p+=k; b->n-=k; return 0; } return 1; }\n",e->out);
|
||||
fputs("unsigned short fe_m4_write_cstr(fe_writer w, const char *p) { return fe_m4_write_bytes(w,(const unsigned char*)p,(unsigned long)strlen(p)); }\n",e->out);
|
||||
fputs("#define fe_m4_write_slice(w,s) fe_m4_write_bytes((w),(s).p,(s).n)\n",e->out);
|
||||
fputs("unsigned short fe_m4_write_int(fe_writer w, long v) { char b[40]; sprintf(b,\"%ld\",v); return fe_m4_write_cstr(w,b); }\n",e->out);
|
||||
@@ -456,13 +454,8 @@ static void emit_m4_piece(FILE *out, const char *fmt, unsigned long begin,
|
||||
|
||||
static void emit_m4_writer(FeEmitter *e, FeNode *arg, int buffer)
|
||||
{
|
||||
if (buffer) {
|
||||
fputs("fe_m4_buf_writer((fe_m4_slice*)&",e->out);
|
||||
if (arg && arg->kind==FE_N_UNARY && arg->text &&
|
||||
(strcmp(arg->text,"&")==0 || strcmp(arg->text,"&mut")==0)) emit_expr(e,arg->a);
|
||||
else emit_expr(e,arg);
|
||||
fputs(")",e->out);
|
||||
} else if (arg && arg->kind==FE_N_UNARY && arg->text &&
|
||||
(void)buffer;
|
||||
if (arg && arg->kind==FE_N_UNARY && arg->text &&
|
||||
(strcmp(arg->text,"&")==0 || strcmp(arg->text,"&mut")==0)) {
|
||||
emit_expr(e,arg->a);
|
||||
} else if (arg && arg->kind==FE_N_CALL && arg->a &&
|
||||
@@ -817,10 +810,6 @@ static void emit_expr(FeEmitter *e, FeNode *n)
|
||||
fputs("()",e->out);
|
||||
special=1;
|
||||
}
|
||||
else if(n->a && n->a->kind==FE_N_MEMBER && n->a->a &&
|
||||
n->a->a->kind==FE_N_IDENT && n->a->a->text &&
|
||||
strcmp(n->a->a->text,"io")==0 && n->a->b && n->a->b->text &&
|
||||
strcmp(n->a->b->text,"buf_writer")==0 && n->children) { emit_m4_writer(e,n->children,1); special=1; }
|
||||
else if(n->a && n->a->kind==FE_N_MEMBER && n->a->a &&
|
||||
n->a->a->kind==FE_N_IDENT && n->a->a->text &&
|
||||
strcmp(n->a->a->text,"io")==0 && n->a->b && n->a->b->text &&
|
||||
@@ -861,7 +850,9 @@ static void emit_expr(FeEmitter *e, FeNode *n)
|
||||
FeVariantType *v;
|
||||
if(n->a && n->a->kind==FE_N_IDENT && n->a->text &&
|
||||
strcmp(n->a->text,"io")==0 && n->b && n->b->text &&
|
||||
strcmp(n->b->text,"stdout")==0) fputs("fe_m4_stdout_writer()",e->out);
|
||||
(strcmp(n->b->text,"stdout")==0 || strcmp(n->b->text,"stderr")==0))
|
||||
fputs(strcmp(n->b->text,"stderr")==0 ?
|
||||
"fe_m4_stderr_writer()" : "fe_m4_stdout_writer()",e->out);
|
||||
else if(n->a && n->a->sem_type && n->a->sem_type->kind==FE_TYPE_REF &&
|
||||
n->b && n->b->text && strcmp(n->b->text,"^")==0) {
|
||||
fputs("(*",e->out); emit_expr(e,n->a); fputs(")",e->out);
|
||||
|
||||
+5
-3
@@ -1,4 +1,6 @@
|
||||
unit fmt;
|
||||
pub fn write_str(w: &mut io.Writer, s: str) -> !void;
|
||||
pub fn write_int_i32(w: &mut io.Writer, v: i32) -> !void;
|
||||
pub fn write_bool(w: &mut io.Writer, v: bool) -> !void;
|
||||
pub fn fmt_int_i32(buf: []mut u8, v: i32) -> str;
|
||||
pub fn fmt_hex_i32(buf: []mut u8, v: i32) -> str;
|
||||
pub fn fmt_char(buf: []mut u8, v: char) -> str;
|
||||
pub fn fmt_bool(buf: []mut u8, v: bool) -> str;
|
||||
pub fn fmt_error(buf: []mut u8, v: core.Error) -> str;
|
||||
|
||||
+6
-5
@@ -1,9 +1,10 @@
|
||||
unit io;
|
||||
pub struct Writer {
|
||||
ctx: *void,
|
||||
write_fn: fn(*void, []u8) -> !usize,
|
||||
}
|
||||
pub enum Writer { Stdout, Stderr, File(u16), Null }
|
||||
pub enum Reader { Stdin, File(u16) }
|
||||
pub fn write(w: Writer, bytes: []u8) -> !usize;
|
||||
pub fn read(r: Reader, bytes: []mut u8) -> !usize;
|
||||
pub struct File {
|
||||
handle: u16,
|
||||
pub fn close(self: &mut Self) { }
|
||||
pub fn close(self: Self) -> !void;
|
||||
pub fn drop(self: &mut Self) { }
|
||||
}
|
||||
|
||||
@@ -237,6 +237,8 @@ fec.exe --target=bits32 --emit-c TESTS\M4\BAD-TRY.FE -o TESTS\M4\BAD-TRY.C > nul
|
||||
if not errorlevel 1 goto test_fail
|
||||
fec.exe --target=bits32 --emit-c TESTS\M4\BAD-WRIT.FE -o TESTS\M4\BAD-WRI.C > nul
|
||||
if not errorlevel 1 goto test_fail
|
||||
fec.exe --target=bits32 --emit-c TESTS\M4\BAD-BUFW.FE -o TESTS\M4\BAD-BUFW.C > nul
|
||||
if not errorlevel 1 goto test_fail
|
||||
fec.exe --target=bits32 --emit-c TESTS\M4\BAD-MANY.FE -o TESTS\M4\BAD-MANY.C > nul
|
||||
if not errorlevel 1 goto test_fail
|
||||
fec.exe --target=bits32 --emit-c TESTS\M4\BAD-OPEN.FE -o TESTS\M4\BAD-OPEN.C > nul
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
unit m4_bad_buffer_writer;
|
||||
|
||||
fn main() -> void {
|
||||
var raw: [4]u8 = [0, 0, 0, 0];
|
||||
var buf: []mut u8 = raw[..];
|
||||
let w = io.buf_writer(buf);
|
||||
}
|
||||
@@ -2,6 +2,6 @@ unit m4_bad_writer;
|
||||
|
||||
fn main() -> i32 {
|
||||
var x: i32 = 0;
|
||||
@fprint(&mut x, "bad");
|
||||
@fprint(x, "bad");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -8,15 +8,15 @@ fn main() -> i32 {
|
||||
var raw3: [8]u8 = [0, 0, 0, 0, 0, 0, 0, 0];
|
||||
var raw4: [8]u8 = [0, 0, 0, 0, 0, 0, 0, 0];
|
||||
var raw5: [8]u8 = [0, 0, 0, 0, 0, 0, 0, 0];
|
||||
var buf: []u8 = raw[..];
|
||||
var buf2: []u8 = raw2[..];
|
||||
var buf3: []u8 = raw3[..];
|
||||
var buf4: []u8 = raw4[..];
|
||||
var buf5: []u8 = raw5[..];
|
||||
let w: io.Writer = io.buf_writer(&mut buf);
|
||||
var buf: []mut u8 = raw[..];
|
||||
var buf2: []mut u8 = raw2[..];
|
||||
var buf3: []mut u8 = raw3[..];
|
||||
var buf4: []mut u8 = raw4[..];
|
||||
var buf5: []mut u8 = raw5[..];
|
||||
let w: io.Writer = io.null_writer();
|
||||
const LOCAL_FMT: str = "value={}\n";
|
||||
@print(FMT, 7, 15, 'A', "yes", true);
|
||||
@fprint(&mut w, LOCAL_FMT, 12);
|
||||
@fprint(w, LOCAL_FMT, 12);
|
||||
let n: usize = @sprint(buf2, "A\x42\u0043defghi");
|
||||
let n2: usize = @sprint(buf3, "xy");
|
||||
let inner_n: usize = @sprint(buf4, "xy");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
unit m4_prop;
|
||||
|
||||
pub fn propagate(w: &mut io.Writer) -> !void {
|
||||
pub fn propagate(w: io.Writer) -> !void {
|
||||
try @fprint(w, "a{}b", 1);
|
||||
}
|
||||
|
||||
+4
-16
@@ -1,23 +1,11 @@
|
||||
#include "prop.c"
|
||||
|
||||
static unsigned short calls;
|
||||
|
||||
static unsigned short fail_write(void *ctx, const unsigned char *p,
|
||||
unsigned long n)
|
||||
{
|
||||
(void)ctx;
|
||||
(void)p;
|
||||
(void)n;
|
||||
++calls;
|
||||
return calls == 1 ? 7 : 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
fe_writer w;
|
||||
unsigned short result;
|
||||
w.ctx=0;
|
||||
w.write_fn=fail_write;
|
||||
result=fe_m4_prop_propagate(&w);
|
||||
return (result==7 && calls==1) ? 0 : 1;
|
||||
w.tag=2;
|
||||
w.handle=99;
|
||||
result=fe_m4_prop_propagate(w);
|
||||
return result==1 ? 0 : 1;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ unit m4_try_fprint;
|
||||
|
||||
fn main() -> !void {
|
||||
var raw: [4]u8 = [0, 0, 0, 0];
|
||||
var buf: []u8 = raw[..];
|
||||
let w: io.Writer = io.buf_writer(&mut buf);
|
||||
try @fprint(&mut w, "ok");
|
||||
var buf: []mut u8 = raw[..];
|
||||
let w: io.Writer = io.null_writer();
|
||||
try @fprint(w, "ok");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user