History

Fix stack overwrite on structure return

The common code to move a returned structure packed into registers into memory on the caller side didn't take the register size into account when allocating local storage, so sometimes that lead to stack overwrites (e.g. in 73_arm64.c), on x86_64. This fixes it by generally making gfunc_sret also return the register size.

Michael Matz committed 11 years ago

Commit 50899e31 parent d73b4887 files · +26 −17Browse files

Unified · Split

7 files
  1. arm-gen.c +5 −3
  2. arm64-gen.c +1 −1
  3. c67-gen.c +1 −1
  4. i386-gen.c +2 −1
  5. tcc.h +1 −1
  6. tccgen.c +12 −8
  7. x86_64-gen.c +4 −2
arm-gen.c+5−3
@@ -869,18 +869,20 @@ int floats_in_core_regs(SValue *sval) · 868 unmodified lines
869869
870870 /* Return the number of registers needed to return the struct, or 0 if
871871 returning via struct pointer. */
872−ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align) {
872+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) {
873873 #ifdef TCC_ARM_EABI
874874 int size, align;
875875 size = type_size(vt, &align);
876876 if (float_abi == ARM_HARD_FLOAT && !variadic &&
877877 (is_float(vt->t) || is_hgen_float_aggr(vt))) {
878878 *ret_align = 8;
879+ *regsize = 8;
879880 ret->ref = NULL;
880881 ret->t = VT_DOUBLE;
881882 return (size + 7) >> 3;
882883 } else if (size <= 4) {
883884 *ret_align = 4;
885+ *regsize = 4;
884886 ret->ref = NULL;
885887 ret->t = VT_INT;
886888 return 1;
@@ -1255,7 +1257,7 @@ void gfunc_call(int nb_args) · 368 unmodified lines
12551257 void gfunc_prolog(CType *func_type)
12561258 {
12571259 Sym *sym,*sym2;
1258− int n, nf, size, align, struct_ret = 0;
1260+ int n, nf, size, align, rs, struct_ret = 0;
12591261 int addr, pn, sn; /* pn=core, sn=stack */
12601262 CType ret_type;
12611263
@@ -1269,7 +1271,7 @@ void gfunc_prolog(CType *func_type) · 7 unmodified lines
12691271
12701272 n = nf = 0;
12711273 if ((func_vt.t & VT_BTYPE) == VT_STRUCT &&
1272− !gfunc_sret(&func_vt, func_var, &ret_type, &align))
1274+ !gfunc_sret(&func_vt, func_var, &ret_type, &align, &rs))
12731275 {
12741276 n++;
12751277 struct_ret = 1;
arm64-gen.c+1−1
@@ -1196,7 +1196,7 @@ ST_FUNC void gen_va_arg(CType *t) · 1195 unmodified lines
11961196 }
11971197 }
11981198
1199−ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align)
1199+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize)
12001200 {
12011201 return 0;
12021202 }
c67-gen.c+1−1
@@ -1881,7 +1881,7 @@ static void gcall_or_jmp(int is_jmp) · 1880 unmodified lines
18811881
18821882 /* Return the number of registers needed to return the struct, or 0 if
18831883 returning via struct pointer. */
1884−ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align) {
1884+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) {
18851885 *ret_align = 1; // Never have to re-align return values for x86-64
18861886 return 0;
18871887 }
i386-gen.c+2−1
@@ -376,12 +376,13 @@ static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX }; · 375 unmodified lines
376376
377377 /* Return the number of registers needed to return the struct, or 0 if
378378 returning via struct pointer. */
379−ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align)
379+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)
380380 {
381381 #ifdef TCC_TARGET_PE
382382 int size, align;
383383
384384 *ret_align = 1; // Never have to re-align return values for x86
385+ *regsize = 4;
385386 size = type_size(vt, &align);
386387 if (size > 8) {
387388 return 0;
tcc.h+1−1
@@ -1327,7 +1327,7 @@ ST_FUNC void gsym_addr(int t, int a); · 1326 unmodified lines
13271327 ST_FUNC void gsym(int t);
13281328 ST_FUNC void load(int r, SValue *sv);
13291329 ST_FUNC void store(int r, SValue *v);
1330−ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align);
1330+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize);
13311331 ST_FUNC void gfunc_call(int nb_args);
13321332 ST_FUNC void gfunc_prolog(CType *func_type);
13331333 ST_FUNC void gfunc_epilog(void);
tccgen.c+12−8
@@ -4153,7 +4153,7 @@ ST_FUNC void unary(void) · 4152 unmodified lines
41534153 } else if (tok == '(') {
41544154 SValue ret;
41554155 Sym *sa;
4156− int nb_args, ret_nregs, ret_align, variadic;
4156+ int nb_args, ret_nregs, ret_align, regsize, variadic;
41574157
41584158 /* function call */
41594159 if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
@@ -4179,7 +4179,7 @@ ST_FUNC void unary(void) · 19 unmodified lines
41794179 if ((s->type.t & VT_BTYPE) == VT_STRUCT) {
41804180 variadic = (s->c == FUNC_ELLIPSIS);
41814181 ret_nregs = gfunc_sret(&s->type, variadic, &ret.type,
4182− &ret_align);
4182+ &ret_align, &regsize);
41834183 if (!ret_nregs) {
41844184 /* get some space for the returned structure */
41854185 size = type_size(&s->type, &align);
@@ -4259,6 +4259,10 @@ ST_FUNC void unary(void) · 73 unmodified lines
42594259 int addr, offset;
42604260
42614261 size = type_size(&s->type, &align);
4262+ /* We're writing whole regs often, make sure there's enough
4263+ space. Assume register size is power of 2. */
4264+ if (regsize > align)
4265+ align = regsize;
42624266 loc = (loc - size) & -align;
42634267 addr = loc;
42644268 offset = 0;
@@ -4269,8 +4273,7 @@ ST_FUNC void unary(void) · 4 unmodified lines
42694273 vtop--;
42704274 if (--ret_nregs == 0)
42714275 break;
4272− /* XXX: compatible with arm only: ret_align == register_size */
4273− offset += ret_align;
4276+ offset += regsize;
42744277 }
42754278 vset(&s->type, VT_LOCAL | VT_LVAL, addr);
42764279 }
@@ -4850,9 +4853,9 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 573 unmodified lines
48504853 #else
48514854 if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
48524855 CType type, ret_type;
4853− int ret_align, ret_nregs;
4856+ int ret_align, ret_nregs, regsize;
48544857 ret_nregs = gfunc_sret(&func_vt, func_var, &ret_type,
4855− &ret_align);
4858+ &ret_align, &regsize);
48564859 if (0 == ret_nregs) {
48574860 /* if returning structure, must copy it to implicit
48584861 first pointer arg location */
@@ -4890,9 +4893,10 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 31 unmodified lines
48904893 /* We assume that when a structure is returned in multiple
48914894 registers, their classes are consecutive values of the
48924895 suite s(n) = 2^n */
4896+ /* XXX This seems confused, if r == 0, this never
4897+ changes r. */
48934898 r <<= 1;
4894− /* XXX: compatible with arm only: ret_align == register_size */
4895− vtop->c.i += ret_align;
4899+ vtop->c.i += regsize;
48964900 vtop->r = VT_LOCAL | VT_LVAL;
48974901 }
48984902 }
x86_64-gen.c+4−2
@@ -662,9 +662,10 @@ void gen_offs_sp(int b, int r, int d) · 661 unmodified lines
662662
663663 /* Return the number of registers needed to return the struct, or 0 if
664664 returning via struct pointer. */
665−ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align)
665+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)
666666 {
667667 int size, align;
668+ *regsize = 8;
668669 *ret_align = 1; // Never have to re-align return values for x86-64
669670 size = type_size(vt, &align);
670671 ret->ref = NULL;
@@ -1069,10 +1070,11 @@ ST_FUNC int classify_x86_64_va_arg(CType *ty) · 398 unmodified lines
10691070
10701071 /* Return the number of registers needed to return the struct, or 0 if
10711072 returning via struct pointer. */
1072−ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align)
1073+ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)
10731074 {
10741075 int size, align, reg_count;
10751076 *ret_align = 1; // Never have to re-align return values for x86-64
1077+ *regsize = 8;
10761078 return (classify_x86_64_arg(vt, ret, &size, &align, &reg_count) != x86_64_mode_memory);
10771079 }
10781080

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t