6060#include < signal.h>
6161#include < sys/stat.h>
6262#include < sys/wait.h>
63+ #include < thread>
6364#include < unistd.h>
6465
6566#include < cerrno>
@@ -154,6 +155,10 @@ cl::opt<bool> InteractiveMode("interactive",
154155 cl::desc (" Launch klee in interactive mode." ),
155156 cl::init(false ), cl::cat(StartCat));
156157
158+ cl::opt<int > TimeoutPerFunction (" timeout-per-function" ,
159+ cl::desc (" Timeout per function in klee." ),
160+ cl::init(0 ), cl::cat(StartCat));
161+
157162cl::opt<std::string>
158163 EntryPointsFile (" entrypoints-file" ,
159164 cl::desc (" Path to file with entrypoints name." ),
@@ -1575,6 +1580,43 @@ static int run_klee_on_function(
15751580 return 0 ;
15761581}
15771582
1583+ void kill_child (pid_t child_pid) {
1584+ if (kill (child_pid, 0 ) != 0 ) {
1585+ return ;
1586+ }
1587+ int statusSIGTERM = kill (child_pid, SIGTERM);
1588+ std::this_thread::sleep_for (std::chrono::milliseconds (10 ));
1589+ if (kill (child_pid, 0 ) == 0 ) {
1590+ int statusSIGKILL = kill (child_pid, SIGKILL);
1591+ if (statusSIGKILL != 0 ) {
1592+ klee_error (" Kill with signal SIGKILL return nonzero code." );
1593+ }
1594+ }
1595+ }
1596+
1597+ void wait_until_any_child_dies (const std::vector<std::pair<pid_t ,
1598+ std::chrono::time_point<std::chrono::steady_clock>>> &child_processes) {
1599+ while (true ) {
1600+ bool something_dead = false ;
1601+ for (const auto &child_process : child_processes) {
1602+ if (kill (child_process.first , 0 ) != 0 ) {
1603+ something_dead = true ;
1604+ }
1605+ auto current_time = std::chrono::steady_clock::now ();
1606+ auto duration_function = std::chrono::duration_cast<std::chrono::seconds>(current_time -
1607+ child_process.second ).count ();
1608+ if (duration_function > TimeoutPerFunction) {
1609+ kill_child (child_process.first );
1610+ something_dead = true ;
1611+ }
1612+ }
1613+ if (something_dead) {
1614+ break ;
1615+ }
1616+ std::this_thread::sleep_for (std::chrono::milliseconds (10 ));
1617+ }
1618+ }
1619+
15781620int run_klee (int argc, char **argv, char **envp) {
15791621 if (theInterpreter) {
15801622 theInterpreter = nullptr ;
@@ -1881,29 +1923,36 @@ int run_klee(int argc, char **argv, char **envp) {
18811923
18821924 SmallString<128 > outputDirectory = handler->getOutputDirectory ();
18831925 const int PROCESS = ProcessNumber;
1884- std::vector<pid_t > child_process;
1926+ using time_point = std::chrono::time_point<std::chrono::steady_clock>;
1927+ std::vector<std::pair<pid_t , time_point>> child_processes;
1928+ signal (SIGCHLD, SIG_IGN);
18851929 while (true ) {
18861930 std::string entrypoint;
18871931 if (!(entrypoints >> entrypoint)) {
18881932 break ;
18891933 }
18901934
1891- if (child_process.size () == PROCESS) {
1892- wait (NULL );
1935+ if (child_processes.size () == PROCESS) {
1936+ if (TimeoutPerFunction != 0 ) {
1937+ wait_until_any_child_dies (child_processes);
1938+ } else {
1939+ wait (NULL );
1940+ }
18931941 }
18941942
1895- std::vector<pid_t > alive_child;
1896- for (const pid_t child_id : child_process ) {
1897- if (kill (child_id , 0 ) == 0 ) {
1898- alive_child.push_back (child_id );
1943+ std::vector<std::pair< pid_t , time_point> > alive_child;
1944+ for (const auto &child_process : child_processes ) {
1945+ if (kill (child_process. first , 0 ) == 0 ) {
1946+ alive_child.push_back (child_process );
18991947 }
19001948 }
1901- child_process = alive_child;
1949+ child_processes = alive_child;
19021950
19031951 pid_t pid = fork ();
19041952 if (pid < 0 ) {
19051953 klee_error (" %s" , " Cannot create child process." );
19061954 } else if (pid == 0 ) {
1955+ signal (SIGCHLD, SIG_DFL);
19071956 EntryPoint = entrypoint;
19081957 SmallString<128 > newOutputDirectory = outputDirectory;
19091958 sys::path::append (newOutputDirectory, entrypoint);
@@ -1912,12 +1961,25 @@ int run_klee(int argc, char **argv, char **envp) {
19121961 finalModule, replayPath, loadedModules);
19131962 exit (0 );
19141963 } else {
1915- child_process. push_back (pid);
1964+ child_processes. emplace_back (pid, std::chrono::steady_clock::now () );
19161965 }
19171966 }
19181967
1919- while (wait (NULL ) > 0 )
1920- ;
1968+ if (TimeoutPerFunction != 0 ) {
1969+ while (!child_processes.empty ()) {
1970+ wait_until_any_child_dies (child_processes);
1971+
1972+ std::vector<std::pair<pid_t , time_point>> alive_child;
1973+ for (const auto &child_process : child_processes) {
1974+ if (kill (child_process.first , 0 ) == 0 ) {
1975+ alive_child.push_back (child_process);
1976+ }
1977+ }
1978+ child_processes = alive_child;
1979+ }
1980+ } else {
1981+ while (wait (NULL ) > 0 );
1982+ }
19211983 } else {
19221984 run_klee_on_function (pArgc, pArgv, pEnvp, handler, interpreter, finalModule,
19231985 replayPath, loadedModules);
0 commit comments