Even more R2R (#16348)

* Fix r2r without FILE
* Fix many tests for r2r-c
* Pipe stdin in r2r to make isatty() return false
* Fix a leak in r2r
* Fix lock usage in RThread
* Always print stderr on failed tests
* Break broken zip tests
* Add -j arg to r2r
* Temporarily disable some tests that js and v don't parse
* Fix ar= trailing newline
This commit is contained in:
Florian Märkl 2020-03-29 18:07:44 +02:00 committed by GitHub
parent a88ec62304
commit 2c7ecc9736
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 139 additions and 68 deletions

View File

@ -132,16 +132,6 @@ R_API RPVector *r2r_load_cmd_test_file(const char *file) {
if (val) {
*val = '\0';
val++;
// Strip comment
char *cmt = strchr (val, '#');
if (cmt) {
*cmt = '\0';
cmt--;
while (cmt > val && *cmt == ' ') {
*cmt = '\0';
cmt--;
}
}
}
// RUN is the only cmd without value
@ -180,6 +170,16 @@ R_API RPVector *r2r_load_cmd_test_file(const char *file) {
eprintf (LINEFMT "Warning: Duplicate key \"%s\"\n", file, linenum, key); \
} \
test->field.set = true; \
/* Strip comment */ \
char *cmt = strchr (val, '#'); \
if (cmt) { \
*cmt = '\0'; \
cmt--; \
while (cmt > val && *cmt == ' ') { \
*cmt = '\0'; \
cmt--; \
} \
} \
if (!strcmp (val, "1")) { \
test->field.value = true; \
} else if (!strcmp (val, "0")) { \

View File

@ -23,18 +23,23 @@ static RThreadFunctionRet worker_th(RThread *th);
static void print_state(R2RState *state, ut64 prev_completed);
static int help(bool verbose) {
printf ("Usage: r2r [test]\n");
printf ("Usage: r2r [-vh] [-j threads] [test path]\n");
if (verbose) {
printf (" TODO: verbose help\n");
printf (
" -h print this help\n"
" -v verbose\n"
" -j [threads] how many threads to use for running tests concurrently (default is 4)\n");
}
return 1;
}
int main(int argc, char **argv) {
int c, workers_count = 4; // TODO: read from arg
int workers_count = 4;
bool verbose = false;
RGetopt opt;
r_getopt_init (&opt, argc, (const char **)argv, "hv");
r_getopt_init (&opt, argc, (const char **)argv, "hvj:");
int c;
while ((c = r_getopt_next (&opt)) != -1) {
switch (c) {
case 'h':
@ -42,6 +47,14 @@ int main(int argc, char **argv) {
case 'v':
verbose = true;
break;
case 'j': {
workers_count = atoi (opt.arg);
if (workers_count <= 0) {
eprintf ("Invalid thread count\n");
return help (false);
}
break;
}
default:
return help (false);
}
@ -254,9 +267,12 @@ static void print_result_diff(R2RRunConfig *config, R2RTestResultInfo *result) {
print_diff (result->proc_out->out, expect);
}
expect = result->test->cmd_test->expect_err.value;
if (expect && strcmp (result->proc_out->err, expect)) {
const char *err = result->proc_out->err;
if (expect && strcmp (err, expect)) {
printf ("-- stderr\n");
print_diff (result->proc_out->err, expect);
print_diff (err, expect);
} else if (*err) {
printf ("-- stderr\n%s\n", err);
}
if (result->proc_out->ret != 0) {
printf ("-- exit status: "Color_RED"%d"Color_RESET"\n", result->proc_out->ret);

View File

@ -41,6 +41,7 @@ R_API void r2r_subprocess_free(R2RSubprocess *proc) {}
struct r2r_subprocess_t {
pid_t pid;
int stdin_fd;
int stdout_fd;
int stderr_fd;
int killpipe[2];
@ -174,6 +175,13 @@ R_API R2RSubprocess *r2r_subprocess_start(
goto error;
}
int stdin_pipe[2] = { -1, -1 };
if (pipe (stdin_pipe) == -1) {
perror ("pipe");
goto error;
}
proc->stdin_fd = stdin_pipe[1];
int stdout_pipe[2] = { -1, -1 };
if (pipe (stdout_pipe) == -1) {
perror ("pipe");
@ -207,6 +215,9 @@ R_API R2RSubprocess *r2r_subprocess_start(
return NULL;
} else if (proc->pid == 0) {
// child
while ((dup2(stdin_pipe[0], STDIN_FILENO) == -1) && (errno == EINTR)) {}
close (stdin_pipe[0]);
close (stdin_pipe[1]);
while ((dup2(stdout_pipe[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {}
close (stdout_pipe[1]);
close (stdout_pipe[0]);
@ -225,6 +236,7 @@ R_API R2RSubprocess *r2r_subprocess_start(
free (argv);
// parent
close (stdin_pipe[0]);
close (stdout_pipe[1]);
close (stderr_pipe[1]);
@ -254,6 +266,12 @@ error:
if (stdout_pipe[1] == -1) {
close (stdout_pipe[1]);
}
if (stdin_pipe[0] == -1) {
close (stdin_pipe[0]);
}
if (stdin_pipe[1] == -1) {
close (stdin_pipe[1]);
}
return NULL;
}
@ -345,9 +363,10 @@ R_API void r2r_subprocess_free(R2RSubprocess *proc) {
r_pvector_remove_data (&subprocs, proc);
r_th_lock_leave (subprocs_mutex);
r_strbuf_fini (&proc->out);
r_strbuf_fini (&proc->err);;
close (proc->killpipe[0]);;
r_strbuf_fini (&proc->err);
close (proc->killpipe[0]);
close (proc->killpipe[1]);
close (proc->stdin_fd);
close (proc->stdout_fd);
close (proc->stderr_fd);
free (proc);
@ -397,7 +416,9 @@ static R2RProcessOutput *run_r2_test(R2RRunConfig *config, const char *cmds, RLi
"1"
};
size_t env_size = load_plugins ? 0 : 1;
return runner (config->r2_cmd, args.v.a, r_pvector_len (&args), envvars, envvals, env_size);
R2RProcessOutput *out = runner (config->r2_cmd, args.v.a, r_pvector_len (&args), envvars, envvals, env_size);
r_pvector_clear (&args);
return out;
}
R_API R2RProcessOutput *r2r_run_cmd_test(R2RRunConfig *config, R2RCmdTest *test, R2RCmdRunner runner) {
@ -411,6 +432,14 @@ R_API R2RProcessOutput *r2r_run_cmd_test(R2RRunConfig *config, R2RCmdTest *test,
r_list_delete (files, it);
}
}
if (r_list_empty (files)) {
if (!files) {
files = r_list_new ();
} else {
files->free = NULL;
}
r_list_push (files, "-");
}
R2RProcessOutput *out = run_r2_test (config, test->cmds.value, files, extra_args, test->load_plugins, runner);
r_list_free (extra_args);
r_list_free (files);

View File

@ -355,7 +355,7 @@ static int string_scan_range(RList *list, RBinFile *bf, int min,
pj_end (pj);
RIO *io = bin->iob.io;
if (io) {
io->cb_printf ("%s", pj_string (pj));
io->cb_printf ("%s\n", pj_string (pj));
}
pj_free (pj);
}

View File

@ -417,7 +417,7 @@ static void _print_strings(RCore *r, RList *list, int mode, int va) {
R_FREE (b64.string);
if (IS_MODE_JSON (mode)) {
pj_end (pj);
r_cons_printf ("%s", pj_string (pj));
r_cons_printf ("%s\n", pj_string (pj));
pj_free (pj);
pj = NULL;
} else if (IS_MODE_SET (mode)) {
@ -502,7 +502,7 @@ static bool bin_strings(RCore *r, int mode, int va) {
if (plugin->info && plugin->name) {
if (strcmp (plugin->name, "any") == 0 && !rawstr) {
if (IS_MODE_JSON (mode)) {
r_cons_print ("[]");
r_cons_print ("[]\n");
return true;
}
return false;
@ -621,7 +621,7 @@ static int bin_info(RCore *r, int mode, ut64 laddr) {
RBinFile *bf = r_bin_cur (r->bin);
if (!bf) {
if (IS_MODE_JSON (mode)) {
r_cons_printf ("{}");
r_cons_printf ("{}\n");
}
return false;
}
@ -631,7 +631,7 @@ static int bin_info(RCore *r, int mode, ut64 laddr) {
if (!bf || !info || !obj) {
if (mode & R_MODE_JSON) {
r_cons_printf ("{}");
r_cons_printf ("{}\n");
return true;
}
return false;
@ -863,7 +863,7 @@ static int bin_info(RCore *r, int mode, ut64 laddr) {
}
}
if (IS_MODE_JSON (mode)) {
r_cons_printf ("}");
r_cons_printf ("}\n");
}
}
const char *dir_prefix = r_config_get (r->config, "dir.prefix");
@ -2085,7 +2085,7 @@ static int bin_symbols(RCore *r, int mode, ut64 laddr, int va, ut64 at, const ch
bool bin_demangle = r_config_get_i (r->config, "bin.demangle");
if (!info) {
if (IS_MODE_JSON (mode)) {
r_cons_printf (printHere? "{}": "[]");
r_cons_printf (printHere? "{}": "[]\n");
}
r_table_free (table);
return 0;
@ -2336,7 +2336,7 @@ next:
pj_end (pj);
}
const char *js = pj_string (pj);
r_cons_printf ("%s", (js && *js)? js: "{}");
r_cons_printf ("%s\n", (js && *js)? js: "{}");
}
pj_free (pj);
@ -3127,7 +3127,7 @@ static int bin_classes(RCore *r, int mode) {
RList *cs = r_bin_get_classes (r->bin);
if (!cs) {
if (IS_MODE_JSON (mode)) {
r_cons_print ("[]");
r_cons_print ("[]\n");
return true;
}
return false;
@ -3286,7 +3286,7 @@ static int bin_classes(RCore *r, int mode) {
free (name);
}
if (IS_MODE_JSON (mode)) {
r_cons_print ("]");
r_cons_print ("]\n");
}
return true;
@ -3778,7 +3778,7 @@ static void bin_pe_resources(RCore *r, int mode) {
r_cons_printf ("%s\n", pj_string (pj));
pj_free (pj);
} else if (IS_MODE_RAD (mode)) {
r_cons_printf ("fs *");
r_cons_println ("fs *");
}
}
@ -3825,7 +3825,7 @@ static int bin_signature(RCore *r, int mode) {
if (plg && plg->signature) {
const char *signature = plg->signature (cur, IS_MODE_JSON (mode));
if (IS_MODE_JSON (mode)) {
r_cons_printf ("{\"signature\":%s}", signature);
r_cons_printf ("{\"signature\":%s}\n", signature);
} else {
r_cons_println (signature);
}

View File

@ -651,7 +651,7 @@ static int cmd_info(void *data, const char *input) {
}
}
pj_end (pj);
r_cons_printf ("%s", pj_string (pj));
r_cons_printf ("%s\n", pj_string (pj));
pj_free (pj);
} else { // "it"
if (!equal) {

View File

@ -4287,7 +4287,7 @@ static void func_walk_blocks(RCore *core, RAnalFunction *f, char input, char typ
}
}
pj_end (pj);
r_cons_printf ("%s", pj_string (pj));
r_cons_printf ("%s\n", pj_string (pj));
pj_free (pj);
} else {
bool asm_lines = r_config_get_i (core->config, "asm.lines.bb");

View File

@ -280,7 +280,7 @@ beach:
dbg->cb_printf ("}\n");
} else if (rad == 'J') {
// do nothing
} else if (n > 0 && rad == 2 && ((n%cols))) {
} else if (n > 0 && (rad == 2 || rad == '=') && ((n%cols))) {
dbg->cb_printf ("\n");
}
return n;

View File

@ -39,6 +39,7 @@ static void *_r_th_launcher(void *_th) {
th->running = false;
r_th_lock_enter (th->lock);
} while (ret);
r_th_lock_leave (th->lock);
#if HAVE_PTHREAD
pthread_exit (&ret);
#endif

View File

@ -2371,7 +2371,9 @@ s 0x2254d
agf~invalid
echo end
EOF
EXPECT=end
EXPECT=<<EOF
end
EOF
RUN
NAME=noreturn of reloc-functions

View File

@ -148,8 +148,10 @@ EOF
RUN
NAME=afcl: mips-32-override
FILE=/../bins/elf/libc.so.0
FILE=../bins/elf/libc.so.0
EXPECT=<<EOF
n32
o32
EOF
ARGS=-a mips -b 64
CMDS=afcl

View File

@ -4,7 +4,9 @@ CMDS=<<EOF
aaa 2> /dev/null
agCj~{0}
EOF
EXPECT={"name":"entry0", "size":46,"imports":["reloc.__libc_start_main"]}
EXPECT=<<EOF
{"name":"entry0", "size":46,"imports":["reloc.__libc_start_main"]}
EOF
RUN
NAME=agCd entry0 imports libc_start_main
@ -37,5 +39,7 @@ aaa 2> /dev/null
agC~unk.
echo end
EOF
EXPECT=end
EXPECT=<<EOF
end
EOF
RUN

View File

@ -260,25 +260,30 @@ isq~?
EOF
RUN
NAME=ob 0 fix
FILE=- - -
CMDS=<<EOF
ob~[0-1]
?e
ob 1; i~^fd
ob 2; i~^fd
ob 0; i~^fd
EOF
EXPECT=<<EOF
0 3
1 4
2 5
fd 4
fd 5
fd 3
EOF
RUN
# TODO: re-enable when r2r.js and v are dead
#NAME=ob 0 fix
#FILE=<<EOF
#-
#-
#-
#EOF
#CMDS=<<EOF
#ob~[0-1]
#?e
#ob 1; i~^fd
#ob 2; i~^fd
#ob 0; i~^fd
#EOF
#EXPECT=<<EOF
#0 3
#1 4
#2 5
#
#fd 4
#fd 5
#fd 3
#EOF
#RUN
NAME=o-*
FILE=-

View File

@ -63,7 +63,6 @@ pdr
?e
pdrj~{}
?e
?e
pir
?e
pirj~{}

View File

@ -463,7 +463,9 @@ RUN
NAME=pf? struct not defined
FILE=-
CMDS=pf?cat_sat_on_keyboard
EXPECT_ERR=Struct cat_sat_on_keyboard is not defined
EXPECT_ERR=<<EOF
Struct cat_sat_on_keyboard is not defined
EOF
RUN
NAME=-nn filename with @

View File

@ -13,7 +13,9 @@ RUN
NAME=rop search without maxhits
FILE=../bins/elf/varsub
CMDS=/Rq pop r15~?
EXPECT=4
EXPECT=<<EOF
4
EOF
RUN
NAME=rop search without maxhits
@ -22,7 +24,9 @@ CMDS=<<EOF
e search.maxhits=2
/Rq pop r15~?
EOF
EXPECT=2
EXPECT=<<EOF
2
EOF
RUN
NAME=search all rop gadgets

View File

@ -1,7 +1,12 @@
NAME=multiple files opened
FILE=- - -
CMDS=o~?
EXPECT=<<EOF
3
EOF
RUN
# TODO: re-enable when r2r.js and v are dead
#NAME=multiple files opened
#FILE=<<EOF
#-
#-
#-
#EOF
#CMDS=o~?
#EXPECT=<<EOF
#3
#EOF
#RUN

View File

@ -1,5 +1,6 @@
NAME=io-zip
FILE=zip://../bins/java/example.zip
BROKEN=1
EXPECT=<<EOF
0 research_data/experiment/decompiler/dumped_jar_dec/c.class
EOF
@ -38,6 +39,7 @@ RUN
NAME=io-zip hello.apk
FILE=zip://../bins/dex/Hello.apk
BROKEN=1
EXPECT=<<EOF
0 classes.dex
EOF