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;
}
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];
while cursor != MEM {
debug_assert_eq!(self[cursor].kind, Kind::Stre);
@ -1799,6 +1807,7 @@ pub struct Node {
loop_depth: Cell<LoopDepth>,
aclass: AClassId,
antidep: Nid,
pos: Pos,
}
impl Node {
@ -2318,9 +2327,10 @@ impl<'a> Codegen<'a> {
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]);
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));
stck
}
@ -2452,7 +2462,7 @@ impl<'a> Codegen<'a> {
Loc::Reg => Some(self.ci.nodes.new_const_lit(oty, 0)),
Loc::Stack => {
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 value = self.ci.nodes.new_const(flag_ty, 0);
self.store_mem(offset, flag_ty, value);
@ -2464,7 +2474,7 @@ impl<'a> Codegen<'a> {
inference!(ty, ctx, self, pos, "value", "@as(<ty>, idk)");
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 {
Some(self.ci.nodes.new_const_lit(ty, 0))
}
@ -2562,6 +2572,8 @@ impl<'a> Codegen<'a> {
&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[self.ci.ctrl.get()].outputs.push(NEVER);
} 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))
}
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 mut val = self.raw_expr_ctx(val, ctx)?;
@ -2673,7 +2685,7 @@ impl<'a> Codegen<'a> {
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);
Some(Value::new(stack).ty(self.tys.make_ptr(val.ty)))
@ -2710,11 +2722,11 @@ impl<'a> Codegen<'a> {
Value::NEVER
}
}
Expr::BinOp { left, op: TokenKind::Decl, right, .. } => {
Expr::BinOp { left, op: TokenKind::Decl, right, pos } => {
let mut right = self.expr(right)?;
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);
right.id = stck;
right.ptr = true;
@ -2807,7 +2819,7 @@ impl<'a> Codegen<'a> {
let mut rhs = rhs?;
self.strip_var(&mut rhs);
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);
Some(Value::ptr(dst).ty(lhs.ty))
}
@ -2906,7 +2918,7 @@ impl<'a> Codegen<'a> {
match ty.loc(self.tys) {
Loc::Reg if mem::take(&mut val.ptr) => val.id = self.load_mem(val.id, ty),
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);
val.id = stack;
val.ptr = true;
@ -3074,7 +3086,7 @@ impl<'a> Codegen<'a> {
let alt_value = match ty.loc(self.tys) {
Loc::Reg => None,
Loc::Stack => {
let stck = self.new_stack(ty);
let stck = self.new_stack(pos, ty);
inps.push(stck);
Some(Value::ptr(stck).ty(ty))
}
@ -3151,7 +3163,7 @@ impl<'a> Codegen<'a> {
let alt_value = match sig.ret.loc(self.tys) {
Loc::Reg => None,
Loc::Stack => {
let stck = self.new_stack(sig.ret);
let stck = self.new_stack(func.pos(), sig.ret);
inps.push(stck);
Some(Value::ptr(stck).ty(sig.ret))
}
@ -3298,7 +3310,7 @@ impl<'a> Codegen<'a> {
match sty.expand() {
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);
for field in fields {
let Some((ty, offset)) = offs.next_ty(self.tys) else {
@ -3352,7 +3364,7 @@ impl<'a> Codegen<'a> {
return Value::NEVER;
}
let mem = self.new_stack(aty);
let mem = self.new_stack(pos, aty);
for (field, offset) in
fields.iter().zip((0u32..).step_by(elem_size as usize))
@ -3407,7 +3419,7 @@ impl<'a> Codegen<'a> {
.into_iter(self.tys)
.map(|(f, o)| (f.ty, o))
.collect::<Vec<_>>();
let mem = self.new_stack(sty);
let mem = self.new_stack(pos, sty);
for field in fields {
let Some(index) = self.tys.find_struct_field(s, field.name) else {
self.report(
@ -4199,6 +4211,23 @@ impl<'a> Codegen<'a> {
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 {
self.ci.nodes.check_final_integrity(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);
let was_ptr = val.ptr;
@ -4294,7 +4323,7 @@ impl<'a> Codegen<'a> {
}
Loc::Stack => {
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);
self.store_mem(stack, flag_ty, fill);
let off = self.offset(stack, payload_offset);
@ -4394,7 +4423,7 @@ impl<'a> Codegen<'a> {
if inner != src.ty {
self.assert_ty(pos, src, inner, hint);
}
self.wrap_in_opt(src);
self.wrap_in_opt(pos, src);
} else {
debug_assert!(
src.ty.is_integer() || src.ty == ty::Id::NEVER,
@ -4609,6 +4638,7 @@ mod tests {
fb_driver;
// Purely Testing Examples;
stack_provenance;
advanced_floating_point_arithmetic;
nullable_structure;
needless_unwrap;

View file

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

View file

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