Browse Source

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.
Michael Forney 4 years ago
parent
commit
ae8803cbe6
2 changed files with 9 additions and 2 deletions
  1. 8 2
      amd64/sysv.c
  2. 1 0
      arm64/abi.c

+ 8 - 2
amd64/sysv.c

@@ -4,6 +4,7 @@ typedef struct AClass AClass;
 typedef struct RAlloc RAlloc;
 typedef struct RAlloc RAlloc;
 
 
 struct AClass {
 struct AClass {
+	Typ *type;
 	int inmem;
 	int inmem;
 	int align;
 	int align;
 	uint size;
 	uint size;
@@ -72,6 +73,7 @@ typclass(AClass *a, Typ *t)
 		al = 8;
 		al = 8;
 	sz = (sz + al-1) & -al;
 	sz = (sz + al-1) & -al;
 
 
+	a->type = t;
 	a->size = sz;
 	a->size = sz;
 	a->align = t->align;
 	a->align = t->align;
 
 
@@ -125,7 +127,7 @@ selret(Blk *b, Fn *fn)
 		if (aret.inmem) {
 		if (aret.inmem) {
 			assert(rtype(fn->retr) == RTmp);
 			assert(rtype(fn->retr) == RTmp);
 			emit(Ocopy, Kl, TMP(RAX), fn->retr, R);
 			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;
 			ca = 1;
 		} else {
 		} else {
 			ca = retr(reg, &aret);
 			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);
 			emit(Ocopy, Kl, i1->to, TMP(RAX), R);
 			ca += 1;
 			ca += 1;
 		} else {
 		} else {
+			/* todo, may read out of bounds.
+			 * gcc did this up until 5.2, but
+			 * this should still be fixed.
+			 */
 			if (aret.size > 8) {
 			if (aret.size > 8) {
 				r = newtmp("abi", Kl, fn);
 				r = newtmp("abi", Kl, fn);
 				aret.ref[1] = newtmp("abi", aret.cls[1], 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 (i->op == Oargc) {
 			if (a->align == 4)
 			if (a->align == 4)
 				off += off & 15;
 				off += off & 15;
-			blit(r, off, i->arg[1], a->size, fn);
+			blit(r, off, i->arg[1], a->type->size, fn);
 		} else {
 		} else {
 			r1 = newtmp("abi", Kl, fn);
 			r1 = newtmp("abi", Kl, fn);
 			emit(Ostorel, 0, R, i->arg[0], r1);
 			emit(Ostorel, 0, R, i->arg[0], r1);

+ 1 - 0
arm64/abi.c

@@ -144,6 +144,7 @@ sttmps(Ref tmp[], int cls[], uint nreg, Ref mem, Fn *fn)
 	}
 	}
 }
 }
 
 
+/* todo, may read out of bounds */
 static void
 static void
 ldregs(int reg[], int cls[], int n, Ref mem, Fn *fn)
 ldregs(int reg[], int cls[], int n, Ref mem, Fn *fn)
 {
 {