Coverage Report

Created: 2023-06-07 07:09

/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__