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
869 869
870/* Return the number of registers needed to return the struct, or 0 if870/* Return the number of registers needed to return the struct, or 0 if
871 returning via struct pointer. */871 returning via struct pointer. */
872ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align) {872ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) {
873#ifdef TCC_ARM_EABI873#ifdef TCC_ARM_EABI
874 int size, align;874 int size, align;
875 size = type_size(vt, &align);875 size = type_size(vt, &align);
876 if (float_abi == ARM_HARD_FLOAT && !variadic &&876 if (float_abi == ARM_HARD_FLOAT && !variadic &&
877 (is_float(vt->t) || is_hgen_float_aggr(vt))) {877 (is_float(vt->t) || is_hgen_float_aggr(vt))) {
878 *ret_align = 8;878 *ret_align = 8;
879 *regsize = 8;
879 ret->ref = NULL;880 ret->ref = NULL;
880 ret->t = VT_DOUBLE;881 ret->t = VT_DOUBLE;
881 return (size + 7) >> 3;882 return (size + 7) >> 3;
882 } else if (size <= 4) {883 } else if (size <= 4) {
883 *ret_align = 4;884 *ret_align = 4;
885 *regsize = 4;
884 ret->ref = NULL;886 ret->ref = NULL;
885 ret->t = VT_INT;887 ret->t = VT_INT;
886 return 1;888 return 1;
@@ -1255,7 +1257,7 @@ void gfunc_call(int nb_args) · 368 unmodified lines
1255void gfunc_prolog(CType *func_type)1257void gfunc_prolog(CType *func_type)
1256{1258{
1257 Sym *sym,*sym2;1259 Sym *sym,*sym2;
1258 int n, nf, size, align, struct_ret = 0;1260 int n, nf, size, align, rs, struct_ret = 0;
1259 int addr, pn, sn; /* pn=core, sn=stack */1261 int addr, pn, sn; /* pn=core, sn=stack */
1260 CType ret_type;1262 CType ret_type;
1261 1263
@@ -1269,7 +1271,7 @@ void gfunc_prolog(CType *func_type) · 7 unmodified lines
1269 1271
1270 n = nf = 0;1272 n = nf = 0;
1271 if ((func_vt.t & VT_BTYPE) == VT_STRUCT &&1273 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))
1273 {1275 {
1274 n++;1276 n++;
1275 struct_ret = 1;1277 struct_ret = 1;
arm64-gen.c+1−1
@@ -1196,7 +1196,7 @@ ST_FUNC void gen_va_arg(CType *t) · 1195 unmodified lines
1196 }1196 }
1197}1197}
1198 1198
1199ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align)1199ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize)
1200{1200{
1201 return 0;1201 return 0;
1202}1202}
c67-gen.c+1−1
@@ -1881,7 +1881,7 @@ static void gcall_or_jmp(int is_jmp) · 1880 unmodified lines
1881 1881
1882/* Return the number of registers needed to return the struct, or 0 if1882/* Return the number of registers needed to return the struct, or 0 if
1883 returning via struct pointer. */1883 returning via struct pointer. */
1884ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align) {1884ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize) {
1885 *ret_align = 1; // Never have to re-align return values for x86-641885 *ret_align = 1; // Never have to re-align return values for x86-64
1886 return 0;1886 return 0;
1887}1887}
i386-gen.c+2−1
@@ -376,12 +376,13 @@ static uint8_t fastcallw_regs[2] = { TREG_ECX, TREG_EDX }; · 375 unmodified lines
376 376
377/* Return the number of registers needed to return the struct, or 0 if377/* Return the number of registers needed to return the struct, or 0 if
378 returning via struct pointer. */378 returning via struct pointer. */
379ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align)379ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)
380{380{
381#ifdef TCC_TARGET_PE381#ifdef TCC_TARGET_PE
382 int size, align;382 int size, align;
383 383
384 *ret_align = 1; // Never have to re-align return values for x86384 *ret_align = 1; // Never have to re-align return values for x86
385 *regsize = 4;
385 size = type_size(vt, &align);386 size = type_size(vt, &align);
386 if (size > 8) {387 if (size > 8) {
387 return 0;388 return 0;
tcc.h+1−1
@@ -1327,7 +1327,7 @@ ST_FUNC void gsym_addr(int t, int a); · 1326 unmodified lines
1327ST_FUNC void gsym(int t);1327ST_FUNC void gsym(int t);
1328ST_FUNC void load(int r, SValue *sv);1328ST_FUNC void load(int r, SValue *sv);
1329ST_FUNC void store(int r, SValue *v);1329ST_FUNC void store(int r, SValue *v);
1330ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align);1330ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *align, int *regsize);
1331ST_FUNC void gfunc_call(int nb_args);1331ST_FUNC void gfunc_call(int nb_args);
1332ST_FUNC void gfunc_prolog(CType *func_type);1332ST_FUNC void gfunc_prolog(CType *func_type);
1333ST_FUNC void gfunc_epilog(void);1333ST_FUNC void gfunc_epilog(void);
tccgen.c+12−8
@@ -4153,7 +4153,7 @@ ST_FUNC void unary(void) · 4152 unmodified lines
4153 } else if (tok == '(') {4153 } else if (tok == '(') {
4154 SValue ret;4154 SValue ret;
4155 Sym *sa;4155 Sym *sa;
4156 int nb_args, ret_nregs, ret_align, variadic;4156 int nb_args, ret_nregs, ret_align, regsize, variadic;
4157 4157
4158 /* function call */4158 /* function call */
4159 if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {4159 if ((vtop->type.t & VT_BTYPE) != VT_FUNC) {
@@ -4179,7 +4179,7 @@ ST_FUNC void unary(void) · 19 unmodified lines
4179 if ((s->type.t & VT_BTYPE) == VT_STRUCT) {4179 if ((s->type.t & VT_BTYPE) == VT_STRUCT) {
4180 variadic = (s->c == FUNC_ELLIPSIS);4180 variadic = (s->c == FUNC_ELLIPSIS);
4181 ret_nregs = gfunc_sret(&s->type, variadic, &ret.type,4181 ret_nregs = gfunc_sret(&s->type, variadic, &ret.type,
4182 &ret_align);4182 &ret_align, &regsize);
4183 if (!ret_nregs) {4183 if (!ret_nregs) {
4184 /* get some space for the returned structure */4184 /* get some space for the returned structure */
4185 size = type_size(&s->type, &align);4185 size = type_size(&s->type, &align);
@@ -4259,6 +4259,10 @@ ST_FUNC void unary(void) · 73 unmodified lines
4259 int addr, offset;4259 int addr, offset;
4260 4260
4261 size = type_size(&s->type, &align);4261 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;
4262 loc = (loc - size) & -align;4266 loc = (loc - size) & -align;
4263 addr = loc;4267 addr = loc;
4264 offset = 0;4268 offset = 0;
@@ -4269,8 +4273,7 @@ ST_FUNC void unary(void) · 4 unmodified lines
4269 vtop--;4273 vtop--;
4270 if (--ret_nregs == 0)4274 if (--ret_nregs == 0)
4271 break;4275 break;
4272 /* XXX: compatible with arm only: ret_align == register_size */4276 offset += regsize;
4273 offset += ret_align;
4274 }4277 }
4275 vset(&s->type, VT_LOCAL | VT_LVAL, addr);4278 vset(&s->type, VT_LOCAL | VT_LVAL, addr);
4276 }4279 }
@@ -4850,9 +4853,9 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 573 unmodified lines
4850#else4853#else
4851 if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {4854 if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
4852 CType type, ret_type;4855 CType type, ret_type;
4853 int ret_align, ret_nregs;4856 int ret_align, ret_nregs, regsize;
4854 ret_nregs = gfunc_sret(&func_vt, func_var, &ret_type,4857 ret_nregs = gfunc_sret(&func_vt, func_var, &ret_type,
4855 &ret_align);4858 &ret_align, &regsize);
4856 if (0 == ret_nregs) {4859 if (0 == ret_nregs) {
4857 /* if returning structure, must copy it to implicit4860 /* if returning structure, must copy it to implicit
4858 first pointer arg location */4861 first pointer arg location */
@@ -4890,9 +4893,10 @@ static void block(int *bsym, int *csym, int *case_sym, int *def_sym, · 31 unmodified lines
4890 /* We assume that when a structure is returned in multiple4893 /* We assume that when a structure is returned in multiple
4891 registers, their classes are consecutive values of the4894 registers, their classes are consecutive values of the
4892 suite s(n) = 2^n */4895 suite s(n) = 2^n */
4896 /* XXX This seems confused, if r == 0, this never
4897 changes r. */
4893 r <<= 1;4898 r <<= 1;
4894 /* XXX: compatible with arm only: ret_align == register_size */4899 vtop->c.i += regsize;
4895 vtop->c.i += ret_align;
4896 vtop->r = VT_LOCAL | VT_LVAL;4900 vtop->r = VT_LOCAL | VT_LVAL;
4897 }4901 }
4898 }4902 }
x86_64-gen.c+4−2
@@ -662,9 +662,10 @@ void gen_offs_sp(int b, int r, int d) · 661 unmodified lines
662 662
663/* Return the number of registers needed to return the struct, or 0 if663/* Return the number of registers needed to return the struct, or 0 if
664 returning via struct pointer. */664 returning via struct pointer. */
665ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align)665ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)
666{666{
667 int size, align;667 int size, align;
668 *regsize = 8;
668 *ret_align = 1; // Never have to re-align return values for x86-64669 *ret_align = 1; // Never have to re-align return values for x86-64
669 size = type_size(vt, &align);670 size = type_size(vt, &align);
670 ret->ref = NULL;671 ret->ref = NULL;
@@ -1069,10 +1070,11 @@ ST_FUNC int classify_x86_64_va_arg(CType *ty) · 398 unmodified lines
1069 1070
1070/* Return the number of registers needed to return the struct, or 0 if1071/* Return the number of registers needed to return the struct, or 0 if
1071 returning via struct pointer. */1072 returning via struct pointer. */
1072ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align)1073ST_FUNC int gfunc_sret(CType *vt, int variadic, CType *ret, int *ret_align, int *regsize)
1073{1074{
1074 int size, align, reg_count;1075 int size, align, reg_count;
1075 *ret_align = 1; // Never have to re-align return values for x86-641076 *ret_align = 1; // Never have to re-align return values for x86-64
1077 *regsize = 8;
1076 return (classify_x86_64_arg(vt, ret, &size, &align, &reg_count) != x86_64_mode_memory);1078 return (classify_x86_64_arg(vt, ret, &size, &align, &reg_count) != x86_64_mode_memory);
1077}1079}
1078 1080

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