Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
8bf01108a30014bd8d3492ba8a3de9fa02442988
[simgrid.git] / src / mc / explo / Exploration.cpp
1 /* Copyright (c) 2016-2023. The SimGrid Team. All rights reserved.          */
2
3 /* This program is free software; you can redistribute it and/or modify it
4  * under the terms of the license (GNU LGPL) which comes with this package. */
5
6 #include "src/mc/explo/Exploration.hpp"
7 #include "src/mc/mc_config.hpp"
8 #include "src/mc/mc_environ.h"
9 #include "src/mc/mc_exit.hpp"
10 #include "src/mc/mc_private.hpp"
11 #include "xbt/string.hpp"
12
13 #if SIMGRID_HAVE_STATEFUL_MC
14 #include "src/mc/sosp/RemoteProcessMemory.hpp"
15 #endif
16
17 #include <sys/wait.h>
18
19 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_explo, mc, "Generic exploration algorithm of the model-checker");
20
21 namespace simgrid::mc {
22
23 static simgrid::config::Flag<std::string> cfg_dot_output_file{
24     "model-check/dot-output", "Name of dot output file corresponding to graph state", ""};
25
26 Exploration* Exploration::instance_ = nullptr; // singleton instance
27
28 Exploration::Exploration(const std::vector<char*>& args, bool need_memory_introspection)
29     : remote_app_(std::make_unique<RemoteApp>(args, need_memory_introspection))
30 {
31   xbt_assert(instance_ == nullptr, "Cannot have more than one exploration instance");
32   instance_ = this;
33
34   if (not cfg_dot_output_file.get().empty()) {
35     dot_output_ = fopen(cfg_dot_output_file.get().c_str(), "w");
36     xbt_assert(dot_output_ != nullptr, "Error open dot output file: %s", strerror(errno));
37
38     fprintf(dot_output_, "digraph graphname{\n fixedsize=true; rankdir=TB; ranksep=.25; edge [fontsize=12]; node "
39                          "[fontsize=10, shape=circle,width=.5 ]; graph [resolution=20, fontsize=10];\n");
40   }
41 }
42
43 Exploration::~Exploration()
44 {
45   if (dot_output_ != nullptr)
46     fclose(dot_output_);
47   instance_ = nullptr;
48 }
49
50 void Exploration::dot_output(const char* fmt, ...)
51 {
52   if (dot_output_ != nullptr) {
53     va_list ap;
54     va_start(ap, fmt);
55     vfprintf(dot_output_, fmt, ap);
56     va_end(ap);
57     fflush(dot_output_);
58   }
59 }
60
61 void Exploration::log_state()
62 {
63   if (not cfg_dot_output_file.get().empty()) {
64     dot_output("}\n");
65     fclose(dot_output_);
66   }
67   if (getenv(MC_ENV_SYSTEM_STATISTICS)) {
68     int ret = system("free");
69     if (ret != 0)
70       XBT_WARN("Call to system(free) did not return 0, but %d", ret);
71   }
72 }
73 // Make our tests fully reproducible despite the subtle differences of strsignal() across archs
74 static const char* signal_name(int status)
75 {
76   switch (WTERMSIG(status)) {
77     case SIGABRT: // FreeBSD uses "Abort trap" as a strsignal for SIGABRT
78       return "Aborted";
79     case SIGSEGV: // MacOSX uses "Segmentation fault: 11" for SIGKILL
80       return "Segmentation fault";
81     default:
82       return strsignal(WTERMSIG(status));
83   }
84 }
85
86 std::vector<std::string> Exploration::get_textual_trace()
87 {
88   std::vector<std::string> trace;
89   for (auto const& transition : get_record_trace())
90     trace.push_back(xbt::string_printf("%ld: %s", transition->aid_, transition->to_string().c_str()));
91   return trace;
92 }
93
94 XBT_ATTRIB_NORETURN void Exploration::report_crash(int status)
95 {
96   XBT_INFO("**************************");
97   XBT_INFO("** CRASH IN THE PROGRAM **");
98   XBT_INFO("**************************");
99   if (WIFSIGNALED(status))
100     XBT_INFO("From signal: %s", signal_name(status));
101   else if (WIFEXITED(status))
102     XBT_INFO("From exit: %i", WEXITSTATUS(status));
103   if (not xbt_log_no_loc)
104     XBT_INFO("%s core dump was generated by the system.", WCOREDUMP(status) ? "A" : "No");
105
106   XBT_INFO("Counter-example execution trace:");
107   for (auto const& s : get_textual_trace())
108     XBT_INFO("  %s", s.c_str());
109   XBT_INFO("You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with "
110            "--cfg=model-check/replay:'%s'",
111            get_record_trace().to_string().c_str());
112   log_state();
113   if (xbt_log_no_loc) {
114     XBT_INFO("Stack trace not displayed because you passed --log=no_loc");
115   } else {
116 #if SIMGRID_HAVE_STATEFUL_MC
117     const auto* memory = get_remote_app().get_remote_process_memory();
118     if (memory) {
119       XBT_INFO("Stack trace:");
120       memory->dump_stack();
121     } else
122 #endif
123       XBT_INFO("Stack trace not shown because there is no memory introspection.");
124   }
125
126   throw McError(ExitStatus::PROGRAM_CRASH);
127 }
128 XBT_ATTRIB_NORETURN void Exploration::report_assertion_failure()
129 {
130   XBT_INFO("**************************");
131   XBT_INFO("*** PROPERTY NOT VALID ***");
132   XBT_INFO("**************************");
133   XBT_INFO("Counter-example execution trace:");
134   for (auto const& s : get_textual_trace())
135     XBT_INFO("  %s", s.c_str());
136   XBT_INFO("You can debug the problem (and see the whole details) by rerunning out of simgrid-mc with "
137            "--cfg=model-check/replay:'%s'",
138            get_record_trace().to_string().c_str());
139   log_state();
140   throw McError(ExitStatus::SAFETY);
141 }
142
143 }; // namespace simgrid::mc