7 ms·
1) Our goal is emitting goto rarely, not excluding them entirely. However, most of the gotos one sees in IDA are due limitations in control-flow recovery, examp
by aleclm 3y ago
1) Our goal is emitting goto rarely, not excluding them entirely.
However, most of the gotos one sees in IDA are due limitations in control-flow recovery, example:
switch (x) {
case 0:
do_0();
// Missing case 1
case 2:
do_2();
case 3:
do_3();
default:
do_default();
}
IDA will produce something like...
if (x > 3)
goto label;
switch (x) {
case 0:
do_0();
case 1:
label:
do_default();
case 2:
do_2();
case 3:
do_3();
}
gotos originally present in the original code are almost never the reason you see a goto in IDA.
In any case, in presence of gotos, we currently duplicate code and sometimes this is good.
Imagine the following code snippet which represents a legitimate use of gotos:
int *x = malloc(sizeof(int));
if (x == NULL)
goto cleanup;
int *y = malloc(sizeof(int));
if (y == NULL)
goto cleanup;
do_stuff(x, y);
cleanup:
if (x != NULL)
free(x);
if (y != NULL)
free(y);
return;
By "inlining" the gotos and doing some trivial optimizations we'd get:
int *x = malloc(sizeof(int));
if (x == NULL)
return;
int *y = malloc(sizeof(int));
if (y == NULL) {
free(x);
return;
}
do_stuff(x, y);
free(x);
free(y);
return;
Which is not bad a at all IMO.
2) We don't deal with duplication, it's way less of a problem, usually.
For deduplication, if it leads to gotos, we duplicate.