adding some simple provenance checks on return values

This commit is contained in:
Jakub Doka 2024-11-08 11:51:10 +01:00
parent 7d48d3beb1
commit a299bad75b
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
5 changed files with 126 additions and 89 deletions

File diff suppressed because one or more lines are too long

View file

@ -994,6 +994,14 @@ impl Nodes {
continue; continue;
} }
if self[class.1].outputs.iter().any(|&n| {
self[n].kind != Kind::Stre
&& self[n].outputs.iter().any(|&n| self[n].kind != Kind::Stre)
}) {
new_inps.push(n);
continue;
}
cursor = self[cursor].inputs[3]; cursor = self[cursor].inputs[3];
while cursor != MEM { while cursor != MEM {
debug_assert_eq!(self[cursor].kind, Kind::Stre); debug_assert_eq!(self[cursor].kind, Kind::Stre);
@ -1799,6 +1807,7 @@ pub struct Node {
loop_depth: Cell<LoopDepth>, loop_depth: Cell<LoopDepth>,
aclass: AClassId, aclass: AClassId,
antidep: Nid, antidep: Nid,
pos: Pos,
} }
impl Node { impl Node {
@ -2318,9 +2327,10 @@ impl<'a> Codegen<'a> {
self.ct.run(ret_loc, entry) self.ct.run(ret_loc, entry)
} }
fn new_stack(&mut self, ty: ty::Id) -> Nid { fn new_stack(&mut self, pos: Pos, ty: ty::Id) -> Nid {
let stck = self.ci.nodes.new_node_nop(ty, Kind::Stck, [VOID, MEM]); let stck = self.ci.nodes.new_node_nop(ty, Kind::Stck, [VOID, MEM]);
self.ci.nodes[stck].aclass = self.ci.scope.aclasses.len() as _; self.ci.nodes[stck].aclass = self.ci.scope.aclasses.len() as _;
self.ci.nodes[stck].pos = pos;
self.ci.scope.aclasses.push(AClass::new(&mut self.ci.nodes)); self.ci.scope.aclasses.push(AClass::new(&mut self.ci.nodes));
stck stck
} }
@ -2452,7 +2462,7 @@ impl<'a> Codegen<'a> {
Loc::Reg => Some(self.ci.nodes.new_const_lit(oty, 0)), Loc::Reg => Some(self.ci.nodes.new_const_lit(oty, 0)),
Loc::Stack => { Loc::Stack => {
let OptLayout { flag_ty, flag_offset, .. } = self.tys.opt_layout(ty); let OptLayout { flag_ty, flag_offset, .. } = self.tys.opt_layout(ty);
let stack = self.new_stack(oty); let stack = self.new_stack(pos, oty);
let offset = self.offset(stack, flag_offset); let offset = self.offset(stack, flag_offset);
let value = self.ci.nodes.new_const(flag_ty, 0); let value = self.ci.nodes.new_const(flag_ty, 0);
self.store_mem(offset, flag_ty, value); self.store_mem(offset, flag_ty, value);
@ -2464,7 +2474,7 @@ impl<'a> Codegen<'a> {
inference!(ty, ctx, self, pos, "value", "@as(<ty>, idk)"); inference!(ty, ctx, self, pos, "value", "@as(<ty>, idk)");
if ty.loc(self.tys) == Loc::Stack { if ty.loc(self.tys) == Loc::Stack {
Some(Value::ptr(self.new_stack(ty)).ty(ty)) Some(Value::ptr(self.new_stack(pos, ty)).ty(ty))
} else { } else {
Some(self.ci.nodes.new_const_lit(ty, 0)) Some(self.ci.nodes.new_const_lit(ty, 0))
} }
@ -2562,6 +2572,8 @@ impl<'a> Codegen<'a> {
&mut self.ci.nodes, &mut self.ci.nodes,
); );
self.ci.nodes[self.ci.ctrl.get()].pos = pos;
self.ci.nodes[NEVER].inputs.push(self.ci.ctrl.get()); self.ci.nodes[NEVER].inputs.push(self.ci.ctrl.get());
self.ci.nodes[self.ci.ctrl.get()].outputs.push(NEVER); self.ci.nodes[self.ci.ctrl.get()].outputs.push(NEVER);
} else if let Some((pv, ctrl, scope)) = &mut self.ci.inline_ret { } else if let Some((pv, ctrl, scope)) = &mut self.ci.inline_ret {
@ -2661,7 +2673,7 @@ impl<'a> Codegen<'a> {
Some(Value::ptr(self.offset(vtarget.id, offset)).ty(ty)) Some(Value::ptr(self.offset(vtarget.id, offset)).ty(ty))
} }
Expr::UnOp { op: TokenKind::Band, val, .. } => { Expr::UnOp { op: TokenKind::Band, val, pos } => {
let ctx = Ctx { ty: ctx.ty.and_then(|ty| self.tys.base_of(ty)) }; let ctx = Ctx { ty: ctx.ty.and_then(|ty| self.tys.base_of(ty)) };
let mut val = self.raw_expr_ctx(val, ctx)?; let mut val = self.raw_expr_ctx(val, ctx)?;
@ -2673,7 +2685,7 @@ impl<'a> Codegen<'a> {
return Some(val); return Some(val);
} }
let stack = self.new_stack(val.ty); let stack = self.new_stack(pos, val.ty);
self.store_mem(stack, val.ty, val.id); self.store_mem(stack, val.ty, val.id);
Some(Value::new(stack).ty(self.tys.make_ptr(val.ty))) Some(Value::new(stack).ty(self.tys.make_ptr(val.ty)))
@ -2710,11 +2722,11 @@ impl<'a> Codegen<'a> {
Value::NEVER Value::NEVER
} }
} }
Expr::BinOp { left, op: TokenKind::Decl, right, .. } => { Expr::BinOp { left, op: TokenKind::Decl, right, pos } => {
let mut right = self.expr(right)?; let mut right = self.expr(right)?;
if right.ty.loc(self.tys) == Loc::Stack { if right.ty.loc(self.tys) == Loc::Stack {
let stck = self.new_stack(right.ty); let stck = self.new_stack(pos, right.ty);
self.store_mem(stck, right.ty, right.id); self.store_mem(stck, right.ty, right.id);
right.id = stck; right.id = stck;
right.ptr = true; right.ptr = true;
@ -2807,7 +2819,7 @@ impl<'a> Codegen<'a> {
let mut rhs = rhs?; let mut rhs = rhs?;
self.strip_var(&mut rhs); self.strip_var(&mut rhs);
self.assert_ty(pos, &mut rhs, lhs.ty, "struct operand"); self.assert_ty(pos, &mut rhs, lhs.ty, "struct operand");
let dst = self.new_stack(lhs.ty); let dst = self.new_stack(pos, lhs.ty);
self.struct_op(left.pos(), op, s, dst, lhs.id, rhs.id); self.struct_op(left.pos(), op, s, dst, lhs.id, rhs.id);
Some(Value::ptr(dst).ty(lhs.ty)) Some(Value::ptr(dst).ty(lhs.ty))
} }
@ -2906,7 +2918,7 @@ impl<'a> Codegen<'a> {
match ty.loc(self.tys) { match ty.loc(self.tys) {
Loc::Reg if mem::take(&mut val.ptr) => val.id = self.load_mem(val.id, ty), Loc::Reg if mem::take(&mut val.ptr) => val.id = self.load_mem(val.id, ty),
Loc::Stack if !val.ptr => { Loc::Stack if !val.ptr => {
let stack = self.new_stack(ty); let stack = self.new_stack(pos, ty);
self.store_mem(stack, val.ty, val.id); self.store_mem(stack, val.ty, val.id);
val.id = stack; val.id = stack;
val.ptr = true; val.ptr = true;
@ -3074,7 +3086,7 @@ impl<'a> Codegen<'a> {
let alt_value = match ty.loc(self.tys) { let alt_value = match ty.loc(self.tys) {
Loc::Reg => None, Loc::Reg => None,
Loc::Stack => { Loc::Stack => {
let stck = self.new_stack(ty); let stck = self.new_stack(pos, ty);
inps.push(stck); inps.push(stck);
Some(Value::ptr(stck).ty(ty)) Some(Value::ptr(stck).ty(ty))
} }
@ -3151,7 +3163,7 @@ impl<'a> Codegen<'a> {
let alt_value = match sig.ret.loc(self.tys) { let alt_value = match sig.ret.loc(self.tys) {
Loc::Reg => None, Loc::Reg => None,
Loc::Stack => { Loc::Stack => {
let stck = self.new_stack(sig.ret); let stck = self.new_stack(func.pos(), sig.ret);
inps.push(stck); inps.push(stck);
Some(Value::ptr(stck).ty(sig.ret)) Some(Value::ptr(stck).ty(sig.ret))
} }
@ -3298,7 +3310,7 @@ impl<'a> Codegen<'a> {
match sty.expand() { match sty.expand() {
ty::Kind::Struct(s) => { ty::Kind::Struct(s) => {
let mem = self.new_stack(sty); let mem = self.new_stack(pos, sty);
let mut offs = OffsetIter::new(s, self.tys); let mut offs = OffsetIter::new(s, self.tys);
for field in fields { for field in fields {
let Some((ty, offset)) = offs.next_ty(self.tys) else { let Some((ty, offset)) = offs.next_ty(self.tys) else {
@ -3352,7 +3364,7 @@ impl<'a> Codegen<'a> {
return Value::NEVER; return Value::NEVER;
} }
let mem = self.new_stack(aty); let mem = self.new_stack(pos, aty);
for (field, offset) in for (field, offset) in
fields.iter().zip((0u32..).step_by(elem_size as usize)) fields.iter().zip((0u32..).step_by(elem_size as usize))
@ -3407,7 +3419,7 @@ impl<'a> Codegen<'a> {
.into_iter(self.tys) .into_iter(self.tys)
.map(|(f, o)| (f.ty, o)) .map(|(f, o)| (f.ty, o))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let mem = self.new_stack(sty); let mem = self.new_stack(pos, sty);
for field in fields { for field in fields {
let Some(index) = self.tys.find_struct_field(s, field.name) else { let Some(index) = self.tys.find_struct_field(s, field.name) else {
self.report( self.report(
@ -4199,6 +4211,23 @@ impl<'a> Codegen<'a> {
self.ci.unlock(); self.ci.unlock();
for &node in self.ci.nodes[NEVER].inputs.iter() {
if self.ci.nodes[node].kind == Kind::Return
&& self.ci.nodes[self.ci.nodes.aclass_index(self.ci.nodes[node].inputs[1]).1].kind
== Kind::Stck
{
self.report(
self.ci.nodes[node].pos,
"returning value with local provenance \
(pointer will be invalid after function returns)",
);
self.report(
self.ci.nodes[self.ci.nodes.aclass_index(self.ci.nodes[node].inputs[1]).1].pos,
"...the pointer points to stack allocation created here",
);
}
}
if self.errors.borrow().len() == prev_err_len { if self.errors.borrow().len() == prev_err_len {
self.ci.nodes.check_final_integrity(self.ty_display(ty::Id::VOID)); self.ci.nodes.check_final_integrity(self.ty_display(ty::Id::VOID));
self.ci.nodes.graphviz(self.ty_display(ty::Id::VOID)); self.ci.nodes.graphviz(self.ty_display(ty::Id::VOID));
@ -4265,7 +4294,7 @@ impl<'a> Codegen<'a> {
} }
} }
fn wrap_in_opt(&mut self, val: &mut Value) { fn wrap_in_opt(&mut self, pos: Pos, val: &mut Value) {
debug_assert!(!val.var); debug_assert!(!val.var);
let was_ptr = val.ptr; let was_ptr = val.ptr;
@ -4294,7 +4323,7 @@ impl<'a> Codegen<'a> {
} }
Loc::Stack => { Loc::Stack => {
self.strip_ptr(val); self.strip_ptr(val);
let stack = self.new_stack(oty); let stack = self.new_stack(pos, oty);
let fill = self.ci.nodes.new_const(flag_ty, 1); let fill = self.ci.nodes.new_const(flag_ty, 1);
self.store_mem(stack, flag_ty, fill); self.store_mem(stack, flag_ty, fill);
let off = self.offset(stack, payload_offset); let off = self.offset(stack, payload_offset);
@ -4394,7 +4423,7 @@ impl<'a> Codegen<'a> {
if inner != src.ty { if inner != src.ty {
self.assert_ty(pos, src, inner, hint); self.assert_ty(pos, src, inner, hint);
} }
self.wrap_in_opt(src); self.wrap_in_opt(pos, src);
} else { } else {
debug_assert!( debug_assert!(
src.ty.is_integer() || src.ty == ty::Id::NEVER, src.ty.is_integer() || src.ty == ty::Id::NEVER,
@ -4609,6 +4638,7 @@ mod tests {
fb_driver; fb_driver;
// Purely Testing Examples; // Purely Testing Examples;
stack_provenance;
advanced_floating_point_arithmetic; advanced_floating_point_arithmetic;
nullable_structure; nullable_structure;
needless_unwrap; needless_unwrap;

View file

@ -1,7 +1,5 @@
get_ptr: get_ptr:
ADDI64 r254, r254, -8d LI64 r1, 0d
ADDI64 r1, r254, 0d
ADDI64 r254, r254, 8d
JALA r0, r31, 0a JALA r0, r31, 0a
main: main:
ADDI64 r254, r254, -40d ADDI64 r254, r254, -40d
@ -21,6 +19,6 @@ main:
1: LD r31, r254, 0a, 40h 1: LD r31, r254, 0a, 40h
ADDI64 r254, r254, 40d ADDI64 r254, r254, 40d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 208 code size: 185
ret: 10 ret: 0
status: Ok(()) status: Ok(())

View file

@ -2,8 +2,8 @@ decide:
LI8 r1, 1b LI8 r1, 1b
JALA r0, r31, 0a JALA r0, r31, 0a
main: main:
ADDI64 r254, r254, -224d ADDI64 r254, r254, -232d
ST r31, r254, 80a, 144h ST r31, r254, 80a, 152h
JAL r31, r0, :decide JAL r31, r0, :decide
LI64 r32, 0d LI64 r32, 0d
ADDI64 r2, r254, 72d ADDI64 r2, r254, 72d
@ -13,52 +13,54 @@ main:
CP r34, r32 CP r34, r32
JMP :1 JMP :1
0: CP r34, r33 0: CP r34, r33
1: JNE r34, r32, :2 1: LI64 r35, 1d
ST r35, r254, 72a, 8h
JNE r34, r32, :2
LI64 r1, 9001d LI64 r1, 9001d
JMP :3 JMP :3
2: JAL r31, r0, :decide 2: JAL r31, r0, :decide
LI8 r35, 0b LI8 r36, 0b
ANDI r1, r1, 255d ANDI r1, r1, 255d
JNE r1, r0, :4 JNE r1, r0, :4
LI8 r36, 1b LI8 r37, 1b
ST r36, r254, 56a, 1h ST r37, r254, 56a, 1h
LD r36, r34, 0a, 8h LD r37, r34, 0a, 8h
ST r36, r254, 64a, 8h ST r37, r254, 64a, 8h
JMP :5 JMP :5
4: ST r35, r254, 56a, 1h 4: ST r36, r254, 56a, 1h
5: LD r37, r254, 56a, 1h 5: LD r38, r254, 56a, 1h
ANDI r37, r37, 255d ANDI r38, r38, 255d
ANDI r35, r35, 255d ANDI r36, r36, 255d
JEQ r37, r35, :6 JEQ r38, r36, :6
LI64 r1, 42d LI64 r1, 42d
JMP :3 JMP :3
6: JAL r31, r0, :decide 6: JAL r31, r0, :decide
LI32 r38, 0w LI32 r39, 0w
ANDI r1, r1, 255d ANDI r1, r1, 255d
JNE r1, r0, :7 JNE r1, r0, :7
CP r39, r38 CP r40, r39
JMP :8 JMP :8
7: LI32 r39, 2147483649w 7: LI32 r40, 2147483649w
8: ANDI r39, r39, 4294967295d 8: ANDI r40, r40, 4294967295d
ANDI r38, r38, 4294967295d ANDI r39, r39, 4294967295d
JNE r39, r38, :9 JNE r40, r39, :9
LI64 r1, 69d LI64 r1, 69d
JMP :3 JMP :3
9: ADDI64 r3, r254, 40d 9: ADDI64 r3, r254, 40d
CP r40, r3 CP r41, r3
JAL r31, r0, :new_foo JAL r31, r0, :new_foo
ST r1, r254, 40a, 16h ST r1, r254, 40a, 16h
LI64 r32, 0d LI64 r42, 0d
LD r41, r254, 40a, 8h LD r43, r254, 40a, 8h
JNE r41, r32, :10 JNE r43, r42, :10
LI64 r1, 999d LI64 r1, 999d
JMP :3 JMP :3
10: LRA r4, r0, :"foo\0" 10: LRA r4, r0, :"foo\0"
CP r3, r40 CP r3, r41
CP r2, r3 CP r2, r3
LD r2, r2, 0a, 16h LD r2, r2, 0a, 16h
JAL r31, r0, :use_foo JAL r31, r0, :use_foo
ADDI64 r42, r254, 0d ADDI64 r44, r254, 0d
JAL r31, r0, :no_foo JAL r31, r0, :no_foo
ST r1, r254, 0a, 16h ST r1, r254, 0a, 16h
JAL r31, r0, :decide JAL r31, r0, :decide
@ -68,11 +70,9 @@ main:
JMP :12 JMP :12
11: CP r2, r33 11: CP r2, r33
ST r2, r254, 0a, 8h ST r2, r254, 0a, 8h
LI64 r43, 1d ST r35, r254, 8a, 8h
ST r43, r254, 8a, 8h 12: LD r45, r254, 0a, 8h
ST r43, r254, 72a, 8h JNE r45, r42, :13
12: LD r44, r254, 0a, 8h
JNE r44, r32, :13
LI64 r1, 34d LI64 r1, 34d
JMP :3 JMP :3
13: ADDI64 r1, r254, 16d 13: ADDI64 r1, r254, 16d
@ -81,19 +81,19 @@ main:
ANDI r1, r1, 255d ANDI r1, r1, 255d
JNE r1, r0, :14 JNE r1, r0, :14
JMP :15 JMP :15
14: ST r35, r254, 16a, 1h 14: ST r36, r254, 16a, 1h
15: LD r45, r254, 16a, 1h 15: LD r46, r254, 16a, 1h
ANDI r45, r45, 255d ANDI r46, r46, 255d
ANDI r35, r35, 255d ANDI r36, r36, 255d
JEQ r45, r35, :16 JEQ r46, r36, :16
LI64 r1, 420d LI64 r1, 420d
JMP :3 JMP :3
16: LD r46, r254, 0a, 8h 16: LD r47, r254, 0a, 8h
LD r47, r46, 0a, 8h LD r48, r47, 0a, 8h
ANDI r48, r39, 65535d ANDI r49, r40, 65535d
SUB64 r1, r48, r47 SUB64 r1, r49, r48
3: LD r31, r254, 80a, 144h 3: LD r31, r254, 80a, 152h
ADDI64 r254, r254, 224d ADDI64 r254, r254, 232d
JALA r0, r31, 0a JALA r0, r31, 0a
new_bar: new_bar:
ADDI64 r254, r254, -24d ADDI64 r254, r254, -24d

View file

@ -0,0 +1,6 @@
test.hb:5:23: returning value with local provenance (pointer will be invalid after function returns)
dangle := fn(): ^uint return &0
^
test.hb:5:30: ...the pointer points to stack allocation created here
dangle := fn(): ^uint return &0
^