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_METADATA_LITE_H__
32#define GOOGLE_PROTOBUF_METADATA_LITE_H__
33
34#include <string>
35#include <google/protobuf/stubs/common.h>
36#include <google/protobuf/arena.h>
37#include <google/protobuf/port.h>
38
39// Must be included last.
40#include <google/protobuf/port_def.inc>
41
42#ifdef SWIG
43#error "You cannot SWIG proto headers"
44#endif
45
46namespace google {
47namespace protobuf {
48namespace internal {
49
50// This is the representation for messages that support arena allocation. It
51// uses a tagged pointer to either store the owning Arena pointer, if there are
52// no unknown fields, or a pointer to a block of memory with both the owning
53// Arena pointer and the UnknownFieldSet, if there are unknown fields. Besides,
54// it also uses the tag to distinguish whether the owning Arena pointer is also
55// used by sub-structure allocation. This optimization allows for
56// "zero-overhead" storage of the Arena pointer, relative to the above baseline
57// implementation.
58//
59// The tagged pointer uses the least two significant bits to disambiguate cases.
60// It uses bit 0 == 0 to indicate an arena pointer and bit 0 == 1 to indicate a
61// UFS+Arena-container pointer. Besides it uses bit 1 == 0 to indicate arena
62// allocation and bit 1 == 1 to indicate heap allocation.
63class PROTOBUF_EXPORT InternalMetadata {
64 public:
65 constexpr InternalMetadata() : ptr_(0) {}
66 explicit InternalMetadata(Arena* arena, bool is_message_owned = false) {
67 SetArena(arena, is_message_owned);
68 }
69
70 void SetArena(Arena* arena, bool is_message_owned) {
71 ptr_ = is_message_owned
72 ? reinterpret_cast<intptr_t>(arena) | kMessageOwnedArenaTagMask
73 : reinterpret_cast<intptr_t>(arena);
74 GOOGLE_DCHECK(!is_message_owned || arena != nullptr);
75 }
76
77 // To keep the ABI identical between debug and non-debug builds,
78 // the destructor is always defined here even though it may delegate
79 // to a non-inline private method.
80 // (see https://github.com/protocolbuffers/protobuf/issues/9947)
81 ~InternalMetadata() {
82#if defined(NDEBUG) || defined(_MSC_VER)
83 if (HasMessageOwnedArenaTag()) {
84 delete reinterpret_cast<Arena*>(ptr_ - kMessageOwnedArenaTagMask);
85 }
86#else
87 CheckedDestruct();
88#endif
89 }
90
91 template <typename T>
92 void Delete() {
93 // Note that Delete<> should be called not more than once.
94 if (have_unknown_fields()) {
95 DeleteOutOfLineHelper<T>();
96 }
97 }
98
99 // DeleteReturnArena will delete the unknown fields only if they weren't
100 // allocated on an arena. Then it updates the flags so that if you call
101 // have_unknown_fields(), it will return false. Finally, it returns the
102 // current value of arena(). It is designed to be used as part of a
103 // Message class's destructor call, so that when control eventually gets
104 // to ~InternalMetadata(), we don't need to check for have_unknown_fields()
105 // again.
106 template <typename T>
107 Arena* DeleteReturnArena() {
108 if (have_unknown_fields()) {
109 return DeleteOutOfLineHelper<T>();
110 } else {
111 return PtrValue<Arena>();
112 }
113 }
114
115 PROTOBUF_NDEBUG_INLINE Arena* owning_arena() const {
116 return HasMessageOwnedArenaTag() ? nullptr : arena();
117 }
118
119 PROTOBUF_NDEBUG_INLINE Arena* user_arena() const {
120 Arena* a = arena();
121 return a && !a->IsMessageOwned() ? a : nullptr;
122 }
123
124 PROTOBUF_NDEBUG_INLINE Arena* arena() const {
125 if (PROTOBUF_PREDICT_FALSE(have_unknown_fields())) {
126 return PtrValue<ContainerBase>()->arena;
127 } else {
128 return PtrValue<Arena>();
129 }
130 }
131
132 PROTOBUF_NDEBUG_INLINE bool have_unknown_fields() const {
133 return HasUnknownFieldsTag();
134 }
135
136 PROTOBUF_NDEBUG_INLINE void* raw_arena_ptr() const {
137 return reinterpret_cast<void*>(ptr_);
138 }
139
140 template <typename T>
141 PROTOBUF_NDEBUG_INLINE const T& unknown_fields(
142 const T& (*default_instance)()) const {
143 if (PROTOBUF_PREDICT_FALSE(have_unknown_fields())) {
144 return PtrValue<Container<T>>()->unknown_fields;
145 } else {
146 return default_instance();
147 }
148 }
149
150 template <typename T>
151 PROTOBUF_NDEBUG_INLINE T* mutable_unknown_fields() {
152 if (PROTOBUF_PREDICT_TRUE(have_unknown_fields())) {
153 return &PtrValue<Container<T>>()->unknown_fields;
154 } else {
155 return mutable_unknown_fields_slow<T>();
156 }
157 }
158
159 template <typename T>
160 PROTOBUF_NDEBUG_INLINE void Swap(InternalMetadata* other) {
161 // Semantics here are that we swap only the unknown fields, not the arena
162 // pointer. We cannot simply swap ptr_ with other->ptr_ because we need to
163 // maintain our own arena ptr. Also, our ptr_ and other's ptr_ may be in
164 // different states (direct arena pointer vs. container with UFS) so we
165 // cannot simply swap ptr_ and then restore the arena pointers. We reuse
166 // UFS's swap implementation instead.
167 if (have_unknown_fields() || other->have_unknown_fields()) {
168 DoSwap<T>(other->mutable_unknown_fields<T>());
169 }
170 }
171
172 PROTOBUF_NDEBUG_INLINE void InternalSwap(InternalMetadata* other) {
173 std::swap(a&: ptr_, b&: other->ptr_);
174 }
175
176 template <typename T>
177 PROTOBUF_NDEBUG_INLINE void MergeFrom(const InternalMetadata& other) {
178 if (other.have_unknown_fields()) {
179 DoMergeFrom<T>(other.unknown_fields<T>(nullptr));
180 }
181 }
182
183 template <typename T>
184 PROTOBUF_NDEBUG_INLINE void Clear() {
185 if (have_unknown_fields()) {
186 DoClear<T>();
187 }
188 }
189
190 private:
191 intptr_t ptr_;
192
193 // Tagged pointer implementation.
194 static constexpr intptr_t kUnknownFieldsTagMask = 1;
195 static constexpr intptr_t kMessageOwnedArenaTagMask = 2;
196 static constexpr intptr_t kPtrTagMask =
197 kUnknownFieldsTagMask | kMessageOwnedArenaTagMask;
198 static constexpr intptr_t kPtrValueMask = ~kPtrTagMask;
199
200 // Accessors for pointer tag and pointer value.
201 PROTOBUF_ALWAYS_INLINE bool HasUnknownFieldsTag() const {
202 return ptr_ & kUnknownFieldsTagMask;
203 }
204 PROTOBUF_ALWAYS_INLINE bool HasMessageOwnedArenaTag() const {
205 return ptr_ & kMessageOwnedArenaTagMask;
206 }
207
208 template <typename U>
209 U* PtrValue() const {
210 return reinterpret_cast<U*>(ptr_ & kPtrValueMask);
211 }
212
213 // If ptr_'s tag is kTagContainer, it points to an instance of this struct.
214 struct ContainerBase {
215 Arena* arena;
216 };
217
218 template <typename T>
219 struct Container : public ContainerBase {
220 T unknown_fields;
221 };
222
223 template <typename T>
224 PROTOBUF_NOINLINE Arena* DeleteOutOfLineHelper() {
225 if (auto* a = arena()) {
226 // Subtle: we want to preserve the message-owned arena flag, while at the
227 // same time replacing the pointer to Container<T> with a pointer to the
228 // arena.
229 intptr_t message_owned_arena_tag = ptr_ & kMessageOwnedArenaTagMask;
230 ptr_ = reinterpret_cast<intptr_t>(a) | message_owned_arena_tag;
231 return a;
232 } else {
233 delete PtrValue<Container<T>>();
234 ptr_ = 0;
235 return nullptr;
236 }
237 }
238
239 template <typename T>
240 PROTOBUF_NOINLINE T* mutable_unknown_fields_slow() {
241 Arena* my_arena = arena();
242 Container<T>* container = Arena::Create<Container<T>>(my_arena);
243 intptr_t message_owned_arena_tag = ptr_ & kMessageOwnedArenaTagMask;
244 // Two-step assignment works around a bug in clang's static analyzer:
245 // https://bugs.llvm.org/show_bug.cgi?id=34198.
246 ptr_ = reinterpret_cast<intptr_t>(container);
247 ptr_ |= kUnknownFieldsTagMask | message_owned_arena_tag;
248 container->arena = my_arena;
249 return &(container->unknown_fields);
250 }
251
252 // Templated functions.
253
254 template <typename T>
255 PROTOBUF_NOINLINE void DoClear() {
256 mutable_unknown_fields<T>()->Clear();
257 }
258
259 template <typename T>
260 PROTOBUF_NOINLINE void DoMergeFrom(const T& other) {
261 mutable_unknown_fields<T>()->MergeFrom(other);
262 }
263
264 template <typename T>
265 PROTOBUF_NOINLINE void DoSwap(T* other) {
266 mutable_unknown_fields<T>()->Swap(other);
267 }
268
269 // Private helper with debug checks for ~InternalMetadata()
270 void CheckedDestruct();
271};
272
273// String Template specializations.
274
275template <>
276PROTOBUF_EXPORT void InternalMetadata::DoClear<std::string>();
277template <>
278PROTOBUF_EXPORT void InternalMetadata::DoMergeFrom<std::string>(
279 const std::string& other);
280template <>
281PROTOBUF_EXPORT void InternalMetadata::DoSwap<std::string>(std::string* other);
282
283// This helper RAII class is needed to efficiently parse unknown fields. We
284// should only call mutable_unknown_fields if there are actual unknown fields.
285// The obvious thing to just use a stack string and swap it at the end of
286// the parse won't work, because the destructor of StringOutputStream needs to
287// be called before we can modify the string (it check-fails). Using
288// LiteUnknownFieldSetter setter(&_internal_metadata_);
289// StringOutputStream stream(setter.buffer());
290// guarantees that the string is only swapped after stream is destroyed.
291class PROTOBUF_EXPORT LiteUnknownFieldSetter {
292 public:
293 explicit LiteUnknownFieldSetter(InternalMetadata* metadata)
294 : metadata_(metadata) {
295 if (metadata->have_unknown_fields()) {
296 buffer_.swap(s&: *metadata->mutable_unknown_fields<std::string>());
297 }
298 }
299 ~LiteUnknownFieldSetter() {
300 if (!buffer_.empty())
301 metadata_->mutable_unknown_fields<std::string>()->swap(s&: buffer_);
302 }
303 std::string* buffer() { return &buffer_; }
304
305 private:
306 InternalMetadata* metadata_;
307 std::string buffer_;
308};
309
310} // namespace internal
311} // namespace protobuf
312} // namespace google
313
314#include <google/protobuf/port_undef.inc>
315
316#endif // GOOGLE_PROTOBUF_METADATA_LITE_H__
317