diff options
author | Michael Forney <mforney@mforney.org> | 2021-09-25 13:27:27 -0700 |
---|---|---|
committer | Quentin Carbonneaux <quentin@c9x.me> | 2021-11-08 14:11:10 +0100 |
commit | ae8803cbe655f64a2ef1739c8dfc5c12af99bdfb (patch) | |
tree | ad526ee40568cc5ac7642ad677b69c69d3315377 /amd64 | |
parent | cd095a44db262351b09ea144a44b76e22d62c77a (diff) | |
download | roux-ae8803cbe655f64a2ef1739c8dfc5c12af99bdfb.tar.gz |
amd64: avoid reading past end of passed struct
If the size of the struct is not a multiple of 8, the actual struct size may be different from the size reserved on the stack. This fixes the case where the struct is passed in memory, but we still may over-read a struct passed in registers. A TODO is added for now.
Diffstat (limited to 'amd64')
-rw-r--r-- | amd64/sysv.c | 10 |
1 files changed, 8 insertions, 2 deletions
diff --git a/amd64/sysv.c b/amd64/sysv.c index 2e3e4a8..7dc5981 100644 --- a/amd64/sysv.c +++ b/amd64/sysv.c @@ -4,6 +4,7 @@ typedef struct AClass AClass; typedef struct RAlloc RAlloc; struct AClass { + Typ *type; int inmem; int align; uint size; @@ -72,6 +73,7 @@ typclass(AClass *a, Typ *t) al = 8; sz = (sz + al-1) & -al; + a->type = t; a->size = sz; a->align = t->align; @@ -125,7 +127,7 @@ selret(Blk *b, Fn *fn) if (aret.inmem) { assert(rtype(fn->retr) == RTmp); emit(Ocopy, Kl, TMP(RAX), fn->retr, R); - blit(fn->retr, 0, r0, aret.size, fn); + blit(fn->retr, 0, r0, aret.type->size, fn); ca = 1; } else { ca = retr(reg, &aret); @@ -338,6 +340,10 @@ selcall(Fn *fn, Ins *i0, Ins *i1, RAlloc **rap) emit(Ocopy, Kl, i1->to, TMP(RAX), R); ca += 1; } else { + /* todo, may read out of bounds. + * gcc did this up until 5.2, but + * this should still be fixed. + */ if (aret.size > 8) { r = newtmp("abi", Kl, fn); aret.ref[1] = newtmp("abi", aret.cls[1], fn); @@ -407,7 +413,7 @@ selcall(Fn *fn, Ins *i0, Ins *i1, RAlloc **rap) if (i->op == Oargc) { if (a->align == 4) off += off & 15; - blit(r, off, i->arg[1], a->size, fn); + blit(r, off, i->arg[1], a->type->size, fn); } else { r1 = newtmp("abi", Kl, fn); emit(Ostorel, 0, R, i->arg[0], r1); |