Skip to content

Commit 78fd185

Browse files
Fix typed proxy access to generic skeleton event storage
Signed-off-by: Rudresh Shirwal <rudresh.shirwal@systream.io>
1 parent 1e03b31 commit 78fd185

7 files changed

Lines changed: 150 additions & 11 deletions

File tree

score/mw/com/impl/bindings/lola/proxy_event.h

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@
1414
#define SCORE_MW_COM_IMPL_BINDINGS_LOLA_PROXY_EVENT_H
1515

1616
#include "score/mw/com/impl/bindings/lola/event_data_storage.h"
17+
#include "score/mw/com/impl/bindings/lola/event_meta_info.h"
1718
#include "score/mw/com/impl/bindings/lola/proxy_event_common.h"
19+
20+
#include "score/language/safecpp/safe_math/safe_math.h"
21+
#include "score/memory/shared/pointer_arithmetic_util.h"
1822
#include "score/mw/com/impl/proxy_event_binding.h"
1923
#include "score/mw/com/impl/sample_reference_tracker.h"
2024
#include "score/mw/com/impl/subscription_state.h"
@@ -64,7 +68,7 @@ class ProxyEvent final : public ProxyEventBinding<SampleType>
6468
ProxyEvent(Proxy& parent, const ElementFqId element_fq_id, const std::string_view event_name)
6569
: ProxyEventBinding<SampleType>{},
6670
proxy_event_common_{parent, element_fq_id, event_name},
67-
samples_{parent.GetEventDataStorage<SampleType>(element_fq_id)}
71+
meta_info_{parent.GetEventMetaInfo(element_fq_id)}
6872
{
6973
}
7074

@@ -126,7 +130,7 @@ class ProxyEvent final : public ProxyEventBinding<SampleType>
126130
Result<std::size_t> GetNumNewSamplesAvailableImpl() const noexcept;
127131

128132
ProxyEventCommon proxy_event_common_;
129-
const EventDataStorage<SampleType>& samples_;
133+
const EventMetaInfo& meta_info_;
130134
};
131135

132136
template <typename SampleType>
@@ -184,9 +188,40 @@ inline Result<std::size_t> ProxyEvent<SampleType>::GetNewSamplesImpl(Callback&&
184188

185189
auto& event_data_control_local = proxy_event_common_.GetConsumerEventDataControlLocal();
186190

191+
const std::size_t aligned_sample_size =
192+
memory::shared::CalculateAlignedSize(sizeof(SampleType), alignof(SampleType));
193+
const auto event_slots_raw_array_size =
194+
safe_math::Multiply(aligned_sample_size, event_data_control_local.GetMaxSampleSlots());
195+
if (!event_slots_raw_array_size.has_value())
196+
{
197+
score::mw::log::LogFatal("lola") << "Could not calculate the event slots raw array size. Terminating.";
198+
std::terminate();
199+
}
200+
201+
const void* const event_slots_raw_array = meta_info_.event_slots_raw_array_.get(event_slots_raw_array_size.value());
202+
SCORE_LANGUAGE_FUTURECPP_PRECONDITION_PRD_MESSAGE(nullptr != event_slots_raw_array, "Null event slot array");
203+
SCORE_LANGUAGE_FUTURECPP_PRECONDITION_PRD_MESSAGE(meta_info_.data_type_info_.size == sizeof(SampleType),
204+
"Event sample size mismatch");
205+
SCORE_LANGUAGE_FUTURECPP_PRECONDITION_PRD_MESSAGE(meta_info_.data_type_info_.alignment == alignof(SampleType),
206+
"Event sample alignment mismatch");
207+
187208
for (auto slot_index_it = slot_indices.begin; slot_index_it != slot_indices.end; ++slot_index_it)
188209
{
189-
const SampleType& sample_data{samples_.at(static_cast<std::size_t>(*slot_index_it))};
210+
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) The pointer event_slots_raw_array points to
211+
// the first byte of the type-erased event sample storage in shared memory. Samples may originate from either a
212+
// typed SkeletonEvent or a GenericSkeletonEvent, therefore slot lookup must use the stable EventMetaInfo raw
213+
// storage address and SampleType stride instead of interpreting the shared-memory DynamicArray object type.
214+
const auto* const event_slots_array = static_cast<const std::uint8_t*>(event_slots_raw_array);
215+
const auto* const object_start_address = &event_slots_array[aligned_sample_size * (*slot_index_it)];
216+
// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
217+
218+
// Suppress "AUTOSAR C++14 M5-2-8" rule finding: "An object with integer type or pointer to void type shall
219+
// not be converted to an object with pointer type.".
220+
// The raw storage address is provided through EventMetaInfo. The regular typed proxy validates the expected
221+
// type at compile time and calculates the slot offset with sizeof(SampleType)/alignof(SampleType).
222+
// coverity[autosar_cpp14_m5_2_8_violation]
223+
const auto* const typed_sample_data = reinterpret_cast<const SampleType*>(object_start_address);
224+
const SampleType& sample_data{*typed_sample_data};
190225
const EventSlotStatus event_slot_status{event_data_control_local[*slot_index_it]};
191226
const EventSlotStatus::EventTimeStamp sample_timestamp{event_slot_status.GetTimeStamp()};
192227

score/mw/com/impl/bindings/lola/proxy_event_test.cpp

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,35 @@ TYPED_TEST(LolaProxyEventDeathTest, FailOnEventNotFound)
693693
}
694694

