mirror of
https://github.com/frida/tinycc
synced 2024-11-24 08:39:37 +03:00
Fix miscompile with dead switches
In certain very specific situations (involving switches with asms inside dead statement expressions) we could generate invalid code (clobbering the buffer so much that we generated invalid instructions). Don't emit the decision table if the switch itself is dead.
This commit is contained in:
parent
7ae35bf1bb
commit
d042e71e9f
16
tccgen.c
16
tccgen.c
@ -5692,13 +5692,15 @@ static void block(int *bsym, int *csym, int is_expr)
|
||||
a = gjmp(a); /* add implicit break */
|
||||
/* case lookup */
|
||||
gsym(b);
|
||||
qsort(sw.p, sw.n, sizeof(void*), case_cmp);
|
||||
for (b = 1; b < sw.n; b++)
|
||||
if (sw.p[b - 1]->v2 >= sw.p[b]->v1)
|
||||
tcc_error("duplicate case value");
|
||||
gcase(sw.p, sw.n, c, &a);
|
||||
if (sw.def_sym)
|
||||
gjmp_addr(sw.def_sym);
|
||||
if (!nocode_wanted) {
|
||||
qsort(sw.p, sw.n, sizeof(void*), case_cmp);
|
||||
for (b = 1; b < sw.n; b++)
|
||||
if (sw.p[b - 1]->v2 >= sw.p[b]->v1)
|
||||
tcc_error("duplicate case value");
|
||||
gcase(sw.p, sw.n, c, &a);
|
||||
if (sw.def_sym)
|
||||
gjmp_addr(sw.def_sym);
|
||||
}
|
||||
dynarray_reset(&sw.p, &sw.n);
|
||||
cur_switch = saved;
|
||||
/* break label */
|
||||
|
@ -2964,6 +2964,56 @@ void test_high_clobbers(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
static long cpu_number;
|
||||
void trace_console(long len, long len2)
|
||||
{
|
||||
/* This generated invalid code when the emission of the switch
|
||||
table isn't disabled. The asms are necessary to show the bug,
|
||||
normal statements don't work (they need to generate some code
|
||||
even under nocode_wanted, which normal statements don't do,
|
||||
but asms do). Also at least these number of cases is necessary
|
||||
to generate enough "random" bytes. They ultimately are enough
|
||||
to create invalid instruction patterns to which the first
|
||||
skip-to-decision-table jump jumps. If decision table emission
|
||||
is disabled all of this is no problem.
|
||||
|
||||
It also is necessary that the switches are in a statement expression
|
||||
(which has the property of not being enterable from outside. no
|
||||
matter what). */
|
||||
if (0
|
||||
&&
|
||||
({
|
||||
long pscr_ret__;
|
||||
switch(len) {
|
||||
case 4:
|
||||
{
|
||||
long pfo_ret__;
|
||||
switch (len2) {
|
||||
case 8: printf("bla"); pfo_ret__ = 42; break;
|
||||
}
|
||||
pscr_ret__ = pfo_ret__;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
{
|
||||
long pfo_ret__;
|
||||
switch (len2) {
|
||||
case 1:asm("movq %1,%0": "=r" (pfo_ret__) : "m" (cpu_number)); break;
|
||||
case 2:asm("movq %1,%0": "=r" (pfo_ret__) : "m" (cpu_number)); break;
|
||||
case 4:asm("movq %1,%0": "=r" (pfo_ret__) : "m" (cpu_number)); break;
|
||||
case 8:asm("movq %1,%0": "=r" (pfo_ret__) : "m" (cpu_number)); break;
|
||||
default: printf("impossible\n");
|
||||
}
|
||||
pscr_ret__ = pfo_ret__;
|
||||
};
|
||||
break;
|
||||
}
|
||||
pscr_ret__;
|
||||
}))
|
||||
{
|
||||
printf("huh?\n");
|
||||
}
|
||||
}
|
||||
void asm_test(void)
|
||||
{
|
||||
char buf[128];
|
||||
@ -3044,6 +3094,7 @@ void asm_test(void)
|
||||
asm volatile ("mov $0x4243, %%esi" : "=r" (regvar));
|
||||
printf ("regvar=%x\n", regvar);
|
||||
test_high_clobbers();
|
||||
trace_console(8, 8);
|
||||
return;
|
||||
label1:
|
||||
goto label2;
|
||||
|
Loading…
Reference in New Issue
Block a user