// Return 1 if no children are running or zombies, 0 if there are any running // or zombie children. // Will wait for any already-terminated children first. // Passes if no rogue children were running, fails otherwise. // If your test gets a failure in here, either you're not killing all your // children, or you're not calling waitpid(2) on all of them. static bool no_running_children() { #ifndef _WIN32 pid_t wait_result; // Acknowledge and complain about any zombie children do { int status = 0; wait_result = waitpid(-1, &status, WNOHANG); if (wait_result > 0) { char buf[256]; snprintf(buf, sizeof(buf) - 1, "%d", wait_result); buf[sizeof(buf)-1] = '\0'; WVFAILEQSTR("Unclaimed dead child process", buf); } } while (wait_result > 0); // There should not be any running children, so waitpid should return -1 WVPASS(errno == ECHILD); WVPASS(wait_result == -1); return (wait_result == -1 && errno == ECHILD); #endif return true; }
/** * @brief Read input string into a disassembler using a Hexbyte input reader * * @param data byte string * @param dis disassembler * @param hir input reader * @param codeAddress code base address * @param expect_bytes number of bytes to read * @return void **/ static void inputToDisassembler(char const *data, Udis86Disassembler& dis, HexbyteInputReader& hir, Address codeAddress, unsigned expect_bytes) { std::vector<std::string> in; boost::split(in, data, boost::is_any_of(" ")); WVPASS(in.size() == expect_bytes); BOOST_FOREACH(std::string s, in) { hir.addData(s.c_str()); }
/** * @brief Test disassembly of a single instruction * * @param dis disassembler * @param memloc base address of instruction buffer (EIP - offset) * @param offset offset of instruction within buffer * @param len instruction length in bytes * @param repr instruction string representation * @param branch is a branch instruction Defaults to false. * @param release_mem release Instruction memory within this func or return a pointer to caller Defaults to true. * @return Instruction* **/ static Instruction * checkSequentialInstruction(Udis86Disassembler& dis, Address memloc, unsigned offset, unsigned len, char const *repr, bool branch = false, bool release_mem = true) { Instruction *i = dis.disassemble(Address(offset)); WVPASS(i); WVPASS(i->ip().v == (memloc.v + offset)); WVPASS(i->membase().v == dis.buffer().base.v + offset); WVPASS(i->length() == len); std::string str(i->c_str()); boost::trim(str); std::cout << "'" << str << "'" << " <-> '" << repr << "'" << std::endl; WVPASS(strcmp(str.c_str(), repr) == 0); WVPASS(i->isBranch() == branch); if (release_mem) { delete i; i = 0; } return i; }
int wvtest_run_all(char * const *prefixes) { int old_valgrind_errs = 0, new_valgrind_errs; int old_valgrind_leaks = 0, new_valgrind_leaks; #ifdef _WIN32 /* I should be doing something to do with SetTimer here, * not sure exactly what just yet */ #else char *disable = getenv("WVTEST_DISABLE_TIMEOUT"); if (disable != NULL && disable[0] != '\0' && disable[0] != '0') signal(SIGALRM, SIG_IGN); else signal(SIGALRM, alarm_handler); alarm(MAX_TEST_TIME); #endif start_time = time(NULL); // make sure we can always start out in the same directory, so tests have // access to their files. If a test uses chdir(), we want to be able to // reverse it. char wd[1024]; if (!getcwd(wd, sizeof(wd))) strcpy(wd, "."); const char *slowstr1 = getenv("WVTEST_MIN_SLOWNESS"); const char *slowstr2 = getenv("WVTEST_MAX_SLOWNESS"); int min_slowness = 0, max_slowness = 65535; if (slowstr1) min_slowness = atoi(slowstr1); if (slowstr2) max_slowness = atoi(slowstr2); #ifdef _WIN32 run_twice = false; #else char *parallel_str = getenv("WVTEST_PARALLEL"); if (parallel_str) run_twice = atoi(parallel_str) > 0; #endif // there are lots of fflush() calls in here because stupid win32 doesn't // flush very often by itself. fails = runs = 0; struct WvTest *cur; for (cur = wvtest_first; cur != NULL; cur = cur->next) { if (cur->slowness <= max_slowness && cur->slowness >= min_slowness && (!prefixes || prefix_match(cur->idstr, prefixes) || prefix_match(cur->descr, prefixes))) { #ifndef _WIN32 // set SIGPIPE back to default, helps catch tests which don't set // this signal to SIG_IGN (which is almost always what you want) // on startup signal(SIGPIPE, SIG_DFL); pid_t child = 0; if (run_twice) { // I see everything twice! printf("Running test in parallel.\n"); child = fork(); } #endif printf("\nTesting \"%s\" in %s:\n", cur->descr, cur->idstr); fflush(stdout); cur->main(); chdir(wd); new_valgrind_errs = memerrs(); WVPASS(new_valgrind_errs == old_valgrind_errs); old_valgrind_errs = new_valgrind_errs; new_valgrind_leaks = memleaks(); WVPASS(new_valgrind_leaks == old_valgrind_leaks); old_valgrind_leaks = new_valgrind_leaks; fflush(stderr); printf("\n"); fflush(stdout); #ifndef _WIN32 if (run_twice) { if (!child) { // I see everything once! printf("Child exiting.\n"); _exit(0); } else { printf("Waiting for child to exit.\n"); int result; while ((result = waitpid(child, NULL, 0)) == -1 && errno == EINTR) printf("Waitpid interrupted, retrying.\n"); } } #endif WVPASS(no_running_children()); } } WVPASS(runs > 0); if (prefixes && *prefixes && **prefixes) printf("WvTest: WARNING: only ran tests starting with " "specifed prefix(es).\n"); else printf("WvTest: ran all tests.\n"); printf("WvTest: %d test%s, %d failure%s.\n", runs, runs==1 ? "" : "s", fails, fails==1 ? "": "s"); fflush(stdout); return fails != 0; }