X-Git-Url: http://plrg.eecs.uci.edu/git/?p=c11tester.git;a=blobdiff_plain;f=model.cc;h=f1df6ae8bfbbdacd806f56976de6b1c2f2bc8099;hp=66af988821af8ef491191a0cfb80151092ef38fd;hb=e45f16f22c8e36652a8f11f6f085ac43da24e1a8;hpb=86b818595e02c86250a17ed88f2d6af15a3141f3 diff --git a/model.cc b/model.cc index 66af9888..f1df6ae8 100644 --- a/model.cc +++ b/model.cc @@ -18,37 +18,74 @@ #include "history.h" #include "bugmessage.h" #include "params.h" +#include "plugins.h" ModelChecker *model = NULL; -/** Wrapper to run the user's main function, with appropriate arguments */ -void user_main_wrapper(void *) +void placeholder(void *) { + ASSERT(0); +} + +#include + +#define SIGSTACKSIZE 65536 +static void mprot_handle_pf(int sig, siginfo_t *si, void *unused) { - user_main(model->params.argc, model->params.argv); + model_print("Segmentation fault at %p\n", si->si_addr); + model_print("For debugging, place breakpoint at: %s:%d\n", + __FILE__, __LINE__); + print_trace(); // Trace printing may cause dynamic memory allocation + while(1) + ; +} + +void install_handler() { + stack_t ss; + ss.ss_sp = model_malloc(SIGSTACKSIZE); + ss.ss_size = SIGSTACKSIZE; + ss.ss_flags = 0; + sigaltstack(&ss, NULL); + struct sigaction sa; + sa.sa_flags = SA_SIGINFO | SA_NODEFER | SA_RESTART | SA_ONSTACK; + sigemptyset(&sa.sa_mask); + sa.sa_sigaction = mprot_handle_pf; + + if (sigaction(SIGSEGV, &sa, NULL) == -1) { + perror("sigaction(SIGSEGV)"); + exit(EXIT_FAILURE); + } + } /** @brief Constructor */ ModelChecker::ModelChecker() : /* Initialize default scheduler */ params(), - restart_flag(false), scheduler(new Scheduler()), - execution(new ModelExecution(this, scheduler)), history(new ModelHistory()), + execution(new ModelExecution(this, scheduler)), execution_number(1), trace_analyses(), inspect_plugin(NULL) { + model_print("C11Tester\n" + "Copyright (c) 2013 and 2019 Regents of the University of California. All rights reserved.\n" + "Distributed under the GPLv2\n" + "Written by Weiyu Luo, Brian Norris, and Brian Demsky\n\n"); memset(&stats,0,sizeof(struct execution_stats)); - init_thread = new Thread(execution->get_next_id(), (thrd_t *) model_malloc(sizeof(thrd_t)), &user_main_wrapper, NULL, NULL); // L: user_main_wrapper passes the user program + init_thread = new Thread(execution->get_next_id(), (thrd_t *) model_malloc(sizeof(thrd_t)), &placeholder, NULL, NULL); #ifdef TLS init_thread->setTLS((char *)get_tls_addr()); #endif execution->add_thread(init_thread); scheduler->set_current_thread(init_thread); + register_plugins(); execution->setParams(¶ms); param_defaults(¶ms); + parse_options(¶ms); initRaceDetector(); + /* Configure output redirection for the model-checker */ + install_handler(); } /** @brief Destructor */ @@ -77,7 +114,7 @@ void ModelChecker::reset_to_initial_state() for (unsigned int i = 0;i < get_num_threads();i++) delete get_thread(int_to_id(i))->get_pending(); - snapshot_backtrack_before(0); + snapshot_roll_back(snapshot); } /** @return the number of user threads created during this execution */ @@ -130,7 +167,7 @@ Thread * ModelChecker::get_next_thread() * @param msg Descriptive message for the bug (do not include newline char) * @return True if bug is immediately-feasible */ -bool ModelChecker::assert_bug(const char *msg, ...) +void ModelChecker::assert_bug(const char *msg, ...) { char str[800]; @@ -139,7 +176,7 @@ bool ModelChecker::assert_bug(const char *msg, ...) vsnprintf(str, sizeof(str), msg, ap); va_end(ap); - return execution->assert_bug(str); + execution->assert_bug(str); } /** @@ -150,8 +187,8 @@ bool ModelChecker::assert_bug(const char *msg, ...) void ModelChecker::assert_user_bug(const char *msg) { /* If feasible bug, bail out now */ - if (assert_bug(msg)) - switch_to_master(NULL); + assert_bug(msg); + switch_to_master(NULL); } /** @brief Print bug report listing for this execution (if any bugs exist) */ @@ -175,15 +212,12 @@ void ModelChecker::print_bugs() const void ModelChecker::record_stats() { stats.num_total ++; - if (!execution->isfeasibleprefix()) - stats.num_infeasible ++; - else if (execution->have_bug_reports()) + if (execution->have_bug_reports()) stats.num_buggy_executions ++; else if (execution->is_complete_execution()) stats.num_complete ++; else { - stats.num_redundant ++; - + //All threads are sleeping /** * @todo We can violate this ASSERT() when fairness/sleep sets * conflict to cause an execution to terminate, e.g. with: @@ -197,9 +231,7 @@ void ModelChecker::record_stats() void ModelChecker::print_stats() const { model_print("Number of complete, bug-free executions: %d\n", stats.num_complete); - model_print("Number of redundant executions: %d\n", stats.num_redundant); model_print("Number of buggy executions: %d\n", stats.num_buggy_executions); - model_print("Number of infeasible executions: %d\n", stats.num_infeasible); model_print("Total executions: %d\n", stats.num_total); } @@ -234,12 +266,11 @@ void ModelChecker::print_execution(bool printbugs) const * @return If there are more executions to explore, return true. Otherwise, * return false. */ -bool ModelChecker::next_execution() +void ModelChecker::finish_execution(bool more_executions) { DBG(); /* Is this execution a feasible execution that's worth bug-checking? */ - bool complete = execution->isfeasibleprefix() && - (execution->is_complete_execution() || + bool complete = (execution->is_complete_execution() || execution->have_bug_reports()); /* End-of-execution bug checks */ @@ -257,14 +288,12 @@ bool ModelChecker::next_execution() else clear_program_output(); - if (restart_flag) { - do_restart(); - return true; - } // test code execution_number ++; - reset_to_initial_state(); - return false; + if (more_executions) + reset_to_initial_state(); + + history->set_new_exec_flag(); } /** @brief Run trace analyses on complete trace */ @@ -353,16 +382,16 @@ static void runChecker() { void ModelChecker::startChecker() { startExecution(get_system_context(), runChecker); - snapshot_stack_init(); - snapshot_record(0); + snapshot = take_snapshot(); + + install_trace_analyses(get_execution()); + redirect_output(); + initMainThread(); } bool ModelChecker::should_terminate_execution() { - /* Infeasible -> don't take any more steps */ - if (execution->is_infeasible()) - return true; - else if (execution->isfeasibleprefix() && execution->have_fatal_bug_reports()) { + if (execution->have_bug_reports()) { execution->set_assert(); return true; } else if (execution->isFinished()) { @@ -371,38 +400,25 @@ bool ModelChecker::should_terminate_execution() return false; } -/** @brief Restart ModelChecker upon returning to the run loop of the - * model checker. */ -void ModelChecker::restart() -{ - restart_flag = true; -} - -void ModelChecker::do_restart() -{ - restart_flag = false; - reset_to_initial_state(); - memset(&stats,0,sizeof(struct execution_stats)); - execution_number = 1; -} - -void ModelChecker::startMainThread() { - init_thread->set_state(THREAD_RUNNING); - scheduler->set_current_thread(init_thread); - main_thread_startup(); -} - /** @brief Run ModelChecker for the user program */ void ModelChecker::run() { //Need to initial random number generator state to avoid resets on rollback char random_state[256]; initstate(423121, random_state, sizeof(random_state)); - + modelclock_t checkfree = params.checkthreshold; for(int exec = 0;exec < params.maxexecutions;exec++) { Thread * t = init_thread; do { + /* Check whether we need to free model actions. */ + + if (params.traceminsize != 0 && + execution->get_curr_seq_num() > checkfree) { + checkfree += params.checkthreshold; + execution->collectActions(); + } + /* * Stash next pending action(s) for thread(s). There * should only need to stash one thread's action--the @@ -412,8 +428,8 @@ void ModelChecker::run() for (unsigned int i = 0;i < get_num_threads();i++) { thread_id_t tid = int_to_id(i); Thread *thr = get_thread(tid); - if (!thr->is_model_thread() && !thr->is_complete() && (!thr->get_pending())) { - switch_from_master(thr); // L: context swapped, and action type of thr changed. + if (!thr->is_model_thread() && !thr->is_complete() && !thr->get_pending()) { + switch_from_master(thr); if (thr->is_waiting_on(thr)) assert_bug("Deadlock detected (thread %u)", i); } @@ -458,13 +474,19 @@ void ModelChecker::run() t = get_next_thread(); if (!t || t->is_model_thread()) break; + if (t->just_woken_up()) { + t->set_wakeup_state(false); + t->set_pending(NULL); + t = NULL; + continue; // Allow this thread to stash the next pending action + } /* Consume the next action for a Thread */ ModelAction *curr = t->get_pending(); t->set_pending(NULL); t = execution->take_step(curr); } while (!should_terminate_execution()); - next_execution(); + finish_execution((exec+1) < params.maxexecutions); //restore random number generator state after rollback setstate(random_state); } @@ -475,4 +497,9 @@ void ModelChecker::run() /* Have the trace analyses dump their output. */ for (unsigned int i = 0;i < trace_analyses.size();i++) trace_analyses[i]->finish(); + + /* unlink tmp file created by last child process */ + char filename[256]; + snprintf_(filename, sizeof(filename), "C11FuzzerTmp%d", getpid()); + unlink(filename); }