Coverage Report

Created: 2026-07-25 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/protobuf_install/include/google/protobuf/metadata_lite.h
Line
Count
Source
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
46
namespace google {
47
namespace protobuf {
48
namespace 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.
63
class PROTOBUF_EXPORT InternalMetadata {
64
 public:
65
5.57k
  constexpr InternalMetadata() : ptr_(0) {}
66
1.12M
  explicit InternalMetadata(Arena* arena, bool is_message_owned = false) {
67
1.12M
    SetArena(arena, is_message_owned);
68
1.12M
  }
69
70
1.12M
  void SetArena(Arena* arena, bool is_message_owned) {
71
1.12M
    ptr_ = is_message_owned
72
1.12M
               ? reinterpret_cast<intptr_t>(arena) | kMessageOwnedArenaTagMask
73
1.12M
               : reinterpret_cast<intptr_t>(arena);
74
1.12M
    GOOGLE_DCHECK(!is_message_owned || arena != nullptr);
75
1.12M
  }
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
1.13M
  ~InternalMetadata() {
82
#if defined(NDEBUG) || defined(_MSC_VER)
83
    if (HasMessageOwnedArenaTag()) {
84
      delete reinterpret_cast<Arena*>(ptr_ - kMessageOwnedArenaTagMask);
85
    }
86
#else
87
1.13M
    CheckedDestruct();
88
1.13M
#endif
89
1.13M
  }
90
91
  template <typename T>
92
215k
  void Delete() {
93
    // Note that Delete<> should be called not more than once.
94
215k
    if (have_unknown_fields()) {
95
56
      DeleteOutOfLineHelper<T>();
96
56
    }
97
215k
  }
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
917k
  Arena* DeleteReturnArena() {
108
917k
    if (have_unknown_fields()) {
109
175k
      return DeleteOutOfLineHelper<T>();
110
741k
    } else {
111
741k
      return PtrValue<Arena>();
112
741k
    }
113
917k
  }
114
115
489k
  PROTOBUF_NDEBUG_INLINE Arena* owning_arena() const {
116
489k
    return HasMessageOwnedArenaTag() ? nullptr : arena();
117
489k
  }
118
119
0
  PROTOBUF_NDEBUG_INLINE Arena* user_arena() const {
120
0
    Arena* a = arena();
121
0
    return a && !a->IsMessageOwned() ? a : nullptr;
122
0
  }
123
124
3.17M
  PROTOBUF_NDEBUG_INLINE Arena* arena() const {
125
3.17M
    if (PROTOBUF_PREDICT_FALSE(have_unknown_fields())) {
126
420k
      return PtrValue<ContainerBase>()->arena;
127
2.75M
    } else {
128
2.75M
      return PtrValue<Arena>();
129
2.75M
    }
130
3.17M
  }
131
132
11.5M
  PROTOBUF_NDEBUG_INLINE bool have_unknown_fields() const {
133
11.5M
    return HasUnknownFieldsTag();
134
11.5M
  }
135
136
0
  PROTOBUF_NDEBUG_INLINE void* raw_arena_ptr() const {
137
0
    return reinterpret_cast<void*>(ptr_);
138
0
  }
139
140
  template <typename T>
141
  PROTOBUF_NDEBUG_INLINE const T& unknown_fields(
142
378k
      const T& (*default_instance)()) const {
143
378k
    if (PROTOBUF_PREDICT_FALSE(have_unknown_fields())) {
144
92.4k
      return PtrValue<Container<T>>()->unknown_fields;
145
285k
    } else {
146
285k
      return default_instance();
147
285k
    }
148
378k
  }
149
150
  template <typename T>
151
6.70M
  PROTOBUF_NDEBUG_INLINE T* mutable_unknown_fields() {
152
6.70M
    if (PROTOBUF_PREDICT_TRUE(have_unknown_fields())) {
153
6.53M
      return &PtrValue<Container<T>>()->unknown_fields;
154
6.53M
    } else {
155
175k
      return mutable_unknown_fields_slow<T>();
156
175k
    }
157
6.70M
  }
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
216k
  PROTOBUF_NDEBUG_INLINE void InternalSwap(InternalMetadata* other) {
173
216k
    std::swap(ptr_, other->ptr_);
174
216k
  }
175
176
  template <typename T>
177
40.8k
  PROTOBUF_NDEBUG_INLINE void MergeFrom(const InternalMetadata& other) {
178
40.8k
    if (other.have_unknown_fields()) {
179
5.14k
      DoMergeFrom<T>(other.unknown_fields<T>(nullptr));
180
5.14k
    }
181
40.8k
  }
182
183
  template <typename T>
184
76.4k
  PROTOBUF_NDEBUG_INLINE void Clear() {
185
76.4k
    if (have_unknown_fields()) {
186
0
      DoClear<T>();
187
0
    }
188
76.4k
  }
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
11.5M
  PROTOBUF_ALWAYS_INLINE bool HasUnknownFieldsTag() const {
202
11.5M
    return ptr_ & kUnknownFieldsTagMask;
203
11.5M
  }
204
1.62M
  PROTOBUF_ALWAYS_INLINE bool HasMessageOwnedArenaTag() const {
205
1.62M
    return ptr_ & kMessageOwnedArenaTagMask;
206
1.62M
  }
207
208
  template <typename U>
209
10.7M
  U* PtrValue() const {
210
10.7M
    return reinterpret_cast<U*>(ptr_ & kPtrValueMask);
211
10.7M
  }
google::protobuf::internal::InternalMetadata::ContainerBase* google::protobuf::internal::InternalMetadata::PtrValue<google::protobuf::internal::InternalMetadata::ContainerBase>() const
Line
Count
Source
209
420k
  U* PtrValue() const {
210
420k
    return reinterpret_cast<U*>(ptr_ & kPtrValueMask);
211
420k
  }
google::protobuf::Arena* google::protobuf::internal::InternalMetadata::PtrValue<google::protobuf::Arena>() const
Line
Count
Source
209
3.49M
  U* PtrValue() const {
210
3.49M
    return reinterpret_cast<U*>(ptr_ & kPtrValueMask);
211
3.49M
  }
google::protobuf::internal::InternalMetadata::Container<google::protobuf::UnknownFieldSet>* google::protobuf::internal::InternalMetadata::PtrValue<google::protobuf::internal::InternalMetadata::Container<google::protobuf::UnknownFieldSet> >() const
Line
Count
Source
209
6.80M
  U* PtrValue() const {
210
6.80M
    return reinterpret_cast<U*>(ptr_ & kPtrValueMask);
211
6.80M
  }
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
175k
  PROTOBUF_NOINLINE Arena* DeleteOutOfLineHelper() {
225
175k
    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
0
      intptr_t message_owned_arena_tag = ptr_ & kMessageOwnedArenaTagMask;
230
0
      ptr_ = reinterpret_cast<intptr_t>(a) | message_owned_arena_tag;
231
0
      return a;
232
175k
    } else {
233
175k
      delete PtrValue<Container<T>>();
234
175k
      ptr_ = 0;
235
175k
      return nullptr;
236
175k
    }
237
175k
  }
238
239
  template <typename T>
240
175k
  PROTOBUF_NOINLINE T* mutable_unknown_fields_slow() {
241
175k
    Arena* my_arena = arena();
242
175k
    Container<T>* container = Arena::Create<Container<T>>(my_arena);
243
175k
    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
175k
    ptr_ = reinterpret_cast<intptr_t>(container);
247
175k
    ptr_ |= kUnknownFieldsTagMask | message_owned_arena_tag;
248
175k
    container->arena = my_arena;
249
175k
    return &(container->unknown_fields);
250
175k
  }
251
252
  // Templated functions.
253
254
  template <typename T>
255
0
  PROTOBUF_NOINLINE void DoClear() {
256
0
    mutable_unknown_fields<T>()->Clear();
257
0
  }
258
259
  template <typename T>
260
5.14k
  PROTOBUF_NOINLINE void DoMergeFrom(const T& other) {
261
5.14k
    mutable_unknown_fields<T>()->MergeFrom(other);
262
5.14k
  }
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
275
template <>
276
PROTOBUF_EXPORT void InternalMetadata::DoClear<std::string>();
277
template <>
278
PROTOBUF_EXPORT void InternalMetadata::DoMergeFrom<std::string>(
279
    const std::string& other);
280
template <>
281
PROTOBUF_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.
291
class PROTOBUF_EXPORT LiteUnknownFieldSetter {
292
 public:
293
  explicit LiteUnknownFieldSetter(InternalMetadata* metadata)
294
0
      : metadata_(metadata) {
295
0
    if (metadata->have_unknown_fields()) {
296
0
      buffer_.swap(*metadata->mutable_unknown_fields<std::string>());
297
0
    }
298
0
  }
299
0
  ~LiteUnknownFieldSetter() {
300
0
    if (!buffer_.empty())
301
0
      metadata_->mutable_unknown_fields<std::string>()->swap(buffer_);
302
0
  }
303
0
  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__