Repository navigation
Expand file tree
/
Copy pathpointer_arithmetic_util.cpp
More file actions
176 lines (152 loc) · 8.53 KB
/
Copy pathpointer_arithmetic_util.cpp
File metadata and controls
176 lines (152 loc) · 8.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/********************************************************************************
* Copyright (c) 2025 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/
#include "score/memory/shared/pointer_arithmetic_util.h"
#include "score/memory/data_type_size_info.h"
#include "score/mw/log/log_types.h"
#include "score/mw/log/logging.h"
#include "score/language/safecpp/safe_math/safe_math.h"
#include <score/assert.hpp>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <limits>
#include <vector>
namespace score::memory::shared
{
std::uintptr_t AddOffsetToPointerAsInteger(const std::uintptr_t pointer_as_integer, const std::size_t offset)
{
static_assert(std::numeric_limits<std::size_t>::max() <= std::numeric_limits<std::uintptr_t>::max(),
"If max value of size_t is larger than uintptr_t, then subtracting offset from the max value of "
"uintptr_t could underflow.");
SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD_MESSAGE(
pointer_as_integer <= (std::numeric_limits<std::uintptr_t>::max() - offset),
"Could not add offset to pointer. Result would lead to overflow of std::uintptr_t");
return pointer_as_integer + offset;
}
std::uintptr_t AddSignedOffsetToPointerAsInteger(const std::uintptr_t ptr_as_integer, const std::ptrdiff_t offset)
{
static_assert(sizeof(decltype(offset)) <= sizeof(std::size_t),
"Casting offset to size_t will only avoid data loss if the max possible value of offet fits "
"within a size_t.");
if (offset < 0)
{
const auto abs_offset = safe_math::Abs(offset);
return SubtractOffsetFromPointerAsInteger(ptr_as_integer, abs_offset);
}
return AddOffsetToPointerAsInteger(ptr_as_integer, static_cast<std::size_t>(offset));
}
std::uintptr_t SubtractOffsetFromPointerAsInteger(const std::uintptr_t pointer_as_integer, const std::size_t offset)
{
SCORE_LANGUAGE_FUTURECPP_ASSERT_PRD_MESSAGE(
pointer_as_integer >= offset,
"Could not subtract offset from pointer. Result would lead to underflow of std::size_t");
return pointer_as_integer - offset;
}
std::size_t CalculateAlignedSizeOfSequence(const std::vector<DataTypeSizeInfo>& data_type_infos)
{
std::size_t total_size{0U};
for (std::size_t i = 0U; i < data_type_infos.size(); ++i)
{
const auto& current_element = data_type_infos[i];
SCORE_LANGUAGE_FUTURECPP_PRECONDITION_PRD(current_element.Alignment() != 0U);
SCORE_LANGUAGE_FUTURECPP_PRECONDITION_PRD(total_size <= SIZE_MAX - current_element.Size());
total_size += current_element.Size();
// If there is still a remaining next element, we need to calculate the padding between the current element and
// the next element.
const auto is_last_element = i == (data_type_infos.size() - 1U);
if (!is_last_element)
{
const auto next_element = data_type_infos[i + 1U];
SCORE_LANGUAGE_FUTURECPP_PRECONDITION_PRD(next_element.Alignment() != 0U);
// The start location (represented as a distance from the first allocation of the sequence) of the next
// element can be calculated by calculating the aligned size of the currently allocated memory (i.e. up to
// and including the current element) using the alignment of the next element.
total_size = CalculateAlignedSize(total_size, next_element.Alignment());
}
}
return total_size;
}
std::uintptr_t CastPointerToInteger(const void* const pointer) noexcept
{
// Suppress "AUTOSAR C++14 A5-2-4" rule finding: reinterpret_cast shall not be used.
// Rationale : According to https://timsong-cpp.github.io/cppwp/n4659/expr.reinterpret.cast#4, casting a pointer to
// an integral type large enough to hold it is implementation-defined. We rely on sufficient testing to ensure that
// the implementation defined behaviour performs as expected (i.e. that adding an offset to the integer pointer
// value results in the expected final address).
// Suppress "AUTOSAR C++14 M5-2-9" rule finding: "A cast shall not convert a pointer type to an integral type.".
// Rationale: Same as rationale for autosar_cpp14_a5_2_4_violation.
// NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast): see rationale above.
// coverity[autosar_cpp14_a5_2_4_violation]
// coverity[autosar_cpp14_m5_2_9_violation]
return reinterpret_cast<std::uintptr_t>(pointer);
// NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
}
score::mw::log::LogHex64 PointerToLogValue(const void* const pointer)
{
// Suppress "AUTOSAR C++14 A5-2-4" rule finding: "reinterpret_cast shall not be used.".
// Rationale : Accepted for conversion to log output
// Suppress "AUTOSAR C++14 M5-2-9" rule finding: "A cast shall not convert a pointer type to an integral type.".
// Rationale : As per C++11 standard (ISO/IEC 14882:2011) std::uintptr_t is an unsigned integer type capable of
// holding a pointer to void.
// NOLINTBEGIN(cppcoreguidelines-pro-type-reinterpret-cast): see rationale above.
// coverity[autosar_cpp14_a5_2_4_violation]
// coverity[autosar_cpp14_m5_2_9_violation]
return score::mw::log::LogHex64{reinterpret_cast<std::uintptr_t>(pointer)};
// NOLINTEND(cppcoreguidelines-pro-type-reinterpret-cast)
}
std::ptrdiff_t SubtractPointersBytes(const void* const first, const void* const second)
{
static_assert(sizeof(std::ptrdiff_t) == sizeof(std::uintptr_t));
const auto first_address_as_integer = CastPointerToInteger(first);
const auto second_address_as_integer = CastPointerToInteger(second);
constexpr auto ptr_diff_max = std::numeric_limits<std::ptrdiff_t>::max();
if (first_address_as_integer > second_address_as_integer)
{
const auto result_as_integer =
SubtractOffsetFromPointerAsInteger(first_address_as_integer, second_address_as_integer);
if (result_as_integer > static_cast<std::uintptr_t>(ptr_diff_max))
{
score::mw::log::LogFatal("shm")
<< "Could not subtract " << second_address_as_integer << "from" << first_address_as_integer
<< ". Result does not fit into std::ptrdiff_t. Terminating.";
// Reachable in principle, but must not be reached in production: Two addresses further apart than
// std::ptrdiff_t max are possible in principle. Shared memory regions are far smaller, so such a pair of
// addresses must not occur in production.
SCORE_LANGUAGE_FUTURECPP_UNREACHABLE();
}
return static_cast<std::ptrdiff_t>(result_as_integer);
}
// Calculate the absolute value of the subtraction by reversing the order (since we know that the second value is >=
// the first).
const auto absolute_value_result_as_integer =
SubtractOffsetFromPointerAsInteger(second_address_as_integer, first_address_as_integer);
// Since we need to cast positive_result_as_integer to a std::ptrdiff_t, we have to handle the special case in which
// the actual result is equal to ptr_diff_min. In such a case, the absolute value of the result will be ptr_diff_max
// + 1U which cannot fit inside a std::ptrdiff_t. So we directly return ptr_diff_min in such a case.
if (absolute_value_result_as_integer == (static_cast<std::uintptr_t>(ptr_diff_max) + 1U))
{
return std::numeric_limits<std::ptrdiff_t>::min();
}
if (absolute_value_result_as_integer > static_cast<std::uintptr_t>(ptr_diff_max))
{
score::mw::log::LogFatal("shm") << "Could not subtract " << second_address_as_integer << "from"
<< first_address_as_integer
<< ". Result does not fit into std::ptrdiff_t. Terminating.";
// Reachable in principle, but must not be reached in production: Two addresses further apart than
// std::ptrdiff_t max are possible in principle. Shared memory regions are far smaller, so such a pair of
// addresses must not occur in production.
SCORE_LANGUAGE_FUTURECPP_UNREACHABLE();
}
return -1 * static_cast<std::ptrdiff_t>(absolute_value_result_as_integer);
}
} // namespace score::memory::shared