@@ -8,9 +8,9 @@ use genmc_sys::{
88use rustc_abi:: { Align , Size } ;
99use rustc_const_eval:: interpret:: { AllocId , InterpCx , InterpResult , interp_ok} ;
1010use rustc_data_structures:: fx:: FxHashMap ;
11- use rustc_middle:: { throw_machine_stop , throw_ub_format, throw_unsup_format} ;
11+ use rustc_middle:: { throw_ub_format, throw_unsup_format} ;
1212// FIXME(genmc,tracing): Implement some work-around for enabling debug/trace level logging (currently disabled statically in rustc).
13- use tracing:: { debug, info } ;
13+ use tracing:: debug;
1414
1515use self :: global_allocations:: { EvalContextExt as _, GlobalAllocationHandler } ;
1616use self :: helper:: {
@@ -63,12 +63,6 @@ struct ExitStatus {
6363 exit_type : ExitType ,
6464}
6565
66- impl ExitStatus {
67- fn do_leak_check ( self ) -> bool {
68- matches ! ( self . exit_type, ExitType :: MainThreadFinish )
69- }
70- }
71-
7266/// State that is reset at the start of every execution.
7367#[ derive( Debug , Default ) ]
7468struct PerExecutionState {
@@ -223,8 +217,6 @@ impl GenmcCtx {
223217
224218 /// Inform GenMC that the program's execution has ended.
225219 ///
226- /// This function must be called even when the execution is blocked
227- /// (i.e., it returned a `InterpErrorKind::MachineStop` with error kind `TerminationInfo::GenmcBlockedExecution`).
228220 /// Don't call this function if an error was found.
229221 ///
230222 /// GenMC detects certain errors only when the execution ends.
@@ -694,39 +686,37 @@ impl GenmcCtx {
694686 }
695687
696688 /// Handle a call to `libc::exit` or the exit of the main thread.
697- /// Unless an error is returned, the program should continue executing (in a different thread, chosen by the next scheduling call).
689+ /// Unless an error is returned, the program should continue executing (in a different thread,
690+ /// chosen by the next scheduling call).
698691 pub ( crate ) fn handle_exit < ' tcx > (
699692 & self ,
700693 thread : ThreadId ,
701694 exit_code : i32 ,
702695 exit_type : ExitType ,
703696 ) -> InterpResult < ' tcx > {
704- // Calling `libc::exit` doesn't do cleanup, so we skip the leak check in that case.
705- let exit_status = ExitStatus { exit_code, exit_type } ;
706-
707697 if let Some ( old_exit_status) = self . exec_state . exit_status . get ( ) {
708698 throw_ub_format ! (
709- "`exit` called twice, first with status {old_exit_status:?}, now with status {exit_status:?}" ,
699+ "`exit` called twice, first with exit code {old_exit_code}, now with status {exit_code}" ,
700+ old_exit_code = old_exit_status. exit_code,
710701 ) ;
711702 }
712703
713- // FIXME(genmc): Add a flag to continue exploration even when the program exits with a non-zero exit code.
714- if exit_code != 0 {
715- info ! ( "GenMC: 'exit' called with non-zero argument, aborting execution." ) ;
716- let leak_check = exit_status. do_leak_check ( ) ;
717- throw_machine_stop ! ( TerminationInfo :: Exit { code: exit_code, leak_check } ) ;
718- }
719-
720- if matches ! ( exit_type, ExitType :: ExitCalled ) {
721- let thread_infos = self . exec_state . thread_id_manager . borrow ( ) ;
722- let genmc_tid = thread_infos. get_genmc_tid ( thread) ;
723-
724- self . handle . borrow_mut ( ) . pin_mut ( ) . handle_thread_kill ( genmc_tid) ;
725- } else {
726- assert_eq ! ( thread, ThreadId :: MAIN_THREAD ) ;
704+ match exit_type {
705+ ExitType :: ExitCalled => {
706+ // `exit` kills the current thread; we have to tell GenMC about this.
707+ let thread_infos = self . exec_state . thread_id_manager . borrow ( ) ;
708+ let genmc_tid = thread_infos. get_genmc_tid ( thread) ;
709+ self . handle . borrow_mut ( ) . pin_mut ( ) . handle_thread_kill ( genmc_tid) ;
710+ }
711+ ExitType :: MainThreadFinish => {
712+ // The main thread has already exited so we don't call `handle_thread_kill` again.
713+ assert_eq ! ( thread, ThreadId :: MAIN_THREAD ) ;
714+ }
727715 }
728- // We continue executing now, so we store the exit status.
729- self . exec_state . exit_status . set ( Some ( exit_status) ) ;
716+ // To cover all possible behaviors, we have to continue execution the other threads:
717+ // whatever they do next could also have happened before the `exit` call. So we just
718+ // remember the exit status and use it when the other threads are done.
719+ self . exec_state . exit_status . set ( Some ( ExitStatus { exit_code, exit_type } ) ) ;
730720 interp_ok ( ( ) )
731721 }
732722}
0 commit comments