Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
sthread: Add a way to verify accesses to non-reentrant data structures
[simgrid.git] / src / sthread / ObjectAccess.cpp
1 /* Copyright (c) 2002-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 /* Object access checker, for use in sthread. */
7
8 #include "simgrid/modelchecker.h"
9 #include "simgrid/s4u/Actor.hpp"
10 #include "simgrid/simix.hpp"
11 #include "src/kernel/actor/ActorImpl.hpp"
12 #include "src/kernel/actor/SimcallObserver.hpp"
13 #include "src/sthread/sthread.h"
14
15 #include <unordered_map>
16
17 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(sthread);
18
19 namespace simgrid::sthread {
20 XBT_DECLARE_ENUM_CLASS(AccessType, ENTER, EXIT, BOTH);
21
22 class ObjectAccessObserver final : public simgrid::kernel::actor::SimcallObserver {
23   AccessType type_;
24   void* objaddr_;
25   const char* objname_;
26   const char* file_;
27   int line_;
28
29 public:
30   ObjectAccessObserver(simgrid::kernel::actor::ActorImpl* actor, AccessType type, void* objaddr, const char* objname,
31                        const char* file, int line)
32       : SimcallObserver(actor), type_(type), objaddr_(objaddr), objname_(objname), file_(file), line_(line)
33   {
34   }
35   void serialize(std::stringstream& stream) const override;
36   std::string to_string() const override;
37   bool is_visible() const override { return true; }
38 };
39 void ObjectAccessObserver::serialize(std::stringstream& stream) const
40 {
41   stream << (short)mc::Transition::Type::OBJECT_ACCESS << ' ';
42   stream << (short)type_ << ' ' << objaddr_ << ' ' << objname_ << ' ' << file_ << ' ' << line_;
43 }
44 std::string ObjectAccessObserver::to_string() const
45 {
46   return std::string("AccessObject(") + objname_ + ")";
47 }
48 }; // namespace simgrid::sthread
49
50 struct ObjectOwner {
51   simgrid::kernel::actor::ActorImpl* owner = nullptr;
52   const char* file                         = nullptr;
53   int line                                 = -1;
54   ObjectOwner(simgrid::kernel::actor::ActorImpl* o) : owner(o) {}
55 };
56
57 std::unordered_map<void*, ObjectOwner*> owners;
58 static void clean_owners()
59 {
60   for (auto it = owners.begin(); it != owners.end();) {
61     delete it->second;
62     it = owners.erase(it);
63   }
64 }
65 static ObjectOwner* get_owner(void* object)
66 {
67   if (owners.empty())
68     std::atexit(clean_owners);
69   auto it = owners.find(object);
70   if (it != owners.end())
71     return it->second;
72   auto* o = new ObjectOwner(nullptr);
73   owners.emplace(object, o);
74   return o;
75 }
76
77 int sthread_access_begin(void* objaddr, const char* objname, const char* file, int line)
78 {
79   sthread_disable();
80   auto* self = simgrid::kernel::actor::ActorImpl::self();
81   simgrid::sthread::ObjectAccessObserver observer(self, simgrid::sthread::AccessType::ENTER, objaddr, objname, file,
82                                                   line);
83   bool success = simgrid::kernel::actor::simcall_answered(
84       [self, objaddr, objname, file, line]() -> bool {
85         XBT_INFO("%s takes %s", self->get_cname(), objname);
86         auto* ownership = get_owner(objaddr);
87         if (ownership->owner != nullptr) {
88           XBT_CRITICAL("Unprotected concurent access to %s: %s at %s:%d vs. %s at %s:%d.", objname,
89                        ownership->owner->get_cname(), ownership->file, ownership->line, self->get_cname(), file, line);
90           return false;
91         }
92         ownership->owner = self;
93         ownership->file  = file;
94         ownership->line  = line;
95         return true;
96       },
97       &observer);
98   MC_assert(success);
99   xbt_assert(success, "Problem detected, bailing out");
100   sthread_enable();
101   return true;
102 }
103 void sthread_access_end(void* objaddr, const char* objname, const char* file, int line)
104 {
105   sthread_disable();
106   auto* self = simgrid::kernel::actor::ActorImpl::self();
107   simgrid::sthread::ObjectAccessObserver observer(self, simgrid::sthread::AccessType::EXIT, objaddr, objname, file,
108                                                   line);
109   simgrid::kernel::actor::simcall_answered(
110       [self, objaddr, objname, file, line]() -> void {
111         XBT_INFO("%s releases %s", self->get_cname(), objname);
112         auto* ownership = get_owner(objaddr);
113         xbt_assert(ownership->owner == self, "safety check failed: I'm not owner of the object I'm releasing.");
114         ownership->owner = nullptr;
115       },
116       &observer);
117   sthread_enable();
118 }