Adds the core implementation of the new search. The rough architecture is the following: A search for a certain type of information (strings, bytes, keys etc.) creates a collections of items to search for (byte patterns, regular expressions etc.). Then specifies some settings how the search (number of threads, maxum hits...) and the finding is performed (string length, inverse match etc.). It also defines a search space, which is currently only the IO buffer. But can be anything in the future, like a graphs or the knowledge base. The search splits up the search space into windows (for IO: address ranges) and dispatches each search window into a 'find()' thread. The 'find()' handler (provided by a specific search implementation) checks the given window and produces search hits matching the elements in the search collection. The main search handler collects the hits of the dispatched workers and returns them to the user. Note: The byte and string search implementations are added in the next two commits. Part 6/9. Likely won't build in between parts. Co-authored-by: wargio <deroad@kumo.xn--q9jyb4c>
606 lines
17 KiB
C
606 lines
17 KiB
C
// SPDX-FileCopyrightText: 2020 thestr4ng3r <info@florianmaerkl.de>
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
|
|
#include "rz_test.h"
|
|
#include <rz_util/rz_str.h>
|
|
#include <rz_util/rz_regex.h>
|
|
#include <rz_cons.h>
|
|
|
|
#if __WINDOWS__
|
|
static ut8 *crlf2lf(ut8 *str) {
|
|
char *src = (char *)str;
|
|
char *dest = src;
|
|
while (*src) {
|
|
*dest = *src;
|
|
if (src[0] == '\r' && src[1] == '\n') {
|
|
// dest does not move
|
|
} else {
|
|
dest++;
|
|
}
|
|
src++;
|
|
}
|
|
*dest = '\0';
|
|
return str;
|
|
}
|
|
#else
|
|
#define crlf2lf(x) (x)
|
|
#endif
|
|
|
|
static RzSubprocessOutput *subprocess_runner(const char *file, const char *args[], size_t args_size,
|
|
const char *envvars[], const char *envvals[], size_t env_size, ut64 timeout_ms, void *user) {
|
|
RzSubprocess *proc = rz_subprocess_start(file, args, args_size, envvars, envvals, env_size);
|
|
if (!proc) {
|
|
return NULL;
|
|
}
|
|
RzSubprocessWaitReason r = rz_subprocess_wait(proc, timeout_ms);
|
|
if (r == RZ_SUBPROCESS_TIMEDOUT) {
|
|
rz_subprocess_kill(proc);
|
|
}
|
|
RzSubprocessOutput *out = rz_subprocess_drain(proc);
|
|
if (out) {
|
|
out->timeout = r == RZ_SUBPROCESS_TIMEDOUT;
|
|
out->out = crlf2lf(out->out);
|
|
out->err = crlf2lf(out->err);
|
|
}
|
|
rz_subprocess_free(proc);
|
|
return out;
|
|
}
|
|
|
|
#if __WINDOWS__
|
|
static char *convert_win_cmds(const char *cmds) {
|
|
char *r = malloc(strlen(cmds) + 1);
|
|
if (!r) {
|
|
return NULL;
|
|
}
|
|
char *p = r;
|
|
while (*cmds) {
|
|
if (*cmds == '!' || (*cmds == '\"' && cmds[1] == '!')) {
|
|
// Adjust shell syntax for Windows,
|
|
// only for lines starting with ! or "!
|
|
char c;
|
|
for (; c = *cmds, c; cmds++) {
|
|
if (c == '\\') {
|
|
// replace \$ by $
|
|
c = *++cmds;
|
|
if (c == '$') {
|
|
*p++ = '$';
|
|
} else {
|
|
*p++ = '\\';
|
|
*p++ = c;
|
|
}
|
|
} else if (c == '$') {
|
|
// replace ${VARNAME} by %VARNAME%
|
|
c = *++cmds;
|
|
if (c == '{') {
|
|
*p++ = '%';
|
|
cmds++;
|
|
for (; c = *cmds, c && c != '}'; cmds++) {
|
|
*p++ = c;
|
|
}
|
|
if (c) { // must check c to prevent overflow
|
|
*p++ = '%';
|
|
}
|
|
} else {
|
|
*p++ = '$';
|
|
*p++ = c;
|
|
}
|
|
} else {
|
|
*p++ = c;
|
|
if (c == '\n') {
|
|
cmds++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// Nothing to do, just copy the line
|
|
char *lend = strchr(cmds, '\n');
|
|
size_t llen;
|
|
if (lend) {
|
|
llen = lend - cmds + 1;
|
|
} else {
|
|
llen = strlen(cmds);
|
|
}
|
|
memcpy(p, cmds, llen);
|
|
cmds += llen;
|
|
p += llen;
|
|
}
|
|
*p = '\0';
|
|
return rz_str_replace(r, "/dev/null", "nul", true);
|
|
}
|
|
#endif
|
|
|
|
static RzSubprocessOutput *run_rz_test(RzTestRunConfig *config, ut64 timeout_ms, const char *cmds, RzList /*<char *>*/ *files, RzList /*<char *>*/ *extra_args, bool load_plugins, RzTestCmdRunner runner, void *user) {
|
|
RzPVector args;
|
|
rz_pvector_init(&args, NULL);
|
|
rz_pvector_push(&args, "-escr.utf8=0");
|
|
rz_pvector_push(&args, "-escr.color=0");
|
|
rz_pvector_push(&args, "-escr.interactive=0");
|
|
rz_pvector_push(&args, "-eflirt.sigdb.load.system=false");
|
|
rz_pvector_push(&args, "-esearch.show_progress=false");
|
|
rz_pvector_push(&args, "-eflirt.sigdb.load.home=false");
|
|
rz_pvector_push(&args, "-N");
|
|
RzListIter *it;
|
|
void *extra_arg, *file_arg;
|
|
rz_list_foreach (extra_args, it, extra_arg) {
|
|
rz_pvector_push(&args, extra_arg);
|
|
}
|
|
rz_pvector_push(&args, "-qc");
|
|
#if __WINDOWS__
|
|
char *wcmds = convert_win_cmds(cmds);
|
|
rz_pvector_push(&args, wcmds);
|
|
#else
|
|
rz_pvector_push(&args, (void *)cmds);
|
|
#endif
|
|
rz_list_foreach (files, it, file_arg) {
|
|
rz_pvector_push(&args, file_arg);
|
|
}
|
|
|
|
const char *envvars[] = {
|
|
#if __WINDOWS__
|
|
"ANSICON",
|
|
#endif
|
|
"RZ_NOPLUGINS"
|
|
};
|
|
const char *envvals[] = {
|
|
#if __WINDOWS__
|
|
"1",
|
|
#endif
|
|
"1"
|
|
};
|
|
#if __WINDOWS__
|
|
size_t env_size = load_plugins ? 1 : 2;
|
|
#else
|
|
size_t env_size = load_plugins ? 0 : 1;
|
|
#endif
|
|
RzSubprocessOutput *out = runner(config->rz_cmd, args.v.a, rz_pvector_len(&args), envvars, envvals, env_size, timeout_ms, user);
|
|
rz_pvector_clear(&args);
|
|
#if __WINDOWS__
|
|
free(wcmds);
|
|
#endif
|
|
return out;
|
|
}
|
|
|
|
RZ_API RzSubprocessOutput *rz_test_run_cmd_test(RzTestRunConfig *config, RzCmdTest *test, RzTestCmdRunner runner, void *user) {
|
|
RzList *extra_args = test->args.value ? rz_str_split_duplist(test->args.value, " ", true) : NULL;
|
|
RzList *files = test->file.value ? rz_str_split_duplist(test->file.value, "\n", true) : NULL;
|
|
RzListIter *it;
|
|
RzListIter *tmpit;
|
|
char *token;
|
|
rz_list_foreach_safe (extra_args, it, tmpit, token) {
|
|
if (!*token) {
|
|
rz_list_delete(extra_args, it);
|
|
}
|
|
}
|
|
rz_list_foreach_safe (files, it, tmpit, token) {
|
|
if (!*token) {
|
|
rz_list_delete(files, it);
|
|
}
|
|
}
|
|
if (rz_list_empty(files)) {
|
|
if (!files) {
|
|
files = rz_list_new();
|
|
} else {
|
|
files->free = NULL;
|
|
}
|
|
rz_list_push(files, "=");
|
|
}
|
|
ut64 timeout_ms = test->timeout.set ? test->timeout.value * 1000 : config->timeout_ms;
|
|
RzSubprocessOutput *out = run_rz_test(config, timeout_ms, test->cmds.value, files, extra_args, test->load_plugins, runner, user);
|
|
rz_list_free(extra_args);
|
|
rz_list_free(files);
|
|
return out;
|
|
}
|
|
|
|
RZ_API RZ_OWN RzStrBuf *rz_test_regex_full_match_str(RZ_NONNULL const char *pattern, RZ_NONNULL const char *text) {
|
|
return rz_regex_full_match_str(pattern, text, RZ_REGEX_ZERO_TERMINATED, RZ_REGEX_EXTENDED, RZ_REGEX_DEFAULT,
|
|
"\n");
|
|
}
|
|
|
|
RZ_API bool rz_test_cmp_cmd_output(const char *output, const char *expect, const char *regexp) {
|
|
if (regexp) {
|
|
RzStrBuf *match_str = rz_test_regex_full_match_str(regexp, output);
|
|
bool equal = false;
|
|
size_t expect_len = strlen(expect);
|
|
if (expect_len && expect[expect_len - 1] == '\n') {
|
|
// Ignore newline in expect
|
|
expect_len--;
|
|
size_t match_str_len = rz_strbuf_length(match_str);
|
|
if (match_str_len && rz_strbuf_get(match_str)[match_str_len - 1] == '\n') {
|
|
// Ignore newline in match_str
|
|
match_str_len--;
|
|
}
|
|
if (expect_len != match_str_len) {
|
|
rz_strbuf_free(match_str);
|
|
return false;
|
|
}
|
|
equal = !rz_str_cmp(expect, rz_strbuf_get(match_str), expect_len);
|
|
} else {
|
|
equal = RZ_STR_EQ(expect, rz_strbuf_get(match_str));
|
|
}
|
|
rz_strbuf_free(match_str);
|
|
return equal;
|
|
}
|
|
return !strcmp(expect, output);
|
|
}
|
|
|
|
RZ_API bool rz_test_check_cmd_test(RzSubprocessOutput *out, RzCmdTest *test) {
|
|
if (!out || out->ret != 0 || !out->out || !out->err || out->timeout) {
|
|
return false;
|
|
}
|
|
const char *expect_out = test->expect.value;
|
|
const char *regexp_out = test->regexp_out.value;
|
|
if (expect_out && !rz_test_cmp_cmd_output((char *)out->out, expect_out, regexp_out)) {
|
|
return false;
|
|
}
|
|
const char *expect_err = test->expect_err.value;
|
|
const char *regexp_err = test->regexp_err.value;
|
|
if (expect_err && !rz_test_cmp_cmd_output((char *)out->err, expect_err, regexp_err)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#define JQ_CMD "jq"
|
|
|
|
RZ_API bool rz_test_check_jq_available(void) {
|
|
const char *args[] = { "." };
|
|
const char *invalid_json = "this is not json lol";
|
|
RzSubprocess *proc = rz_subprocess_start(JQ_CMD, args, 1, NULL, NULL, 0);
|
|
if (proc) {
|
|
rz_subprocess_stdin_write(proc, (const ut8 *)invalid_json, strlen(invalid_json));
|
|
rz_subprocess_wait(proc, UT64_MAX);
|
|
}
|
|
bool invalid_detected = proc && rz_subprocess_ret(proc) != 0;
|
|
rz_subprocess_free(proc);
|
|
|
|
const char *valid_json = "{\"this is\":\"valid json\",\"lol\":true}";
|
|
proc = rz_subprocess_start(JQ_CMD, args, 1, NULL, NULL, 0);
|
|
if (proc) {
|
|
rz_subprocess_stdin_write(proc, (const ut8 *)valid_json, strlen(valid_json));
|
|
rz_subprocess_wait(proc, UT64_MAX);
|
|
}
|
|
bool valid_detected = proc && rz_subprocess_ret(proc) == 0;
|
|
rz_subprocess_free(proc);
|
|
|
|
return invalid_detected && valid_detected;
|
|
}
|
|
|
|
RZ_API RzSubprocessOutput *rz_test_run_json_test(RzTestRunConfig *config, RzJsonTest *test, RzTestCmdRunner runner, void *user) {
|
|
RzList *files = rz_list_new();
|
|
rz_list_push(files, (void *)config->json_test_file);
|
|
RzSubprocessOutput *ret = run_rz_test(config, config->timeout_ms, test->cmd, files, NULL, test->load_plugins, runner, user);
|
|
rz_list_free(files);
|
|
return ret;
|
|
}
|
|
|
|
RZ_API bool rz_test_check_json_test(RzSubprocessOutput *out, RzJsonTest *test) {
|
|
if (!out || out->ret != 0 || !out->out || !out->err || out->timeout) {
|
|
return false;
|
|
}
|
|
const char *args[] = { "." };
|
|
RzSubprocess *proc = rz_subprocess_start(JQ_CMD, args, 1, NULL, NULL, 0);
|
|
rz_subprocess_stdin_write(proc, (const ut8 *)out->out, strlen((char *)out->out));
|
|
rz_subprocess_wait(proc, UT64_MAX);
|
|
bool ret = rz_subprocess_ret(proc) == 0;
|
|
rz_subprocess_free(proc);
|
|
return ret;
|
|
}
|
|
|
|
RZ_API RzAsmTestOutput *rz_test_run_asm_test(RzTestRunConfig *config, RzAsmTest *test) {
|
|
RzAsmTestOutput *out = RZ_NEW0(RzAsmTestOutput);
|
|
if (!out) {
|
|
return NULL;
|
|
}
|
|
out->as_ret = out->disas_ret = out->il_ret = INT_MAX;
|
|
|
|
RzPVector args;
|
|
rz_pvector_init(&args, NULL);
|
|
|
|
if (test->arch) {
|
|
rz_pvector_push(&args, "-a");
|
|
rz_pvector_push(&args, (void *)test->arch);
|
|
}
|
|
|
|
if (test->cpu) {
|
|
rz_pvector_push(&args, "-c");
|
|
rz_pvector_push(&args, (void *)test->cpu);
|
|
}
|
|
|
|
char bits[0x20];
|
|
if (test->bits) {
|
|
snprintf(bits, sizeof(bits), "%d", test->bits);
|
|
rz_pvector_push(&args, "-b");
|
|
rz_pvector_push(&args, bits);
|
|
}
|
|
|
|
if (test->mode & RZ_ASM_TEST_MODE_BIG_ENDIAN) {
|
|
rz_pvector_push(&args, "-e");
|
|
}
|
|
|
|
char offset[0x20];
|
|
if (test->offset) {
|
|
rz_snprintf(offset, sizeof(offset), "0x%" PFMT64x, test->offset);
|
|
rz_pvector_push(&args, "-o");
|
|
rz_pvector_push(&args, offset);
|
|
}
|
|
|
|
if (test->mode & RZ_ASM_TEST_MODE_ASSEMBLE) {
|
|
rz_pvector_push(&args, test->disasm);
|
|
RzSubprocess *proc = rz_subprocess_start(config->rz_asm_cmd, args.v.a, rz_pvector_len(&args), NULL, NULL, 0);
|
|
if (rz_subprocess_wait(proc, config->timeout_ms) == RZ_SUBPROCESS_TIMEDOUT) {
|
|
rz_subprocess_kill(proc);
|
|
out->as_timeout = true;
|
|
goto rip;
|
|
}
|
|
char *as_err = (char *)crlf2lf(rz_subprocess_err(proc, NULL));
|
|
rz_str_trim(as_err);
|
|
out->as_err = as_err;
|
|
out->as_ret = rz_subprocess_ret(proc);
|
|
if (out->as_ret != 0) {
|
|
goto rip;
|
|
}
|
|
char *hex = (char *)crlf2lf(rz_subprocess_out(proc, NULL));
|
|
size_t hexlen = strlen(hex);
|
|
if (!hexlen) {
|
|
goto rip;
|
|
}
|
|
ut8 *bytes = malloc(hexlen);
|
|
int byteslen = rz_hex_str2bin(hex, bytes);
|
|
free(hex);
|
|
if (byteslen <= 0) {
|
|
free(bytes);
|
|
goto rip;
|
|
}
|
|
out->bytes = bytes;
|
|
out->bytes_size = (size_t)byteslen;
|
|
rip:
|
|
rz_pvector_pop(&args);
|
|
rz_subprocess_free(proc);
|
|
}
|
|
if (test->mode & RZ_ASM_TEST_MODE_DISASSEMBLE) {
|
|
char *hex = rz_hex_bin2strdup(test->bytes, test->bytes_size);
|
|
if (!hex) {
|
|
goto beach;
|
|
}
|
|
rz_pvector_push(&args, "-d");
|
|
rz_pvector_push(&args, hex);
|
|
RzSubprocess *proc = rz_subprocess_start(config->rz_asm_cmd, args.v.a, rz_pvector_len(&args), NULL, NULL, 0);
|
|
if (rz_subprocess_wait(proc, config->timeout_ms) == RZ_SUBPROCESS_TIMEDOUT) {
|
|
rz_subprocess_kill(proc);
|
|
out->disas_timeout = true;
|
|
goto ship;
|
|
}
|
|
char *disas_err = (char *)crlf2lf(rz_subprocess_err(proc, NULL));
|
|
rz_str_trim(disas_err);
|
|
out->disas_err = disas_err;
|
|
out->disas_ret = rz_subprocess_ret(proc);
|
|
if (out->disas_ret != 0) {
|
|
goto ship;
|
|
}
|
|
char *disasm = (char *)crlf2lf(rz_subprocess_out(proc, NULL));
|
|
rz_str_trim(disasm);
|
|
out->disasm = disasm;
|
|
ship:
|
|
free(hex);
|
|
rz_pvector_pop(&args);
|
|
rz_pvector_pop(&args);
|
|
rz_subprocess_free(proc);
|
|
}
|
|
if (test->il) {
|
|
char *hex = rz_hex_bin2strdup(test->bytes, test->bytes_size);
|
|
if (!hex) {
|
|
goto beach;
|
|
}
|
|
rz_pvector_push(&args, "-I");
|
|
rz_pvector_push(&args, hex);
|
|
RzSubprocess *proc = rz_subprocess_start(config->rz_asm_cmd, args.v.a, rz_pvector_len(&args), NULL, NULL, 0);
|
|
if (rz_subprocess_wait(proc, config->timeout_ms) == RZ_SUBPROCESS_TIMEDOUT) {
|
|
rz_subprocess_kill(proc);
|
|
out->il_timeout = true;
|
|
} else {
|
|
char *il = (char *)crlf2lf(rz_subprocess_out(proc, NULL));
|
|
rz_str_trim(il);
|
|
char *il_err = (char *)crlf2lf(rz_subprocess_err(proc, NULL));
|
|
rz_str_trim(il_err);
|
|
out->il = il;
|
|
out->il_err = il_err;
|
|
out->il_ret = rz_subprocess_ret(proc);
|
|
out->il_failed = out->il_ret != 0;
|
|
}
|
|
free(hex);
|
|
rz_pvector_pop(&args);
|
|
rz_pvector_pop(&args);
|
|
rz_subprocess_free(proc);
|
|
}
|
|
|
|
beach:
|
|
rz_pvector_clear(&args);
|
|
return out;
|
|
}
|
|
|
|
RZ_API bool rz_test_check_asm_test(RzAsmTestOutput *out, RzAsmTest *test) {
|
|
if (!out) {
|
|
return false;
|
|
}
|
|
if (test->mode & RZ_ASM_TEST_MODE_ASSEMBLE) {
|
|
if (!out->bytes || !test->bytes || out->bytes_size != test->bytes_size || out->as_timeout) {
|
|
return false;
|
|
}
|
|
if (memcmp(out->bytes, test->bytes, test->bytes_size) != 0) {
|
|
return false;
|
|
}
|
|
}
|
|
if (test->mode & RZ_ASM_TEST_MODE_DISASSEMBLE) {
|
|
if (!out->disasm || !test->disasm || out->as_timeout) {
|
|
return false;
|
|
}
|
|
if (strcmp(out->disasm, test->disasm) != 0) {
|
|
return false;
|
|
}
|
|
}
|
|
if (test->il) {
|
|
// expect some IL, no failure, no report and no timeout
|
|
if (!out->il || out->il_failed || RZ_STR_ISNOTEMPTY(out->il_err) || out->il_timeout) {
|
|
return false;
|
|
}
|
|
// IL must also be correct
|
|
if (strcmp(out->il, test->il) != 0) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
RZ_API void rz_test_asm_test_output_free(RzAsmTestOutput *out) {
|
|
if (!out) {
|
|
return;
|
|
}
|
|
free(out->disasm);
|
|
free(out->bytes);
|
|
free(out->il);
|
|
free(out->as_err);
|
|
free(out->disas_err);
|
|
free(out->il_err);
|
|
free(out);
|
|
}
|
|
|
|
RZ_API RzSubprocessOutput *rz_test_run_fuzz_test(RzTestRunConfig *config, RzFuzzTest *test, RzTestCmdRunner runner, void *user) {
|
|
const char *cmd = "aaa";
|
|
RzList *files = rz_list_new();
|
|
rz_list_push(files, test->file);
|
|
#if ASAN
|
|
if (rz_str_endswith(test->file, "/swift_read")) {
|
|
cmd = "?F";
|
|
}
|
|
#endif
|
|
RzSubprocessOutput *ret = run_rz_test(config, config->timeout_ms, cmd, files, NULL, false, runner, user);
|
|
rz_list_free(files);
|
|
return ret;
|
|
}
|
|
|
|
RZ_API bool rz_test_check_fuzz_test(RzSubprocessOutput *out) {
|
|
return out && out->ret == 0 && out->out && out->err && !out->timeout;
|
|
}
|
|
|
|
RZ_API char *rz_test_test_name(RzTest *test) {
|
|
switch (test->type) {
|
|
case RZ_TEST_TYPE_CMD:
|
|
if (test->cmd_test->name.value) {
|
|
return strdup(test->cmd_test->name.value);
|
|
}
|
|
return strdup("<unnamed>");
|
|
case RZ_TEST_TYPE_ASM:
|
|
return rz_str_newf("<asm> %s", test->asm_test->disasm ? test->asm_test->disasm : "");
|
|
case RZ_TEST_TYPE_JSON:
|
|
return rz_str_newf("<json> %s", test->json_test->cmd ? test->json_test->cmd : "");
|
|
case RZ_TEST_TYPE_FUZZ:
|
|
return rz_str_newf("<fuzz> %s", test->fuzz_test->file);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
RZ_API bool rz_test_broken(RzTest *test) {
|
|
switch (test->type) {
|
|
case RZ_TEST_TYPE_CMD:
|
|
return test->cmd_test->broken.value;
|
|
case RZ_TEST_TYPE_ASM:
|
|
return test->asm_test->mode & RZ_ASM_TEST_MODE_BROKEN ? true : false;
|
|
case RZ_TEST_TYPE_JSON:
|
|
return test->json_test->broken;
|
|
case RZ_TEST_TYPE_FUZZ:
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
RZ_API RzTestResultInfo *rz_test_run_test(RzTestRunConfig *config, RzTest *test) {
|
|
RzTestResultInfo *ret = RZ_NEW0(RzTestResultInfo);
|
|
if (!ret) {
|
|
return NULL;
|
|
}
|
|
ret->test = test;
|
|
bool success = false;
|
|
ut64 start_time = rz_time_now_mono();
|
|
switch (test->type) {
|
|
case RZ_TEST_TYPE_CMD: {
|
|
RzCmdTest *cmd_test = test->cmd_test;
|
|
RzSubprocessOutput *out = rz_test_run_cmd_test(config, cmd_test, subprocess_runner, NULL);
|
|
success = rz_test_check_cmd_test(out, cmd_test);
|
|
ret->proc_out = out;
|
|
ret->timeout = out && out->timeout;
|
|
ret->run_failed = !out;
|
|
break;
|
|
}
|
|
case RZ_TEST_TYPE_ASM: {
|
|
RzAsmTest *asm_test = test->asm_test;
|
|
RzAsmTestOutput *out = rz_test_run_asm_test(config, asm_test);
|
|
success = rz_test_check_asm_test(out, asm_test);
|
|
ret->asm_out = out;
|
|
if (out) {
|
|
ret->timeout = out->as_timeout || out->disas_timeout || out->il_timeout;
|
|
}
|
|
ret->run_failed = !out;
|
|
break;
|
|
}
|
|
case RZ_TEST_TYPE_JSON: {
|
|
RzJsonTest *json_test = test->json_test;
|
|
RzSubprocessOutput *out = rz_test_run_json_test(config, json_test, subprocess_runner, NULL);
|
|
success = rz_test_check_json_test(out, json_test);
|
|
ret->proc_out = out;
|
|
if (out) {
|
|
ret->timeout = out->timeout;
|
|
}
|
|
ret->run_failed = !out;
|
|
break;
|
|
}
|
|
case RZ_TEST_TYPE_FUZZ: {
|
|
RzFuzzTest *fuzz_test = test->fuzz_test;
|
|
RzSubprocessOutput *out = rz_test_run_fuzz_test(config, fuzz_test, subprocess_runner, NULL);
|
|
success = rz_test_check_fuzz_test(out);
|
|
ret->proc_out = out;
|
|
if (out) {
|
|
ret->timeout = out->timeout;
|
|
}
|
|
ret->run_failed = !out;
|
|
}
|
|
}
|
|
ret->time_elapsed = rz_time_now_mono() - start_time;
|
|
bool broken = rz_test_broken(test);
|
|
#if ASAN
|
|
#if !RZ_ASSERT_STDOUT
|
|
#error RZ_ASSERT_STDOUT undefined or 0
|
|
#endif
|
|
RzSubprocessOutput *out = ret->proc_out;
|
|
if (!success && test->type == RZ_TEST_TYPE_CMD && strstr(test->path, "/dbg") && (!out->out || (!strstr((char *)out->out, "WARNING:") && !strstr((char *)out->out, "ERROR:") && !strstr((char *)out->out, "FATAL:"))) && (!out->err || (!strstr((char *)out->err, "Sanitizer") && !strstr((char *)out->err, "runtime error:")))) {
|
|
broken = true;
|
|
}
|
|
#endif
|
|
if (!success) {
|
|
ret->result = broken ? RZ_TEST_RESULT_BROKEN : RZ_TEST_RESULT_FAILED;
|
|
} else {
|
|
ret->result = broken ? RZ_TEST_RESULT_FIXED : RZ_TEST_RESULT_OK;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
RZ_API void rz_test_test_result_info_free(RzTestResultInfo *result) {
|
|
if (!result) {
|
|
return;
|
|
}
|
|
if (result->test) {
|
|
switch (result->test->type) {
|
|
case RZ_TEST_TYPE_CMD:
|
|
case RZ_TEST_TYPE_JSON:
|
|
case RZ_TEST_TYPE_FUZZ:
|
|
rz_subprocess_output_free(result->proc_out);
|
|
break;
|
|
case RZ_TEST_TYPE_ASM:
|
|
rz_test_asm_test_output_free(result->asm_out);
|
|
break;
|
|
}
|
|
}
|
|
free(result);
|
|
}
|