/src/LPM/external.protobuf/include/google/protobuf/arena_cleanup.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Protocol Buffers - Google's data interchange format |
2 | | // Copyright 2008 Google Inc. All rights reserved. |
3 | | // https://developers.google.com/protocol-buffers/ |
4 | | // |
5 | | // Redistribution and use in source and binary forms, with or without |
6 | | // modification, are permitted provided that the following conditions are |
7 | | // met: |
8 | | // |
9 | | // * Redistributions of source code must retain the above copyright |
10 | | // notice, this list of conditions and the following disclaimer. |
11 | | // * Redistributions in binary form must reproduce the above |
12 | | // copyright notice, this list of conditions and the following disclaimer |
13 | | // in the documentation and/or other materials provided with the |
14 | | // distribution. |
15 | | // * Neither the name of Google Inc. nor the names of its |
16 | | // contributors may be used to endorse or promote products derived from |
17 | | // this software without specific prior written permission. |
18 | | // |
19 | | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
20 | | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
21 | | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
22 | | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
23 | | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
24 | | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
25 | | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
26 | | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
27 | | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
28 | | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
29 | | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 | | |
31 | | #ifndef GOOGLE_PROTOBUF_ARENA_CLEANUP_H__ |
32 | | #define GOOGLE_PROTOBUF_ARENA_CLEANUP_H__ |
33 | | |
34 | | #include <cstddef> |
35 | | #include <cstdint> |
36 | | #include <string> |
37 | | |
38 | | #include "absl/base/attributes.h" |
39 | | #include "absl/log/absl_check.h" |
40 | | #include "absl/log/absl_log.h" |
41 | | #include "absl/strings/cord.h" |
42 | | |
43 | | |
44 | | // Must be included last. |
45 | | #include "google/protobuf/port_def.inc" |
46 | | |
47 | | namespace google { |
48 | | namespace protobuf { |
49 | | namespace internal { |
50 | | namespace cleanup { |
51 | | |
52 | | // Helper function invoking the destructor of `object` |
53 | | template <typename T> |
54 | 0 | void arena_destruct_object(void* object) { |
55 | 0 | reinterpret_cast<T*>(object)->~T(); |
56 | 0 | } Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(void*) Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<absl::lts_20230125::Cord>(void*) Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<google::protobuf::internal::InternalMetadata::Container<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >(void*) Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<google::protobuf::internal::ImplicitWeakMessage>(void*) Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<google::protobuf::internal::InternalMetadata::Container<google::protobuf::UnknownFieldSet> >(void*) Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<ruby_fuzzer::VarRef>(void*) Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<ruby_fuzzer::ArrType>(void*) Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<ruby_fuzzer::KVPair>(void*) Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<ruby_fuzzer::HashType>(void*) Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<ruby_fuzzer::StringExtNoArg>(void*) Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<ruby_fuzzer::MathConst>(void*) Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<ruby_fuzzer::Const>(void*) Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<ruby_fuzzer::BinaryOp>(void*) Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<ruby_fuzzer::Rvalue>(void*) Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<ruby_fuzzer::AssignmentStatement>(void*) Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<ruby_fuzzer::IfElse>(void*) Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<ruby_fuzzer::Ternary>(void*) Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<ruby_fuzzer::ObjectSpace>(void*) Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<ruby_fuzzer::Time>(void*) Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<ruby_fuzzer::Array>(void*) Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<ruby_fuzzer::MathType>(void*) Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<ruby_fuzzer::MathOps>(void*) Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<ruby_fuzzer::BuiltinFuncs>(void*) Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<ruby_fuzzer::Statement>(void*) Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<ruby_fuzzer::StatementSeq>(void*) Unexecuted instantiation: void google::protobuf::internal::cleanup::arena_destruct_object<ruby_fuzzer::Function>(void*) |
57 | | |
58 | | // Tag defines the type of cleanup / cleanup object. This tag is stored in the |
59 | | // lowest 2 bits of the `elem` value identifying the type of node. All node |
60 | | // types must start with a `uintptr_t` that stores `Tag` in its low two bits. |
61 | | enum class Tag : uintptr_t { |
62 | | kDynamic = 0, // DynamicNode |
63 | | kString = 1, // TaggedNode (std::string) |
64 | | kCord = 2, // TaggedNode (absl::Cord) |
65 | | }; |
66 | | |
67 | | // DynamicNode contains the object (`elem`) that needs to be |
68 | | // destroyed, and the function to destroy it (`destructor`) |
69 | | // elem must be aligned at minimum on a 4 byte boundary. |
70 | | struct DynamicNode { |
71 | | uintptr_t elem; |
72 | | void (*destructor)(void*); |
73 | | }; |
74 | | |
75 | | // TaggedNode contains a `std::string` or `absl::Cord` object (`elem`) that |
76 | | // needs to be destroyed. The lowest 2 bits of `elem` contain the non-zero |
77 | | // `kString` or `kCord` tag. |
78 | | struct TaggedNode { |
79 | | uintptr_t elem; |
80 | | }; |
81 | | |
82 | | // EnableSpecializedTags() return true if the alignment of tagged objects |
83 | | // such as std::string allow us to poke tags in the 2 LSB bits. |
84 | 0 | inline constexpr bool EnableSpecializedTags() { |
85 | 0 | // For now we require 2 bits |
86 | 0 | return alignof(std::string) >= 8 && alignof(absl::Cord) >= 8; |
87 | 0 | } |
88 | | |
89 | | // Adds a cleanup entry identified by `tag` at memory location `pos`. |
90 | | inline ABSL_ATTRIBUTE_ALWAYS_INLINE void CreateNode(Tag tag, void* pos, |
91 | | const void* elem_raw, |
92 | 0 | void (*destructor)(void*)) { |
93 | 0 | auto elem = reinterpret_cast<uintptr_t>(elem_raw); |
94 | 0 | if (EnableSpecializedTags()) { |
95 | 0 | ABSL_DCHECK_EQ(elem & 3, 0ULL); // Must be aligned |
96 | 0 | switch (tag) { |
97 | 0 | case Tag::kString: { |
98 | 0 | TaggedNode n = {elem | static_cast<uintptr_t>(Tag::kString)}; |
99 | 0 | memcpy(pos, &n, sizeof(n)); |
100 | 0 | return; |
101 | 0 | } |
102 | 0 | case Tag::kCord: { |
103 | 0 | TaggedNode n = {elem | static_cast<uintptr_t>(Tag::kCord)}; |
104 | 0 | memcpy(pos, &n, sizeof(n)); |
105 | 0 | return; |
106 | 0 | } |
107 | 0 | default: |
108 | 0 | break; |
109 | 0 | } |
110 | 0 | } |
111 | 0 | DynamicNode n = {elem, destructor}; |
112 | 0 | memcpy(pos, &n, sizeof(n)); |
113 | 0 | } |
114 | | |
115 | | // Optimization: performs a prefetch on `elem_address`. |
116 | | // Returns the size of the cleanup (meta) data at this address, allowing the |
117 | | // caller to advance cleanup iterators without needing to examine or know |
118 | | // anything about the underlying cleanup node or cleanup meta data / tags. |
119 | | inline ABSL_ATTRIBUTE_ALWAYS_INLINE size_t |
120 | 0 | PrefetchNode(const void* elem_address) { |
121 | 0 | if (EnableSpecializedTags()) { |
122 | 0 | uintptr_t elem; |
123 | 0 | memcpy(&elem, elem_address, sizeof(elem)); |
124 | 0 | if (static_cast<Tag>(elem & 3) != Tag::kDynamic) { |
125 | 0 | return sizeof(TaggedNode); |
126 | 0 | } |
127 | 0 | } |
128 | 0 | return sizeof(DynamicNode); |
129 | 0 | } |
130 | | |
131 | | // Destroys the object referenced by the cleanup node at memory location `pos`. |
132 | | // Returns the size of the cleanup (meta) data at this address, allowing the |
133 | | // caller to advance cleanup iterators without needing to examine or know |
134 | | // anything about the underlying cleanup node or cleanup meta data / tags. |
135 | 0 | inline ABSL_ATTRIBUTE_ALWAYS_INLINE size_t DestroyNode(const void* pos) { |
136 | 0 | uintptr_t elem; |
137 | 0 | memcpy(&elem, pos, sizeof(elem)); |
138 | 0 | if (EnableSpecializedTags()) { |
139 | 0 | switch (static_cast<Tag>(elem & 3)) { |
140 | 0 | case Tag::kString: { |
141 | 0 | // Some compilers don't like fully qualified explicit dtor calls, |
142 | 0 | // so use an alias to avoid having to type `::`. |
143 | 0 | using T = std::string; |
144 | 0 | reinterpret_cast<T*>(elem - static_cast<uintptr_t>(Tag::kString))->~T(); |
145 | 0 | return sizeof(TaggedNode); |
146 | 0 | } |
147 | 0 | case Tag::kCord: { |
148 | 0 | using T = absl::Cord; |
149 | 0 | reinterpret_cast<T*>(elem - static_cast<uintptr_t>(Tag::kCord))->~T(); |
150 | 0 | return sizeof(TaggedNode); |
151 | 0 | } |
152 | 0 | default: |
153 | 0 | break; |
154 | 0 | } |
155 | 0 | } |
156 | 0 | static_cast<const DynamicNode*>(pos)->destructor( |
157 | 0 | reinterpret_cast<void*>(elem - static_cast<uintptr_t>(Tag::kDynamic))); |
158 | 0 | return sizeof(DynamicNode); |
159 | 0 | } |
160 | | |
161 | | // Returns the `tag` identifying the type of object for `destructor` or |
162 | | // kDynamic if `destructor` does not identify a well know object type. |
163 | 0 | inline ABSL_ATTRIBUTE_ALWAYS_INLINE Tag Type(void (*destructor)(void*)) { |
164 | 0 | if (EnableSpecializedTags()) { |
165 | 0 | if (destructor == &arena_destruct_object<std::string>) { |
166 | 0 | return Tag::kString; |
167 | 0 | } |
168 | 0 | if (destructor == &arena_destruct_object<absl::Cord>) { |
169 | 0 | return Tag::kCord; |
170 | 0 | } |
171 | 0 | } |
172 | 0 | return Tag::kDynamic; |
173 | 0 | } |
174 | | |
175 | | // Returns the `tag` identifying the type of object stored at memory location |
176 | | // `elem`, which represents the first uintptr_t value in the node. |
177 | 0 | inline ABSL_ATTRIBUTE_ALWAYS_INLINE Tag Type(void* raw) { |
178 | 0 | if (!EnableSpecializedTags()) return Tag::kDynamic; |
179 | 0 |
|
180 | 0 | uintptr_t elem; |
181 | 0 | memcpy(&elem, raw, sizeof(elem)); |
182 | 0 | switch (static_cast<Tag>(elem & 0x7ULL)) { |
183 | 0 | case Tag::kDynamic: |
184 | 0 | return Tag::kDynamic; |
185 | 0 | case Tag::kString: |
186 | 0 | return Tag::kString; |
187 | 0 | case Tag::kCord: |
188 | 0 | return Tag::kCord; |
189 | 0 | default: |
190 | 0 | ABSL_LOG(FATAL) << "Corrupted cleanup tag: " << (elem & 0x7ULL); |
191 | 0 | return Tag::kDynamic; |
192 | 0 | } |
193 | 0 | } |
194 | | |
195 | | // Returns the required size in bytes off the node type identified by `tag`. |
196 | 0 | inline ABSL_ATTRIBUTE_ALWAYS_INLINE size_t Size(Tag tag) { |
197 | 0 | if (!EnableSpecializedTags()) return sizeof(DynamicNode); |
198 | 0 |
|
199 | 0 | switch (tag) { |
200 | 0 | case Tag::kDynamic: |
201 | 0 | return sizeof(DynamicNode); |
202 | 0 | case Tag::kString: |
203 | 0 | return sizeof(TaggedNode); |
204 | 0 | case Tag::kCord: |
205 | 0 | return sizeof(TaggedNode); |
206 | 0 | default: |
207 | 0 | ABSL_LOG(FATAL) << "Corrupted cleanup tag: " << static_cast<int>(tag); |
208 | 0 | return sizeof(DynamicNode); |
209 | 0 | } |
210 | 0 | } |
211 | | |
212 | | // Returns the required size in bytes off the node type for `destructor`. |
213 | 0 | inline ABSL_ATTRIBUTE_ALWAYS_INLINE size_t Size(void (*destructor)(void*)) { |
214 | 0 | return destructor == nullptr ? 0 : Size(Type(destructor)); |
215 | 0 | } |
216 | | |
217 | | } // namespace cleanup |
218 | | } // namespace internal |
219 | | } // namespace protobuf |
220 | | } // namespace google |
221 | | |
222 | | #include "google/protobuf/port_undef.inc" |
223 | | |
224 | | #endif // GOOGLE_PROTOBUF_ARENA_CLEANUP_H__ |