@@ -777,6 +777,16 @@ def run_message(
777777 reset (solver )
778778
779779
780+ def is_benign_solving_error (e : Exception ) -> bool :
781+ match e :
782+ case ShutdownError ():
783+ return True
784+ case OSError (errno = 9 ): # BAD_FILE_DESCRIPTOR
785+ return True
786+ case _:
787+ return False
788+
789+
780790@dataclass (frozen = True )
781791class CounterexampleHandler :
782792 """Handles potential assertion violations and generates counterexamples."""
@@ -856,13 +866,35 @@ def handle_assertion_violation(
856866 partial (
857867 self ._solve_end_to_end_callback ,
858868 ex = ex ,
869+ path_ctx = path_ctx ,
859870 description = description ,
860871 )
861872 )
862873 self .submitted_futures .append (solve_future )
863874
875+ def _get_solver_output (self , future : Future , path_ctx : PathContext ) -> SolverOutput :
876+ path_id , query_file = path_ctx .path_id , str (path_ctx .dump_file )
877+
878+ if self .ctx .solving_ctx .executor .is_shutdown ():
879+ # if the thread pool is in the process of shutting down,
880+ # we want to stop processing remaining models/timeouts/errors, etc.
881+ e = "executor has been shutdown"
882+ return SolverOutput .from_error (e , path_id = path_id , query_file = query_file )
883+
884+ if e := future .exception ():
885+ if not is_benign_solving_error (e ):
886+ error (f"encountered exception during assertion solving: { e !r} " )
887+ return SolverOutput .from_error (e , path_id = path_id , query_file = query_file )
888+
889+ try :
890+ return future .result ()
891+ except Exception as e :
892+ if not is_benign_solving_error (e ):
893+ error (f"encountered exception during assertion solving: { e !r} " )
894+ return SolverOutput .from_error (e , path_id = path_id , query_file = query_file )
895+
864896 def _solve_end_to_end_callback (
865- self , future : Future , ex : Exec , description : str
897+ self , future : Future , ex : Exec , path_ctx : PathContext , description : str
866898 ) -> None :
867899 """
868900 Callback function for handling solver results.
@@ -878,52 +910,19 @@ def _solve_end_to_end_callback(
878910 ctx = self .ctx
879911 args = ctx .args
880912
881- if ctx .solving_ctx .executor .is_shutdown ():
882- # if the thread pool is in the process of shutting down,
883- # we want to stop processing remaining models/timeouts/errors, etc.
884- return
885-
886- if e := future .exception ():
887- if isinstance (e , ShutdownError ):
888- return
889-
890- # we close file descriptors forcibly to avoid this issue:
891- # https://github.com/a16z/halmos/pull/527
892- if isinstance (e , OSError ) and e .errno == BAD_FILE_DESCRIPTOR :
893- return
894-
895- error (f"encountered exception during assertion solving: { e !r} " )
896- return
897-
898- #
899- # we are done solving, process and triage the result
900- #
901-
902- try :
903- solver_output : SolverOutput = future .result ()
904- except OSError as e :
905- if e .errno == BAD_FILE_DESCRIPTOR :
906- return
907-
908- # re-raise other OSErrors
909- raise
910-
913+ solver_output : SolverOutput = self ._get_solver_output (future , path_ctx )
914+ ctx .solver_outputs .append (solver_output )
911915 result , model = solver_output .result , solver_output .model
912916 path_id = solver_output .path_id
913917
914- # keep track of the solver outputs, so that we can display PASS/FAIL/TIMEOUT/ERROR later
915- ctx .solver_outputs .append (solver_output )
916-
917918 if result == unsat :
918919 if solver_output .unsat_core :
919920 ctx .append_unsat_core (solver_output .unsat_core )
920921 return
921922
922923 if result == "err" :
924+ error (f"{ solver_output .error = } ({ solver_output .returncode = } )" )
923925 self ._save_failed_query (path_id , solver_output , "error" )
924- error (
925- f"solver error: { solver_output .error } (returncode={ solver_output .returncode } )"
926- )
927926 return
928927
929928 # handle "unknown" (timeout) result
@@ -980,9 +979,9 @@ def _save_failed_query(
980979 ctx = self .ctx
981980 args = ctx .args
982981
982+ query_file = solver_output .query_file
983983 debug_dir = f"{ dirname (ctx .solving_ctx .dump_dir )} -{ failure_type } "
984984 os .makedirs (debug_dir , exist_ok = True )
985- query_file = solver_output .query_file
986985 debug_query_file = os .path .join (debug_dir , os .path .basename (query_file ))
987986 try :
988987 shutil .copy2 (query_file , debug_query_file )
0 commit comments