695695
using LoLaTypedProxyEventTestFixture = LolaProxyEventFixture<ProxyEventStruct>;
696+
TEST_F(LoLaTypedProxyEventTestFixture, ReadsSamplesFromGenericSkeletonRawStorage)
697+
{
698+
RecordProperty("Verifies", "SCR-6225206");
699+
RecordProperty("Description",
700+
"Checks that a typed ProxyEvent reads samples from EventMetaInfo raw storage so it is compatible "
701+
"with a GenericSkeletonEvent storage representation.");
702+
RecordProperty("TestType", "Regression test");
703+
RecordProperty("DerivationTechnique", "Analysis of bug 311");
704+
705+
this->ReplaceDummySkeletonEventStorageWithGenericSkeletonLayout();
706+
const std::size_t max_sample_count_subscription{5U};
707+
this->GivenAProxyEvent(this->element_fq_id_, this->event_name_)
708+
.ThatIsSubscribedWithMaxSamples(max_sample_count_subscription)
709+
.WithSkeletonEventData({{kDummySampleValue, kDummyInputTimestamp}});
710+
711+
const std::size_t max_samples{1U};
712+
TestSampleType received_sample{0U};
713+
const auto receiver = [&received_sample](impl::SamplePtr<TestSampleType> sample,
714+
const tracing::ITracingRuntime::TracePointDataId) {
715+
received_sample = *sample;
716+
};
717+
718+
const auto num_callbacks_result = this->GetNewSamples(receiver, max_samples);
719+
720+
ASSERT_TRUE(num_callbacks_result.has_value());
721+
EXPECT_EQ(num_callbacks_result.value(), 1U);
722+
EXPECT_EQ(received_sample, kDummySampleValue);
723+
}
724+
696725
TEST_F(LoLaTypedProxyEventTestFixture, SampleConstness)
697726
{
698727
RecordProperty("Verifies", "SCR-6340729");
@@ -703,8 +732,8 @@ TEST_F(LoLaTypedProxyEventTestFixture, SampleConstness)
703732
this->GivenAProxyEvent(this->element_fq_id_, this->event_name_);
704733

705734
ProxyEventAttorney<TestSampleType> proxy_event_attorney{*test_proxy_event_};
706-
using SamplesMemberType = typename std::remove_reference<decltype(proxy_event_attorney.GetSamplesMember())>::type;
707-
static_assert(std::is_const<SamplesMemberType>::value, "Proxy should hold const slot data.");
735+
using MetaInfoMemberType = typename std::remove_reference<decltype(proxy_event_attorney.GetMetaInfoMember())>::type;
736+
static_assert(std::is_const<MetaInfoMemberType>::value, "Proxy should hold const event meta info.");
708737
}
709738

710739
} // namespace

score/mw/com/impl/bindings/lola/skeleton.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -518,8 +518,9 @@ auto Skeleton::RegisterGeneric(const ElementFqId element_fq_id,
518518
memory_manager_.RollbackSkeletonTracingTransactions(*event_data_control_asil_b);
519519
}
520520

521-
auto& event_data_storage = memory_manager_.RetrieveEventDataFromOpenedSharedMemory<std::uint8_t>(element_fq_id);
522-
return {static_cast<void*>(&event_data_storage), event_data_control_qm, event_data_control_asil_b};
521+
auto* const event_data_storage =
522+
memory_manager_.RetrieveGenericEventDataFromOpenedSharedMemory(element_fq_id, element_properties);
523+
return {event_data_storage, event_data_control_qm, event_data_control_asil_b};
523524
}
524525

