Mir

Merge lp:~albaguirre/mir/fix-1433330 into lp:mir

Proposed by Alberto Aguirre
Status: Merged
Approved by: Alberto Aguirre
Approved revision: no longer in the source branch.
Merged at revision: 2406
Proposed branch: lp:~albaguirre/mir/fix-1433330
Merge into: lp:mir
Diff against target: 151 lines (+45/-18)
4 files modified
cmake/MirCommon.cmake (+0/-1)
src/server/frontend/protobuf_message_processor.cpp (+42/-15)
src/server/frontend/protobuf_message_processor.h (+2/-1)
tests/unit-tests/frontend/test_protobuf_message_processor.cpp (+1/-1)
To merge this branch: bzr merge lp:~albaguirre/mir/fix-1433330
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Kevin DuBois (community) Approve
Alexandros Frantzis (community) Approve
Alan Griffiths Approve
Review via email: mp+253285@code.launchpad.net

Commit message

Fix calling dead objects from some protobuf closure objects.

Since the closure/callback object may be invoked by a different thread in some instances (e.g. SessionMediator::exchange_buffer), the closure object now gets a weak_ptr to the ProtobufMessageProcessor (instead of a raw pointer).

Description of the change

Fix calling dead objects from some protobuf closure objects.

Since the closure/callback object may be invoked by a different thread in some instances (e.g. SessionMediator::exchange_buffer), the closure object now gets a weak_ptr to the ProtobufMessageProcessor (instead of a raw pointer).

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

29 + callback();
30 + delete this;

We should ensure that 'this' is deleted even if callback() throws.

Looks good otherwise.

review: Needs Fixing
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

20 +class SelfDeletingCallback : public google::protobuf::Closure {
21 +public:
22 +
23 + SelfDeletingCallback(std::function<void()> const& callback)
24 + : callback(callback)
25 + {
26 + }
27 +
28 + void Run() {
29 + callback();
30 + delete this;
31 + }
32 +
33 + private:
34 + SelfDeletingCallback(SelfDeletingCallback&) = delete;
35 + void operator=(const SelfDeletingCallback&) = delete;
36 + std::function<void()> callback;
37 +};

