X-Git-Url: http://bilbo.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/dc7fd0d3417e20677162990b6896fe91b4c70306..c312320c2e43da49b536c51a9d19b6ad6d66e489:/src/mc/remote/CheckerSide.cpp diff --git a/src/mc/remote/CheckerSide.cpp b/src/mc/remote/CheckerSide.cpp index 2e64dd8449..211995b856 100644 --- a/src/mc/remote/CheckerSide.cpp +++ b/src/mc/remote/CheckerSide.cpp @@ -5,6 +5,7 @@ #include "src/mc/remote/CheckerSide.hpp" #include "src/mc/explo/Exploration.hpp" +#include "src/mc/mc_environ.h" #include "xbt/config.hpp" #include "xbt/system_error.hpp" @@ -56,7 +57,7 @@ XBT_ATTRIB_NORETURN static void run_child_process(int socket, const std::vector< setenv(MC_ENV_SOCKET_FD, std::to_string(socket).c_str(), 1); if (need_ptrace) - setenv("MC_NEED_PTRACE", "1", 1); + setenv(MC_ENV_NEED_PTRACE, "1", 1); /* Setup the tokenizer that parses the cfg:model-check/setenv parameter */ using Tokenizer = boost::tokenizer>; @@ -109,13 +110,14 @@ static void wait_application_process(pid_t pid) #elif defined BSD ptrace(PT_CONTINUE, pid, (caddr_t)1, 0); #else -#error "no ptrace equivalent coded for this platform" + xbt_die("no ptrace equivalent coded for this platform, stateful model-checking is impossible."); #endif xbt_assert(errno == 0, "Ptrace does not seem to be usable in your setup (errno: %d). " "If you run from within a docker, adding `--cap-add SYS_PTRACE` to the docker line may help. " "If it does not help, please report this bug.", errno); + XBT_DEBUG("%d ptrace correctly setup.", getpid()); } void CheckerSide::setup_events(bool socket_only) @@ -128,18 +130,22 @@ void CheckerSide::setup_events(bool socket_only) [](evutil_socket_t, short events, void* arg) { auto checker = static_cast(arg); if (events == EV_READ) { - std::array buffer; - ssize_t size = recv(checker->get_channel().get_socket(), buffer.data(), buffer.size(), MSG_DONTWAIT); - if (size == -1) { - XBT_ERROR("Channel::receive failure: %s", strerror(errno)); - if (errno != EAGAIN) - throw simgrid::xbt::errno_error(); - } - - if (size == 0) // The app closed the socket. It must be dead by now. - checker->handle_waitpid(); - else if (not checker->handle_message(buffer.data(), size)) - checker->break_loop(); + do { + std::array buffer; + ssize_t size = checker->get_channel().receive(buffer.data(), buffer.size(), MSG_DONTWAIT); + if (size == -1) { + XBT_ERROR("Channel::receive failure: %s", strerror(errno)); + if (errno != EAGAIN) + throw simgrid::xbt::errno_error(); + } + + if (size == 0) // The app closed the socket. It must be dead by now. + checker->handle_waitpid(); + else if (not checker->handle_message(buffer.data(), size)) { + checker->break_loop(); + break; + } + } while (checker->get_channel().has_pending_data()); } else { xbt_die("Unexpected event"); } @@ -173,11 +179,17 @@ CheckerSide::CheckerSide(const std::vector& args, bool need_memory_info) { XBT_DEBUG("Create a CheckerSide. Needs_meminfo: %s", need_memory_info ? "YES" : "no"); - // Create an AF_LOCAL socketpair used for exchanging messages between the model-checker process (ancestor) + // Create an AF_UNIX socketpair used for exchanging messages between the model-checker process (ancestor) // and the application process (child) int sockets[2]; - xbt_assert(socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, sockets) != -1, "Could not create socketpair: %s", - strerror(errno)); + xbt_assert(socketpair(AF_UNIX, +#ifdef __APPLE__ + SOCK_STREAM, /* Mac OSX does not have AF_UNIX + SOCK_SEQPACKET, even if that's faster */ +#else + SOCK_SEQPACKET, +#endif + 0, sockets) != -1, + "Could not create socketpair: %s", strerror(errno)); pid_ = fork(); xbt_assert(pid_ >= 0, "Could not fork application process"); @@ -230,7 +242,7 @@ CheckerSide::~CheckerSide() /* This constructor is called when cloning a checkerside to get its application to fork away */ CheckerSide::CheckerSide(int socket, CheckerSide* child_checker) - : channel_(socket), running_(true), child_checker_(child_checker) + : channel_(socket, child_checker->channel_), running_(true), child_checker_(child_checker) { setup_events(true); // We already have a signal handled in that case @@ -246,11 +258,12 @@ CheckerSide::CheckerSide(int socket, CheckerSide* child_checker) wait_for_requests(); } -std::unique_ptr CheckerSide::clone(int master_socket) +std::unique_ptr CheckerSide::clone(int master_socket, const std::string& master_socket_name) { - s_mc_message_int_t m = {}; - m.type = MessageType::FORK; - m.value = getpid(); + s_mc_message_fork_t m = {}; + m.type = MessageType::FORK; + xbt_assert(master_socket_name.size() == MC_SOCKET_NAME_LEN); + std::copy_n(begin(master_socket_name), MC_SOCKET_NAME_LEN, begin(m.socket_name)); xbt_assert(get_channel().send(m) == 0, "Could not ask the app to fork on need."); int sock = accept(master_socket, nullptr /* I know who's connecting*/, nullptr); @@ -288,15 +301,17 @@ void CheckerSide::break_loop() const bool CheckerSide::handle_message(const char* buffer, ssize_t size) { s_mc_message_t base_message; + ssize_t consumed; xbt_assert(size >= (ssize_t)sizeof(base_message), "Broken message. Got only %ld bytes.", size); memcpy(&base_message, buffer, sizeof(base_message)); switch (base_message.type) { case MessageType::IGNORE_HEAP: { + consumed = sizeof(s_mc_message_ignore_heap_t); #if SIMGRID_HAVE_STATEFUL_MC if (remote_memory_ != nullptr) { s_mc_message_ignore_heap_t message; - xbt_assert(size == sizeof(message), "Broken message"); + xbt_assert(size >= static_cast(sizeof(message)), "Broken message"); memcpy(&message, buffer, sizeof(message)); IgnoredHeapRegion region; @@ -312,10 +327,11 @@ bool CheckerSide::handle_message(const char* buffer, ssize_t size) } case MessageType::UNIGNORE_HEAP: { + consumed = sizeof(s_mc_message_ignore_memory_t); #if SIMGRID_HAVE_STATEFUL_MC if (remote_memory_ != nullptr) { s_mc_message_ignore_memory_t message; - xbt_assert(size == sizeof(message), "Broken message"); + xbt_assert(size == static_cast(sizeof(message)), "Broken message"); memcpy(&message, buffer, sizeof(message)); get_remote_memory()->unignore_heap((void*)message.addr, message.size); } else @@ -325,10 +341,11 @@ bool CheckerSide::handle_message(const char* buffer, ssize_t size) } case MessageType::IGNORE_MEMORY: { + consumed = sizeof(s_mc_message_ignore_memory_t); #if SIMGRID_HAVE_STATEFUL_MC if (remote_memory_ != nullptr) { s_mc_message_ignore_memory_t message; - xbt_assert(size == sizeof(message), "Broken message"); + xbt_assert(size >= static_cast(sizeof(message)), "Broken message"); memcpy(&message, buffer, sizeof(message)); get_remote_memory()->ignore_region(message.addr, message.size); } else @@ -338,10 +355,11 @@ bool CheckerSide::handle_message(const char* buffer, ssize_t size) } case MessageType::STACK_REGION: { + consumed = sizeof(s_mc_message_stack_region_t); #if SIMGRID_HAVE_STATEFUL_MC if (remote_memory_ != nullptr) { s_mc_message_stack_region_t message; - xbt_assert(size == sizeof(message), "Broken message"); + xbt_assert(size >= static_cast(sizeof(message)), "Broken message"); memcpy(&message, buffer, sizeof(message)); get_remote_memory()->stack_areas().push_back(message.stack_region); } else @@ -351,9 +369,10 @@ bool CheckerSide::handle_message(const char* buffer, ssize_t size) } case MessageType::REGISTER_SYMBOL: { + consumed = sizeof(s_mc_message_register_symbol_t); #if SIMGRID_HAVE_STATEFUL_MC s_mc_message_register_symbol_t message; - xbt_assert(size == sizeof(message), "Broken message"); + xbt_assert(size >= static_cast(sizeof(message)), "Broken message"); memcpy(&message, buffer, sizeof(message)); xbt_assert(not message.callback, "Support for client-side function proposition is not implemented."); XBT_DEBUG("Received symbol: %s", message.name.data()); @@ -366,15 +385,29 @@ bool CheckerSide::handle_message(const char* buffer, ssize_t size) } case MessageType::WAITING: + consumed = sizeof(s_mc_message_t); + if (size > consumed) { + XBT_DEBUG("%d reinject %d bytes after a %s message", getpid(), (int)(size - consumed), + to_c_str(base_message.type)); + channel_.reinject(&buffer[consumed], size - consumed); + } + return false; case MessageType::ASSERTION_FAILED: + // report_assertion_failure() is NORETURN, but it may change when we report more than one error per run, + // so please keep the consumed computation even if clang-static detects it as a dead affectation. + consumed = sizeof(s_mc_message_t); Exploration::get_instance()->report_assertion_failure(); break; default: xbt_die("Unexpected message from the application"); } + if (size > consumed) { + XBT_DEBUG("%d reinject %d bytes after a %s message", getpid(), (int)(size - consumed), to_c_str(base_message.type)); + channel_.reinject(&buffer[consumed], size - consumed); + } return true; } @@ -456,7 +489,6 @@ void CheckerSide::handle_waitpid() } } else { // Ask our proxy to wait for us - s_mc_message_int_t request = {}; request.type = MessageType::WAIT_CHILD; request.value = pid_;