525526
auto* const type_erased_event_data_storage = memory_manager_.CreateGenericEventDataInCreatedSharedMemory(

score/mw/com/impl/bindings/lola/skeleton_memory_manager.cpp

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "score/mw/com/impl/runtime.h"
2323
#include "score/mw/com/impl/skeleton_event_binding.h"
2424

25+
#include "score/language/safecpp/safe_math/safe_math.h"
2526
#include "score/memory/shared/managed_memory_resource.h"
2627
#include "score/memory/shared/new_delete_delegate_resource.h"
2728
#include "score/memory/shared/shared_memory_factory.h"
@@ -232,7 +233,35 @@ void* SkeletonMemoryManager::CreateGenericEventDataInCreatedSharedMemory(
232233
SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD_MESSAGE(inserted_meta_info.second,
233234
"Couldn't register/emplace event-meta-info in data-section.");
234235

235-
return data_storage;
236+
return event_data_raw_array;
237+
}
238+
239+
void* SkeletonMemoryManager::RetrieveGenericEventDataFromOpenedSharedMemory(
240+
const ElementFqId element_fq_id,
241+
const SkeletonEventProperties& element_properties) noexcept
242+
{
243+
SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD_MESSAGE(storage_ != nullptr, "Service data storage is not available.");
244+
245+
const auto event_meta_info_it = storage_->events_metainfo_.find(element_fq_id);
246+
SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD_MESSAGE(event_meta_info_it != storage_->events_metainfo_.cend(),
247+
"Could not find element fq id in meta info map");
248+
249+
const auto sample_size = event_meta_info_it->second.data_type_info_.size;
250+
const auto sample_alignment = event_meta_info_it->second.data_type_info_.alignment;
251+
const auto aligned_sample_size =
252+
memory::shared::CalculateAlignedSize(sample_size, static_cast<std::size_t>(sample_alignment));
253+
const auto total_event_slots_size = safe_math::Multiply(aligned_sample_size, element_properties.number_of_slots);
254+
if (!total_event_slots_size.has_value())
255+
{
256+
score::mw::log::LogFatal("lola") << "Could not calculate the event slots raw array size. Terminating.";
257+
std::terminate();
258+
}
259+
260+
void* const event_slots_raw_array =
261+
event_meta_info_it->second.event_slots_raw_array_.get(total_event_slots_size.value());
262+
SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD_MESSAGE(event_slots_raw_array != nullptr,
263+
"Could not get generic EventDataStorage raw array");
264+
return event_slots_raw_array;
236265
}
237266

238267
auto SkeletonMemoryManager::RetrieveEventControlsFromOpenedSharedMemory(const ElementFqId element_fq_id)

score/mw/com/impl/bindings/lola/skeleton_memory_manager.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,14 @@ class SkeletonMemoryManager final
127127
template <typename SampleType>
128128
auto RetrieveEventDataFromOpenedSharedMemory(const ElementFqId element_fq_id) -> EventDataStorage<SampleType>&;
129129

130+
/// \brief Retrieves the raw event sample storage pointer for a generic event from opened shared memory.
131+
///
132+
/// Generic events use EventMetaInfo as the stable type-erased contract. This keeps generic skeleton restarts
133+
/// independent from the concrete DynamicArray<T> representation used by typed skeletons and proxies.
134+
auto RetrieveGenericEventDataFromOpenedSharedMemory(const ElementFqId element_fq_id,
135+
const SkeletonEventProperties& element_properties) noexcept
136+
-> void*;
137+
130138
/// \brief Rolls back any existing operations in the TransactionLog corresponding to a SkeletonEvent
131139
///
132140
/// The TransactionLog would only exist if a SkeletonEvent in a crashed process had tracing enabled. If tracing was

score/mw/com/impl/bindings/lola/test/proxy_event_test_resources.cpp

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@
1313
#include "score/mw/com/impl/bindings/lola/test/proxy_event_test_resources.h"
1414

1515
#include "score/memory/shared/memory_resource_registry.h"
16+
#include "score/memory/shared/pointer_arithmetic_util.h"
1617

1718
#include <gmock/gmock.h>
1819
#include <gtest/gtest.h>
1920

21+
#include <cstring>
2022
#include <memory>
2123
#include <utility>
2224

@@ -129,6 +131,27 @@ void ProxyMockedMemoryFixture::InitialiseDummySkeletonEvent(const ElementFqId el
129131
provider_event_data_control_local_.emplace(event_control_->data_control);
130132
}
131133

134+
void LolaProxyEventResources::ReplaceDummySkeletonEventStorageWithGenericSkeletonLayout()
135+
{
136+
const auto aligned_sample_size = memory::shared::CalculateAlignedSize(sizeof(SampleType), alignof(SampleType));
137+
const auto total_data_size_bytes = aligned_sample_size * max_num_slots_;
138+
const auto num_max_align_elements =
139+
(total_data_size_bytes + sizeof(std::max_align_t) - 1U) / sizeof(std::max_align_t);
140+
141+
auto* const generic_event_data_slots = fake_data_->data_memory->construct<EventDataStorage<std::max_align_t>>(
142+
num_max_align_elements,
143+
memory::shared::PolymorphicOffsetPtrAllocator<std::max_align_t>(*fake_data_->data_memory));
144+
generic_event_data_storage_ = static_cast<std::uint8_t*>(static_cast<void*>(generic_event_data_slots->data()));
145+
146+
auto event_data_it = fake_data_->data_storage->events_.find(element_fq_id_);
147+
SCORE_LANGUAGE_FUTURECPP_ASSERT(event_data_it != fake_data_->data_storage->events_.end());
148+
event_data_it->second = memory::shared::OffsetPtr<void>{static_cast<void*>(generic_event_data_slots)};
149+
150+
auto event_meta_info_it = fake_data_->data_storage->events_metainfo_.find(element_fq_id_);
151+
SCORE_LANGUAGE_FUTURECPP_ASSERT(event_meta_info_it != fake_data_->data_storage->events_metainfo_.end());
152+
event_meta_info_it->second.event_slots_raw_array_ = memory::shared::OffsetPtr<void>{generic_event_data_storage_};
153+
}
154+
132155
LolaProxyEventResources::LolaProxyEventResources() : ProxyMockedMemoryFixture{}
133156
{
134157
InitialiseDummySkeletonEvent(element_fq_id_, SkeletonEventProperties{max_num_slots_, max_subscribers_, true});
@@ -187,7 +210,17 @@ SlotIndexType LolaProxyEventResources::PutData(const std::uint32_t value,
187210
auto slot_result = provider_event_data_control_local_->AllocateNextSlot();
188211
EXPECT_TRUE(slot_result.has_value());
189212
auto slot_index = slot_result.value();
190-
event_data_storage_->at(slot_index) = value;
213+
if (generic_event_data_storage_ != nullptr)
214+
{
215+
const auto aligned_sample_size = memory::shared::CalculateAlignedSize(sizeof(SampleType), alignof(SampleType));
216+
auto* const slot_address =
217+
memory::shared::AddOffsetToPointer(generic_event_data_storage_, aligned_sample_size * slot_index);
218+
std::memcpy(slot_address, &value, sizeof(value));
219+
}
220+
else
221+
{
222+
event_data_storage_->at(slot_index) = value;
223+
}
191224
provider_event_data_control_local_->EventReady(slot_index, timestamp);
192225
return slot_index;
193226
}

score/mw/com/impl/bindings/lola/test/proxy_event_test_resources.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#ifndef SCORE_MW_COM_IMPL_BINDINGS_LOLA_TEST_PROXY_EVENT_TEST_RESOURCES_H
1414
#define SCORE_MW_COM_IMPL_BINDINGS_LOLA_TEST_PROXY_EVENT_TEST_RESOURCES_H
1515

16+
#include "score/mw/com/impl/bindings/lola/event_data_storage.h"
1617
#include "score/mw/com/impl/bindings/lola/event_subscription_control.h"
1718
#include "score/mw/com/impl/bindings/lola/generic_proxy_event.h"
1819
#include "score/mw/com/impl/bindings/lola/i_runtime.h"
@@ -94,9 +95,9 @@ class ProxyEventAttorney
9495

9596
ProxyEventAttorney(ProxyEvent<T>& proxy_event) noexcept : proxy_event_{proxy_event} {}
9697

97-
auto& GetSamplesMember()
98+
auto& GetMetaInfoMember()
9899
{
99-
return proxy_event_.samples_;
100+
return proxy_event_.meta_info_;
100101
}
101102

102103
private:
@@ -207,6 +208,7 @@ class ProxyMockedMemoryFixture : public ::testing::Test
207208
std::optional<ProviderEventDataControlLocalView<>> provider_event_data_control_local_{};
208209
std::optional<ConsumerEventDataControlLocalView<>> consumer_event_data_control_local_{};
209210
EventDataStorage<SampleType>* event_data_storage_{nullptr};
211+
std::uint8_t* generic_event_data_storage_{nullptr};
210212
RollbackSynchronization rollback_synchronization_{};
211213

212214
std::shared_ptr<MessagePassingServiceMock> mock_service_{std::make_shared<MessagePassingServiceMock>()};
@@ -226,6 +228,8 @@ class LolaProxyEventResources : public ProxyMockedMemoryFixture
226228
void ExpectReregisterEventNotification(score::cpp::optional<pid_t> pid = {});
227229
void ExpectUnregisterEventNotification(score::cpp::optional<pid_t> pid = {});
228230

231+
void ReplaceDummySkeletonEventStorageWithGenericSkeletonLayout();
232+
229233
SlotIndexType PutData(const std::uint32_t value = 42, const EventSlotStatus::EventTimeStamp timestamp = 1);
230234

231235
const std::size_t max_num_slots_{5U};

0 commit comments

Comments
 (0)