Why is this needed? google::protobuf::NewCallback<> deletes itself. (NewPermanentCallback<> is the version that doesn't).

And as Alexandros says, callbacks could throw.

review: Needs Fixing
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

> 20 +class SelfDeletingCallback : public google::protobuf::Closure {
> 21 +public:
> 22 +
> 23 + SelfDeletingCallback(std::function<void()> const& callback)
> 24 + : callback(callback)
> 25 + {
> 26 + }
> 27 +
> 28 + void Run() {
> 29 + callback();
> 30 + delete this;
> 31 + }
> 32 +
> 33 + private:
> 34 + SelfDeletingCallback(SelfDeletingCallback&) = delete;
> 35 + void operator=(const SelfDeletingCallback&) = delete;
> 36 + std::function<void()> callback;
> 37 +};
>
> Why is this needed? google::protobuf::NewCallback<> deletes itself.
> (NewPermanentCallback<> is the version that doesn't).

The code in question used to use google::protobuf::NewCallback<>. I need to be able to promote a weak_ptr within Run() so I can't use it as is. I don't want to change any Protobuf related code hence SelfDeletingCallback.

> And as Alexandros says, callbacks could throw.
OK.

Revision history for this message
Alberto Aguirre (albaguirre) wrote :

> 29 + callback();
> 30 + delete this;
>
> We should ensure that 'this' is deleted even if callback() throws.
>
> Looks good otherwise.

Will fix.
Note all ::google::protobuf::Closure implementations have the same issue.

Revision history for this message
Kevin DuBois (kdub) wrote :

20 +class SelfDeletingCallback : public google::protobuf::Closure {
indentation

28 + void Run()
override?

also, something like this would unintuitively double-free:
{
  auto c = std::make_unique<SelfDeletingCallback>();
  c->Run();
}
maybe make ~SelfDeletingCallback() private to avoid.

review: Needs Fixing
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

OK

review: Approve
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

Looks good.

review: Approve
Revision history for this message
Kevin DuBois (kdub) wrote :

lgtm too

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

^---Ummm, can't replicate locally and can't tell if it is related to this MP. Let's try re-triggering a build.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'cmake/MirCommon.cmake'
2--- cmake/MirCommon.cmake 2015-03-13 05:22:41 +0000
3+++ cmake/MirCommon.cmake 2015-03-18 16:01:57 +0000
4@@ -98,7 +98,6 @@
5 set(EXCLUDED_TESTS "UnresponsiveClient.does_not_hang_server:DemoInProcessServerWithStubClientPlatform.surface_creation_does_not_leak_fds:StreamTransportTest/0.SendsFullMessagesWhenInterrupted")
6 endif()
7
8- message("What is this: " "${EXECUTABLE_OUTPUT_PATH}/${EXECUTABLE} --gtest_list_tests ${EXCLUDED_TESTS}")
9 add_custom_target(
10 ${TEST_DISCOVERY_TARGET_NAME} ALL
11 ${EXECUTABLE_OUTPUT_PATH}/${EXECUTABLE} --gtest_list_tests | ${CMAKE_BINARY_DIR}/mir_gtest/mir_discover_gtest_tests --executable=${EXECUTABLE_OUTPUT_PATH}/${EXECUTABLE} --exclusions=${EXCLUDED_TESTS} ${DISCOVER_FLAGS}
12
13=== modified file 'src/server/frontend/protobuf_message_processor.cpp'
14--- src/server/frontend/protobuf_message_processor.cpp 2015-02-18 05:27:28 +0000
15+++ src/server/frontend/protobuf_message_processor.cpp 2015-03-18 16:01:57 +0000
16@@ -74,9 +74,35 @@
17 return request;
18 }
19
20+class SelfDeletingCallback : public google::protobuf::Closure
21+{
22+public:
23+ SelfDeletingCallback(std::function<void()> const& callback)
24+ : callback(callback)
25+ {
26+ }
27+
28+ void Run() override
29+ {
30+ struct Deleter
31+ {
32+ ~Deleter() { delete obj; }
33+ SelfDeletingCallback* obj;
34+ };
35+ Deleter deleter{this};
36+ callback();
37+ }
38+
39+ private:
40+ ~SelfDeletingCallback() = default;
41+ SelfDeletingCallback(SelfDeletingCallback&) = delete;
42+ void operator=(const SelfDeletingCallback&) = delete;
43+ std::function<void()> callback;
44+};
45+
46 template<typename RequestType, typename ResponseType>
47 void invoke(
48- ProtobufMessageProcessor* self,
49+ std::shared_ptr<ProtobufMessageProcessor> const& mp,
50 DisplayServer* server,
51 void (mir::protobuf::DisplayServer::*function)(
52 ::google::protobuf::RpcController* controller,
53@@ -88,15 +114,17 @@
54 {
55 auto const result_message = std::make_shared<ResponseType>();
56
57- auto const callback =
58- google::protobuf::NewCallback<
59- ProtobufMessageProcessor,
60- ::google::protobuf::uint32,
61- std::shared_ptr<ResponseType>>(
62- self,
63- &ProtobufMessageProcessor::send_response,
64- invocation_id,
65- result_message);
66+ std::weak_ptr<ProtobufMessageProcessor> weak_mp = mp;
67+ auto const response_callback = [weak_mp, invocation_id, result_message]
68+ {
69+ auto message_processor = weak_mp.lock();
70+ if (message_processor)
71+ {
72+ message_processor->send_response(invocation_id, result_message);
73+ }
74+ };
75+
76+ auto callback = new SelfDeletingCallback{response_callback};
77
78 try
79 {
80@@ -108,9 +136,8 @@
81 }
82 catch (std::exception const& x)
83 {
84- delete callback;
85 result_message->set_error(boost::diagnostic_information(x));
86- self->send_response(invocation_id, result_message);
87+ callback->Run();
88 }
89 }
90
91@@ -179,7 +206,7 @@
92 else if ("next_buffer" == invocation.method_name())
93 {
94 auto request = parse_parameter<mir::protobuf::SurfaceId>(invocation);
95- invoke(this, display_server.get(), &DisplayServer::next_buffer, invocation.id(), &request);
96+ invoke(shared_from_this(), display_server.get(), &DisplayServer::next_buffer, invocation.id(), &request);
97 }
98 else if ("exchange_buffer" == invocation.method_name())
99 {
100@@ -187,7 +214,7 @@
101 request.mutable_buffer()->clear_fd();
102 for (auto& fd : side_channel_fds)
103 request.mutable_buffer()->add_fd(fd);
104- invoke(this, display_server.get(), &DisplayServer::exchange_buffer, invocation.id(), &request);
105+ invoke(shared_from_this(), display_server.get(), &DisplayServer::exchange_buffer, invocation.id(), &request);
106 }
107 else if ("release_surface" == invocation.method_name())
108 {
109@@ -205,7 +232,7 @@
110 for (auto& fd : side_channel_fds)
111 request.add_fd(fd);
112
113- invoke(this, display_server.get(), &DisplayServer::platform_operation,
114+ invoke(shared_from_this(), display_server.get(), &DisplayServer::platform_operation,
115 invocation.id(), &request);
116 }
117 else if ("configure_display" == invocation.method_name())
118
119=== modified file 'src/server/frontend/protobuf_message_processor.h'
120--- src/server/frontend/protobuf_message_processor.h 2015-01-21 07:34:50 +0000
121+++ src/server/frontend/protobuf_message_processor.h 2015-03-18 16:01:57 +0000
122@@ -37,7 +37,8 @@
123 class DisplayServer;
124 class ProtobufMessageSender;
125
126-class ProtobufMessageProcessor : public MessageProcessor
127+class ProtobufMessageProcessor : public MessageProcessor,
128+ public std::enable_shared_from_this<ProtobufMessageProcessor>
129 {
130 public:
131 ProtobufMessageProcessor(
132
133=== modified file 'tests/unit-tests/frontend/test_protobuf_message_processor.cpp'
134--- tests/unit-tests/frontend/test_protobuf_message_processor.cpp 2015-02-18 05:27:28 +0000
135+++ tests/unit-tests/frontend/test_protobuf_message_processor.cpp 2015-03-18 16:01:57 +0000
136@@ -87,6 +87,7 @@
137 mt::fake_shared(stub_msg_sender),
138 mt::fake_shared(stub_display_server),
139 mt::fake_shared(stub_report));
140+ std::shared_ptr<mfd::MessageProcessor> mp = mt::fake_shared(pb_message_processor);
141
142 mpw::Invocation raw_invocation;
143 mp::BufferRequest buffer_request;
144@@ -97,7 +98,6 @@
145 mfd::Invocation invocation(raw_invocation);
146
147 std::vector<mir::Fd> fds;
148- mfd::MessageProcessor* mp = &pb_message_processor;
149 mp->dispatch(invocation, fds);
150
151 ASSERT_THAT(stub_display_server.exchange_buffer_response, testing::Ne(nullptr));

Subscribers

People subscribed via source and target branches