| File: | root/firefox-clang/toolkit/components/protobuf/src/google/protobuf/map.cc |
| Warning: | line 254, column 26 Forming reference to null pointer |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | // Protocol Buffers - Google's data interchange format | |||
| 2 | // Copyright 2008 Google Inc. All rights reserved. | |||
| 3 | // | |||
| 4 | // Use of this source code is governed by a BSD-style | |||
| 5 | // license that can be found in the LICENSE file or at | |||
| 6 | // https://developers.google.com/open-source/licenses/bsd | |||
| 7 | ||||
| 8 | #include "google/protobuf/map.h" | |||
| 9 | ||||
| 10 | #include <algorithm> | |||
| 11 | #include <atomic> | |||
| 12 | #include <cstddef> | |||
| 13 | #include <cstdint> | |||
| 14 | #include <string> | |||
| 15 | ||||
| 16 | #include "absl/base/no_destructor.h" | |||
| 17 | #include "absl/base/optimization.h" | |||
| 18 | #include "absl/functional/overload.h" | |||
| 19 | #include "absl/log/absl_check.h" | |||
| 20 | #include "google/protobuf/arena.h" | |||
| 21 | #include "google/protobuf/field_with_arena.h" | |||
| 22 | #include "google/protobuf/message_lite.h" | |||
| 23 | #include "google/protobuf/port.h" | |||
| 24 | ||||
| 25 | ||||
| 26 | // Must be included last. | |||
| 27 | #include "google/protobuf/port_def.inc" | |||
| 28 | ||||
| 29 | namespace google { | |||
| 30 | namespace protobuf { | |||
| 31 | namespace internal { | |||
| 32 | ||||
| 33 | std::atomic<MapFieldBaseForParse::SyncFunc> | |||
| 34 | MapFieldBaseForParse::sync_map_with_repeated{}; | |||
| 35 | ||||
| 36 | NodeBase* const kGlobalEmptyTable[kGlobalEmptyTableSize] = {}; | |||
| 37 | ||||
| 38 | void UntypedMapBase::UntypedMergeFrom(Arena* arena, | |||
| 39 | const UntypedMapBase& other) { | |||
| 40 | ABSL_DCHECK_EQ(arena, this->arena())while (const char* absl_log_internal_check_op_result [[maybe_unused ]] = ::absl::log_internal::Check_EQImpl( ::absl::log_internal ::GetReferenceableValue((arena)), ::absl::log_internal::GetReferenceableValue ((this->arena())), ("arena" " " "==" " " "this->arena()" ))) switch (0) case 0: default: !(true) ? (void)0 : ::absl::log_internal ::Voidify() && ::absl::log_internal::LogMessageFatal( "/root/firefox-clang/toolkit/components/protobuf/src/google/protobuf/map.cc" , 40, ::absl::implicit_cast<const char* >( absl_log_internal_check_op_result )) .InternalStream(); | |||
| 41 | if (other.empty()) return; | |||
| 42 | ||||
| 43 | // Do the merging in steps to avoid Key*Value number of instantiations and | |||
| 44 | // reduce code duplication per instantation. | |||
| 45 | NodeBase* nodes = nullptr; | |||
| 46 | ||||
| 47 | // First, allocate all the nodes without types. | |||
| 48 | for (size_t i = 0; i < other.num_elements_; ++i) { | |||
| 49 | NodeBase* new_node = AllocNode(arena); | |||
| 50 | new_node->next = nodes; | |||
| 51 | nodes = new_node; | |||
| 52 | } | |||
| 53 | ||||
| 54 | // Then, copy the values. | |||
| 55 | VisitValueType([&](auto value_type) { | |||
| 56 | using Value = typename decltype(value_type)::type; | |||
| 57 | NodeBase* out_node = nodes; | |||
| 58 | ||||
| 59 | // Get the ClassData once to avoid redundant virtual function calls. | |||
| 60 | const internal::ClassData* class_data = | |||
| 61 | std::is_same_v<MessageLite, Value> | |||
| 62 | ? GetClassData(*other.GetValue<MessageLite>(other.begin().node_)) | |||
| 63 | : nullptr; | |||
| 64 | ||||
| 65 | for (auto it = other.begin(); !it.Equals(EndIterator()); it.PlusPlus()) { | |||
| 66 | Value* out = GetValue<Value>(out_node); | |||
| 67 | out_node = out_node->next; | |||
| 68 | auto& in = *other.GetValue<Value>(it.node_); | |||
| 69 | if constexpr (std::is_same_v<MessageLite, Value>) { | |||
| 70 | class_data->PlacementNew(out, arena)->CheckTypeAndMergeFrom(in); | |||
| 71 | } else { | |||
| 72 | Arena::CreateInArenaStorage(out, arena, in); | |||
| 73 | } | |||
| 74 | } | |||
| 75 | }); | |||
| 76 | ||||
| 77 | // Finally, copy the keys and insert the nodes. | |||
| 78 | VisitKeyType([&](auto key_type) { | |||
| 79 | using Key = typename decltype(key_type)::type; | |||
| 80 | for (auto it = other.begin(); !it.Equals(EndIterator()); it.PlusPlus()) { | |||
| 81 | NodeBase* node = nodes; | |||
| 82 | nodes = nodes->next; | |||
| 83 | const Key& in = *other.GetKey<Key>(it.node_); | |||
| 84 | Key* out = GetKey<Key>(node); | |||
| 85 | if (!internal::InitializeMapKey(out, in, arena)) { | |||
| 86 | Arena::CreateInArenaStorage(out, arena, in); | |||
| 87 | } | |||
| 88 | ||||
| 89 | static_cast<KeyMapBase<Key>*>(this)->InsertOrReplaceNode( | |||
| 90 | arena, static_cast<typename KeyMapBase<Key>::KeyNode*>(node)); | |||
| 91 | } | |||
| 92 | }); | |||
| 93 | } | |||
| 94 | ||||
| 95 | void UntypedMapBase::UntypedSwap(Arena* arena, UntypedMapBase& other, | |||
| 96 | Arena* other_arena) { | |||
| 97 | ABSL_DCHECK_EQ(arena, this->arena())while (const char* absl_log_internal_check_op_result [[maybe_unused ]] = ::absl::log_internal::Check_EQImpl( ::absl::log_internal ::GetReferenceableValue((arena)), ::absl::log_internal::GetReferenceableValue ((this->arena())), ("arena" " " "==" " " "this->arena()" ))) switch (0) case 0: default: !(true) ? (void)0 : ::absl::log_internal ::Voidify() && ::absl::log_internal::LogMessageFatal( "/root/firefox-clang/toolkit/components/protobuf/src/google/protobuf/map.cc" , 97, ::absl::implicit_cast<const char* >( absl_log_internal_check_op_result )) .InternalStream(); | |||
| 98 | ABSL_DCHECK_EQ(other_arena, other.arena())while (const char* absl_log_internal_check_op_result [[maybe_unused ]] = ::absl::log_internal::Check_EQImpl( ::absl::log_internal ::GetReferenceableValue((other_arena)), ::absl::log_internal:: GetReferenceableValue((other.arena())), ("other_arena" " " "==" " " "other.arena()"))) switch (0) case 0: default: !(true) ? (void)0 : ::absl::log_internal::Voidify() && ::absl:: log_internal::LogMessageFatal("/root/firefox-clang/toolkit/components/protobuf/src/google/protobuf/map.cc" , 98, ::absl::implicit_cast<const char* >( absl_log_internal_check_op_result )) .InternalStream(); | |||
| 99 | ||||
| 100 | if (arena == other_arena) { | |||
| 101 | InternalSwap(&other); | |||
| 102 | } else { | |||
| 103 | // `FieldWithArena` checks that the arena pointer is null when destroying a | |||
| 104 | // destructor-skippable type. Since `UntypedMapBase` is | |||
| 105 | // destructor-skippable, we need to put it in an `absl::NoDestructor` and | |||
| 106 | // manually destroy it if the arena pointer is null. | |||
| 107 | absl::NoDestructor<FieldWithArena<UntypedMapBase>> tmp_container( | |||
| 108 | arena, type_info_); | |||
| 109 | UntypedMapBase& tmp = tmp_container->field(); | |||
| 110 | InternalSwap(&tmp); | |||
| 111 | ||||
| 112 | ABSL_DCHECK(empty())switch (0) case 0: default: !((__builtin_expect(false || (!(( empty()))), false))) ? (void)0 : ::absl::log_internal::Voidify () && ::absl::log_internal::LogMessageFatal("/root/firefox-clang/toolkit/components/protobuf/src/google/protobuf/map.cc" , 112, "empty()").InternalStream(); | |||
| 113 | UntypedMergeFrom(arena, other); | |||
| 114 | ||||
| 115 | other.ClearTable(other_arena, /*reset=*/true); | |||
| 116 | other.UntypedMergeFrom(other_arena, tmp); | |||
| 117 | ||||
| 118 | if (arena == nullptr) { | |||
| 119 | tmp.ClearTable(arena, /*reset=*/false); | |||
| 120 | tmp.~UntypedMapBase(); | |||
| 121 | } | |||
| 122 | } | |||
| 123 | } | |||
| 124 | ||||
| 125 | void UntypedMapBase::DeleteNode(NodeBase* node) { | |||
| 126 | const auto destroy = absl::Overload{ | |||
| 127 | [](std::string* str) { str->~basic_string(); }, | |||
| 128 | [](MessageLite* msg) { msg->DestroyInstance(); }, [](void*) {}}; | |||
| 129 | VisitKey(node, destroy); | |||
| 130 | VisitValue(node, destroy); | |||
| 131 | DeallocNode(node); | |||
| 132 | } | |||
| 133 | ||||
| 134 | void UntypedMapBase::DeleteList(NodeBase* list) { | |||
| 135 | while (list != nullptr) { | |||
| 136 | NodeBase* n = list; | |||
| 137 | list = list->next; | |||
| 138 | DeleteNode(n); | |||
| 139 | } | |||
| 140 | } | |||
| 141 | ||||
| 142 | void UntypedMapBase::ClearTableImpl(Arena* arena, bool reset) { | |||
| 143 | ABSL_DCHECK_NE(num_buckets_, kGlobalEmptyTableSize)while (const char* absl_log_internal_check_op_result [[maybe_unused ]] = ::absl::log_internal::Check_NEImpl( ::absl::log_internal ::GetReferenceableValue((num_buckets_)), ::absl::log_internal ::GetReferenceableValue((kGlobalEmptyTableSize)), ("num_buckets_" " " "!=" " " "kGlobalEmptyTableSize"))) switch (0) case 0: default : !(true) ? (void)0 : ::absl::log_internal::Voidify() && ::absl::log_internal::LogMessageFatal("/root/firefox-clang/toolkit/components/protobuf/src/google/protobuf/map.cc" , 143, ::absl::implicit_cast<const char* >( absl_log_internal_check_op_result )) .InternalStream(); | |||
| 144 | ABSL_DCHECK_EQ(arena, this->arena())while (const char* absl_log_internal_check_op_result [[maybe_unused ]] = ::absl::log_internal::Check_EQImpl( ::absl::log_internal ::GetReferenceableValue((arena)), ::absl::log_internal::GetReferenceableValue ((this->arena())), ("arena" " " "==" " " "this->arena()" ))) switch (0) case 0: default: !(true) ? (void)0 : ::absl::log_internal ::Voidify() && ::absl::log_internal::LogMessageFatal( "/root/firefox-clang/toolkit/components/protobuf/src/google/protobuf/map.cc" , 144, ::absl::implicit_cast<const char* >( absl_log_internal_check_op_result )) .InternalStream(); | |||
| 145 | ||||
| 146 | if (arena == nullptr) { | |||
| 147 | const auto loop = [this](auto destroy_node) { | |||
| 148 | NodeBase** table = table_; | |||
| 149 | for (map_index_t b = 0, end = num_buckets_; b < end; ++b) { | |||
| 150 | for (NodeBase* node = table[b]; node != nullptr;) { | |||
| 151 | NodeBase* next = node->next; | |||
| 152 | absl::PrefetchToLocalCacheNta(next); | |||
| 153 | destroy_node(node); | |||
| 154 | SizedDelete(node, type_info_.node_size); | |||
| 155 | node = next; | |||
| 156 | } | |||
| 157 | } | |||
| 158 | }; | |||
| 159 | ||||
| 160 | const auto dispatch_key = [&](auto value_handler) { | |||
| 161 | if (type_info_.key_type_kind() < TypeKind::kString) { | |||
| 162 | loop(value_handler); | |||
| 163 | } else if (type_info_.key_type_kind() == TypeKind::kString) { | |||
| 164 | loop([=](NodeBase* node) { | |||
| 165 | static_cast<std::string*>(node->GetVoidKey())->~basic_string(); | |||
| 166 | value_handler(node); | |||
| 167 | }); | |||
| 168 | } else { | |||
| 169 | Unreachable(); | |||
| 170 | } | |||
| 171 | }; | |||
| 172 | ||||
| 173 | if (type_info_.value_type_kind() < TypeKind::kString) { | |||
| 174 | dispatch_key([](NodeBase*) {}); | |||
| 175 | } else if (type_info_.value_type_kind() == TypeKind::kString) { | |||
| 176 | dispatch_key([&](NodeBase* node) { | |||
| 177 | GetValue<std::string>(node)->~basic_string(); | |||
| 178 | }); | |||
| 179 | } else if (type_info_.value_type_kind() == TypeKind::kMessage) { | |||
| 180 | dispatch_key([&](NodeBase* node) { | |||
| 181 | GetValue<MessageLite>(node)->DestroyInstance(); | |||
| 182 | }); | |||
| 183 | } else { | |||
| 184 | Unreachable(); | |||
| 185 | } | |||
| 186 | } | |||
| 187 | ||||
| 188 | if (reset) { | |||
| 189 | std::fill(table_, table_ + num_buckets_, nullptr); | |||
| 190 | num_elements_ = 0; | |||
| 191 | } else { | |||
| 192 | DeleteTable(arena, table_, num_buckets_); | |||
| 193 | } | |||
| 194 | } | |||
| 195 | ||||
| 196 | size_t UntypedMapBase::SpaceUsedExcludingSelfLong() const { | |||
| 197 | size_t size = 0; | |||
| 198 | // The size of the table. | |||
| 199 | size += sizeof(void*) * num_buckets_; | |||
| 200 | // All the nodes. | |||
| 201 | size += type_info_.node_size * num_elements_; | |||
| 202 | VisitAllNodes([&](auto* key, auto* value) { | |||
| 203 | const auto space_used = absl::Overload{ | |||
| 204 | [](const std::string* str) -> size_t { | |||
| 205 | return StringSpaceUsedExcludingSelfLong(*str); | |||
| 206 | }, | |||
| 207 | [&](const MessageLite* msg) -> size_t { | |||
| 208 | const auto* class_data = GetClassData(*msg); | |||
| 209 | if (class_data->is_lite) return 0; | |||
| 210 | return class_data->full().descriptor_methods()->space_used_long( | |||
| 211 | *msg) - | |||
| 212 | class_data->allocation_size(); | |||
| 213 | }, | |||
| 214 | [](const void*) -> size_t { return 0; }}; | |||
| 215 | size += space_used(key); | |||
| 216 | size += space_used(value); | |||
| 217 | }); | |||
| 218 | return size; | |||
| 219 | } | |||
| 220 | ||||
| 221 | static size_t AlignTo(size_t v, size_t alignment, size_t& max_align) { | |||
| 222 | max_align = std::max<size_t>(max_align, alignment); | |||
| 223 | return (v + alignment - 1) / alignment * alignment; | |||
| 224 | } | |||
| 225 | ||||
| 226 | struct Offsets { | |||
| 227 | size_t start; | |||
| 228 | size_t end; | |||
| 229 | }; | |||
| 230 | ||||
| 231 | template <typename T> | |||
| 232 | static Offsets AlignAndAddSize(size_t v, size_t& max_align) { | |||
| 233 | v = AlignTo(v, alignof(T), max_align); | |||
| 234 | return {v, v + sizeof(T)}; | |||
| 235 | } | |||
| 236 | ||||
| 237 | static Offsets AlignAndAddSizeDynamic( | |||
| 238 | size_t v, UntypedMapBase::TypeKind kind, | |||
| 239 | const MessageLite* value_prototype_if_message, size_t& max_align) { | |||
| 240 | switch (kind) { | |||
| 241 | case UntypedMapBase::TypeKind::kBool: | |||
| 242 | return AlignAndAddSize<bool>(v, max_align); | |||
| 243 | case UntypedMapBase::TypeKind::kU32: | |||
| 244 | return AlignAndAddSize<int32_t>(v, max_align); | |||
| 245 | case UntypedMapBase::TypeKind::kU64: | |||
| 246 | return AlignAndAddSize<int64_t>(v, max_align); | |||
| 247 | case UntypedMapBase::TypeKind::kFloat: | |||
| 248 | return AlignAndAddSize<float>(v, max_align); | |||
| 249 | case UntypedMapBase::TypeKind::kDouble: | |||
| 250 | return AlignAndAddSize<double>(v, max_align); | |||
| 251 | case UntypedMapBase::TypeKind::kString: | |||
| 252 | return AlignAndAddSize<std::string>(v, max_align); | |||
| 253 | case UntypedMapBase::TypeKind::kMessage: { | |||
| 254 | auto* class_data = GetClassData(*value_prototype_if_message); | |||
| ||||
| 255 | v = AlignTo(v, class_data->alignment(), max_align); | |||
| 256 | return {v, v + class_data->allocation_size()}; | |||
| 257 | } | |||
| 258 | default: | |||
| 259 | Unreachable(); | |||
| 260 | } | |||
| 261 | } | |||
| 262 | ||||
| 263 | template <typename T, typename U> | |||
| 264 | T Narrow(U value) { | |||
| 265 | ABSL_CHECK_EQ(value, static_cast<T>(value))while (const char* absl_log_internal_check_op_result [[maybe_unused ]] = ::absl::log_internal::Check_EQImpl( ::absl::log_internal ::GetReferenceableValue((value)), ::absl::log_internal::GetReferenceableValue ((static_cast<T>(value))), ("value" " " "==" " " "static_cast<T>(value)" ))) switch (0) case 0: default: !(true) ? (void)0 : ::absl::log_internal ::Voidify() && ::absl::log_internal::LogMessageFatal( "/root/firefox-clang/toolkit/components/protobuf/src/google/protobuf/map.cc" , 265, ::absl::implicit_cast<const char* >( absl_log_internal_check_op_result )) .InternalStream(); | |||
| 266 | return static_cast<T>(value); | |||
| 267 | } | |||
| 268 | ||||
| 269 | UntypedMapBase::TypeInfo UntypedMapBase::GetTypeInfoDynamic( | |||
| 270 | TypeKind key_type, TypeKind value_type, | |||
| 271 | const MessageLite* value_prototype_if_message) { | |||
| 272 | size_t max_align = alignof(NodeBase); | |||
| 273 | const auto key_offsets = | |||
| 274 | AlignAndAddSizeDynamic(sizeof(NodeBase), key_type, nullptr, max_align); | |||
| ||||
| 275 | const auto value_offsets = AlignAndAddSizeDynamic( | |||
| 276 | key_offsets.end, value_type, value_prototype_if_message, max_align); | |||
| 277 | return TypeInfo{ | |||
| 278 | Narrow<uint16_t>(AlignTo(value_offsets.end, max_align, max_align)), | |||
| 279 | Narrow<uint8_t>(value_offsets.start), static_cast<uint8_t>(key_type), | |||
| 280 | static_cast<uint8_t>(value_type)}; | |||
| 281 | } | |||
| 282 | ||||
| 283 | void UntypedMapBase::InsertOrReplaceNodes(Arena* arena, NodeBase* list, | |||
| 284 | map_index_t count) { | |||
| 285 | if (ABSL_PREDICT_FALSE(count == 0)(__builtin_expect(false || (count == 0), false))) return; | |||
| 286 | VisitKeyType([this, arena, list, count](auto key_type) { | |||
| 287 | using Key = typename decltype(key_type)::type; | |||
| 288 | static_cast<KeyMapBase<Key>&>(*this).InsertOrReplaceNodes( | |||
| 289 | arena, static_cast<typename KeyMapBase<Key>::KeyNode*>(list), count); | |||
| 290 | }); | |||
| 291 | } | |||
| 292 | ||||
| 293 | } // namespace internal | |||
| 294 | } // namespace protobuf | |||
| 295 | } // namespace google | |||
| 296 | ||||
| 297 | #include "google/protobuf/port_undef.inc" |