bool InputProcessor::check(InputGroup keyGroup) const { for (unsigned int i = 0; i < keyGroup.getKeyCount(); ++i) if (check(keyGroup.get(i))) return true; return false; }
// Return the specified queue of the specified input group. static InputQueue & queue(int igroup_id, InputQueueName qn) { InputGroup *ig = igroup(igroup_id); if (!ig) throw Exception("input group "+StringUtility::numberToString(igroup_id)+" does not exist"); return ig->queue(qn); }
// Return the input group with the specified ID, loading it from the database if necessary. static InputGroup * igroup(int igroup_id) { InputGroups::iterator found = igroup_cache.find(igroup_id); if (found!=igroup_cache.end()) return found->second; InputGroup *igroup = new InputGroup; if (!igroup->load(transaction, igroup_id)) { delete igroup; igroup_cache.insert(std::make_pair(igroup_id, (InputGroup*)0)); return NULL; } igroup_cache.insert(std::make_pair(igroup_id, igroup)); return igroup; }
bool InputGroup::containsAllOf(const InputGroup & input) const { for (std::vector<Input>::const_iterator it = myKeys.begin(); it != myKeys.end(); ++it) { if (!input.contains(*it)) return false; } return true; }
int main(int argc, char *argv[]) { std::ios::sync_with_stdio(); argv0 = argv[0]; { size_t slash = argv0.rfind('/'); argv0 = slash==std::string::npos ? argv0 : argv0.substr(slash+1); if (0==argv0.substr(0, 3).compare("lt-")) argv0 = argv0.substr(3); } // Parse switches Switches opt; int argno = 1, ngenerators = 0; for (/*void*/; argno<argc && '-'==argv[argno][0]; ++argno) { if (!strcmp(argv[argno], "--")) { ++argno; break; } else if (!strcmp(argv[argno], "--help") || !strcmp(argv[argno], "-h")) { usage(0); } else if (!strncmp(argv[argno], "--ngroups=", 10)) { opt.ngroups = strtoul(argv[argno]+10, NULL, 0); opt.ngroups_set = true; } else if (!strcmp(argv[argno], "--collection")) { opt.single_collection = true; } else if (!strncmp(argv[argno], "--collection=", 13)) { opt.collection_id = strtoul(argv[argno]+13, NULL, 0); opt.collection_id_set = opt.single_collection = true; } else if (!strncmp(argv[argno], "--default=", 10)) { opt.default_queue = parse_queuename(argv[argno]+10); } else if (!strcmp(argv[argno], "--memhash") || !strncmp(argv[argno], "--memhash=", 10)) { std::string s; if (char *equal = strchr(argv[argno], '=')) s = equal+1; std::vector<std::string> valargs = StringUtility::split(',', s, 3); valargs.resize(3); if (valargs[0].empty()) valargs[0] = "0"; if (valargs[1].empty()) valargs[1] = "255"; std::vector<std::string> randargs(1, "1"); randargs.push_back(valargs[2]); valargs.pop_back(); opt.queue_modifiers.push_back(new ValuesGenerator(IQ_MEMHASH, valargs)); opt.queue_modifiers.push_back(new RandomGenerator(IQ_MEMHASH, randargs)); ++ngenerators; } else { std::cerr <<argv0 <<": unrecognized switch: " <<argv[argno] <<"\n" <<"see \"" <<argv0 <<" --help\" for usage info.\n"; exit(1); } } if (!opt.ngroups_set) { std::cerr <<argv0 <<": missing --ngroups switch\n" <<argv0 <<": see --help for more info\n"; exit(1); } // Parse non-switch arguments (allow the database connection string to appear anywhere in this list since simplifies // the run-analysis.sh script. for (/*void*/; argno<argc; argno++) { std::vector<std::string> colon_parts = StringUtility::split(':', argv[argno], 2); InputQueueName qn = parse_queuename(colon_parts[0]); if (IQ_NONE!=qn && 2==colon_parts.size()) { std::vector<std::string> equal_parts = StringUtility::split('=', colon_parts[1], 2); std::string gname = equal_parts[0]; std::vector<std::string> args; try { if (2==equal_parts.size()) args = StringUtility::split(',', equal_parts[1], (size_t)-1, true); if (0==gname.compare("values")) { opt.queue_modifiers.push_back(new ValuesGenerator(qn, args)); } else if (0==gname.compare("set") || 0==gname.compare("reset")) { opt.queue_modifiers.push_back(new ResetGenerator(qn, args)); } else if (0==gname.compare("pad")) { opt.queue_modifiers.push_back(new PaddingGenerator(qn, args)); ++ngenerators; } else if (0==gname.compare("random")) { opt.queue_modifiers.push_back(new RandomGenerator(qn, args)); ++ngenerators; } else if (0==gname.compare("copy")) { opt.queue_modifiers.push_back(new CopyGenerator(qn, args)); ++ngenerators; } else if (0==gname.compare("permute")) { opt.queue_modifiers.push_back(new PermuteFilter(qn, args)); } else if (0==gname.compare("shuffle")) { opt.queue_modifiers.push_back(new ShuffleFilter(qn, args)); } else if (0==gname.compare("redirect")) { opt.queue_modifiers.push_back(new RedirectFilter(qn, args)); } else { std::cerr <<argv0 <<": unknown generator or filter name: " <<gname <<"\n"; exit(1); } } catch (const Exception &e) { std::cerr <<argv0 <<": " <<argv[argno] <<": " <<e <<"\n"; exit(1); } } else if (transaction==NULL) { transaction = SqlDatabase::Connection::create(argv[argno])->transaction(); } else { std::cerr <<argv0 <<": unknown generator or filter: " <<argv[argno] <<"\n"; exit(1); } } if (transaction==NULL) { std::cerr <<argv0 <<": missing database URL\n" <<argv0 <<": see --help for more info\n"; exit(1); } if (opt.queue_modifiers.empty()) { if (opt.ngroups>0) { std::cerr <<argv0 <<": no generators specified; all input groups would be empty\n"; exit(1); } else { exit(0); } } // Get the list of queues that are affected. std::vector<int> queue_modified(IQ_NQUEUES, 0); for (size_t i=0; i<opt.queue_modifiers.size(); ++i) queue_modified[opt.queue_modifiers[i]->queuename] = 1; // Generate the inputs int64_t cmd_id = start_command(transaction, argc, argv, "generating input groups"); int first_id = transaction->statement("select coalesce(max(igroup_id),-1)+1 from semantic_inputvalues")->execute_int(); if (!opt.collection_id_set) opt.collection_id = first_id; Progress progress(opt.ngroups); for (size_t gi=0; gi<opt.ngroups; ++gi) { ++progress; int igroup_id = first_id + gi; InputGroup igroup; igroup.set_collection_id(opt.single_collection ? opt.collection_id : igroup_id); // All queues initialize redirect to the default queue. If any generator or filter is applied, then // we don't do the default redirect. for (size_t qi=0; qi<IQ_NQUEUES; ++qi) { if (!queue_modified[qi]) igroup.queue((InputQueueName)qi).redirect(opt.default_queue); } // Build the queues for (size_t qmi=0; qmi<opt.queue_modifiers.size(); ++qmi) { QueueModifier *qm = opt.queue_modifiers[qmi]; qm->reseed(igroup_id); InputQueue &q = igroup.queue(qm->queuename); qm->operator()(q, igroup_id); } // Save all queues igroup.save(transaction, igroup_id, cmd_id); } progress.clear(); std::string desc = "generated "+StringUtility::numberToString(opt.ngroups)+" input group"+(1==opt.ngroups?"":"s")+ " starting at "+StringUtility::numberToString(first_id); if (opt.ngroups>0) { finish_command(transaction, cmd_id, desc); transaction->commit(); } std::cerr <<argv0 <<": " <<desc <<"\n"; return 0; }
void operator()() { // Database connections don't survive over fork() according to SqLite and PostgreSQL documentation, so open it again SqlDatabase::TransactionPtr tx = SqlDatabase::Connection::create(databaseUrl)->transaction(); // Use zero for the number of tests ran so that this child process doesn't try to update the semantic_history table. // If two or more processes try to change the same row (which they will if there's a non-zero number of tests) then // they will deadlock with each other. static const size_t NO_TESTS_RAN = 0; NameSet builtin_function_names; add_builtin_functions(builtin_function_names/*out*/); InputGroup igroup; WorkItem prevWorkItem; SgAsmInterpretation *prev_interp = NULL; MemoryMap ro_map; Disassembler::AddressSet whitelist_exports; // dynamic functions that should be called PointerDetectors pointers; InsnCoverage insn_coverage; DynamicCallGraph dynamic_cg; Tracer tracer; ConsumedInputs consumed_inputs; FuncAnalyses funcinfo; OutputGroups ogroups; // do not load from database (that might take a very long time) time_t last_checkpoint = time(NULL); for (size_t workIdx=0; workIdx<work.size(); ++workIdx) { WorkItem &workItem = work[workIdx]; // Load the input group from the database if necessary. if (workItem.igroup_id!=prevWorkItem.igroup_id) { if (!igroup.load(tx, workItem.igroup_id)) { std::cerr <<argv0 <<": input group " <<workItem.igroup_id <<" is empty or does not exist\n"; exit(1); } } // Find the function to test IdFunctionMap::iterator func_found = functions.find(workItem.func_id); assert(func_found!=functions.end()); SgAsmFunction *func = func_found->second; if (opt.verbosity>=LACONIC) { if (opt.verbosity>=EFFUSIVE) std::cerr <<argv0 <<": " <<std::string(100, '=') <<"\n"; std::cerr <<argv0 <<": processing function " <<function_to_str(func, function_ids) <<"\n"; } SgAsmInterpretation *interp = SageInterface::getEnclosingNode<SgAsmInterpretation>(func); assert(interp!=NULL); // Do per-interpretation stuff if (interp!=prev_interp) { prev_interp = interp; assert(interp->get_map()!=NULL); ro_map = *interp->get_map(); ro_map.require(MemoryMap::READABLE).prohibit(MemoryMap::WRITABLE).keep(); Disassembler::AddressSet whitelist_imports = get_import_addresses(interp, builtin_function_names); whitelist_exports.clear(); // imports are addresses of import table slots; exports are functions overmap_dynlink_addresses(interp, *insns, opt.params.follow_calls, &ro_map, GOTPLT_VALUE, whitelist_imports, whitelist_exports/*out*/); if (opt.verbosity>=EFFUSIVE) { std::cerr <<argv0 <<": memory map for SgAsmInterpretation:\n"; interp->get_map()->dump(std::cerr, argv0+": "); } } // Run the test assert(insns!=NULL); assert(entry2id!=NULL); std::cerr <<"process " <<getpid() <<" about to run test " <<workIdx <<"/" <<work.size() <<" " <<workItem <<"\n"; runOneTest(tx, workItem, pointers, func, function_ids, insn_coverage, dynamic_cg, tracer, consumed_inputs, interp, whitelist_exports, cmd_id, igroup, funcinfo, *insns, &ro_map, *entry2id, ogroups); ++ntests_ran; // Checkpoint if (opt.checkpoint>0 && time(NULL)-last_checkpoint > opt.checkpoint) { if (!opt.dry_run) tx = checkpoint(tx, ogroups, tracer, insn_coverage, dynamic_cg, consumed_inputs, NULL, NO_TESTS_RAN, cmd_id); last_checkpoint = time(NULL); } prevWorkItem = workItem; } std::cerr <<"process " <<getpid() <<" is done testing; now finishing up...\n"; if (!tx->is_terminated()) { SqlDatabase::StatementPtr stmt = tx->statement("insert into semantic_funcpartials" " (func_id, ncalls, nretused, ntests, nvoids) values" " (?, ?, ?, ?, ?)"); for (FuncAnalyses::iterator fi=funcinfo.begin(); fi!=funcinfo.end(); ++fi) { stmt->bind(0, fi->first); stmt->bind(1, fi->second.ncalls); stmt->bind(2, fi->second.nretused); stmt->bind(3, fi->second.ntests); stmt->bind(4, fi->second.nvoids); stmt->execute(); } } // Cleanup if (!tx->is_terminated() && !opt.dry_run) { std::cerr <<"process " <<getpid() <<" is doing the final checkpoint\n"; checkpoint(tx, ogroups, tracer, insn_coverage, dynamic_cg, consumed_inputs, NULL, NO_TESTS_RAN, cmd_id); } tx.reset(); std::cerr <<"process " <<getpid() <<" finished\n"; }
bool InputGroup::containsOnly(const InputGroup & input) const { return containsAllOf(input) && input.getKeyCount() == getKeyCount(); }