Merge pull request #8652 from haberman/sync-stage
Integrate from Piper for C++, Java, and Pythonpull/8664/head
commit
bd42fcc7a3
49 changed files with 1650 additions and 292 deletions
@ -0,0 +1,52 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <google/protobuf/field_access_listener.h> |
||||
|
||||
#include <google/protobuf/stubs/once.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
|
||||
internal::once_flag FieldAccessListener::register_once_ = {}; |
||||
FieldAccessListener* FieldAccessListener::field_listener_ = nullptr; |
||||
|
||||
FieldAccessListener* FieldAccessListener::GetListener() { |
||||
return field_listener_; |
||||
} |
||||
|
||||
void FieldAccessListener::RegisterListener(FieldAccessListener* listener) { |
||||
// TODO(danilak): Add a GOOGLE_DCHECK for message_injector_ to be nullptr and update
|
||||
// tests.
|
||||
internal::call_once(register_once_, [&] { field_listener_ = listener; }); |
||||
} |
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,246 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_FIELD_ACCESS_LISTENER_H__ |
||||
#define GOOGLE_PROTOBUF_FIELD_ACCESS_LISTENER_H__ |
||||
|
||||
#include <cstddef> |
||||
#include <functional> |
||||
#include <string> |
||||
#include <type_traits> |
||||
#include <utility> |
||||
#include <vector> |
||||
|
||||
#include <google/protobuf/stubs/common.h> |
||||
#include <google/protobuf/arenastring.h> |
||||
#include <google/protobuf/descriptor.h> |
||||
#include <google/protobuf/map.h> |
||||
#include <google/protobuf/stubs/once.h> |
||||
#include <google/protobuf/repeated_field.h> |
||||
|
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace internal { |
||||
template <typename T> |
||||
struct ResolvedType { |
||||
using type = T; |
||||
}; |
||||
} // namespace internal
|
||||
// Tracks the events of field accesses for all protos
|
||||
// that are built with --inject_field_listener_events. This is a global
|
||||
// interface which you must implement yourself and register with
|
||||
// RegisterListener() function. All events consist of Descriptors,
|
||||
// FieldAccessTypes and the underlying storage for tracking the memory which is
|
||||
// accessed where possible and makes sense. Users are responsible for the
|
||||
// implementations to be thread safe.
|
||||
class FieldAccessListener { |
||||
public: |
||||
FieldAccessListener() = default; |
||||
virtual ~FieldAccessListener() = default; |
||||
|
||||
// The memory annotations of the proto fields that are touched by the
|
||||
// accessors. They are returned as if the operation completes.
|
||||
struct DataAnnotation { |
||||
DataAnnotation() = default; |
||||
DataAnnotation(const void* other_address, size_t other_size) |
||||
: address(other_address), size(other_size) {} |
||||
const void* address = nullptr; |
||||
size_t size = 0; |
||||
}; |
||||
using AddressInfo = std::vector<DataAnnotation>; |
||||
using AddressInfoExtractor = std::function<AddressInfo()>; |
||||
|
||||
enum class FieldAccessType { |
||||
kAdd, // add_<field>(f)
|
||||
kAddMutable, // add_<field>()
|
||||
kGet, // <field>() and <repeated_field>(i)
|
||||
kClear, // clear_<field>()
|
||||
kHas, // has_<field>()
|
||||
kList, // <repeated_field>()
|
||||
kMutable, // mutable_<field>()
|
||||
kMutableList, // mutable_<repeated_field>()
|
||||
kRelease, // release_<field>()
|
||||
kSet, // set_<field>() and set_<repeated_field>(i)
|
||||
kSize, // <repeated_field>_size()
|
||||
}; |
||||
|
||||
static FieldAccessListener* GetListener(); |
||||
|
||||
// Registers the field listener, can be called only once, |listener| must
|
||||
// outlive all proto accesses (in most cases, the lifetime of the program).
|
||||
static void RegisterListener(FieldAccessListener* listener); |
||||
|
||||
// All field accessors noted in FieldAccessType have this call.
|
||||
// |extractor| extracts the address info from the field
|
||||
virtual void OnFieldAccess(const AddressInfoExtractor& extractor, |
||||
const FieldDescriptor* descriptor, |
||||
FieldAccessType access_type) = 0; |
||||
|
||||
// Side effect calls.
|
||||
virtual void OnDeserializationAccess(const Message* message) = 0; |
||||
virtual void OnSerializationAccess(const Message* message) = 0; |
||||
virtual void OnReflectionAccess(const Descriptor* descriptor) = 0; |
||||
virtual void OnByteSizeAccess(const Message* message) = 0; |
||||
// We can probably add more if we need to, like {Merge,Copy}{From}Access.
|
||||
|
||||
// Extracts all the addresses from the underlying fields.
|
||||
template <typename T> |
||||
AddressInfo ExtractFieldInfo(const T* field_value); |
||||
|
||||
|
||||
private: |
||||
template <typename T> |
||||
AddressInfo ExtractFieldInfoSpecific(const T* field_value, |
||||
internal::ResolvedType<T>); |
||||
|
||||
AddressInfo ExtractFieldInfoSpecific(const Message* field_value, |
||||
internal::ResolvedType<Message>); |
||||
|
||||
AddressInfo ExtractFieldInfoSpecific(const std::string* field_value, |
||||
internal::ResolvedType<std::string>); |
||||
|
||||
AddressInfo ExtractFieldInfoSpecific( |
||||
const internal::ArenaStringPtr* field_value, |
||||
internal::ResolvedType<internal::ArenaStringPtr>); |
||||
|
||||
template <typename T> |
||||
AddressInfo ExtractFieldInfoSpecific( |
||||
const RepeatedField<T>* field_value, |
||||
internal::ResolvedType<RepeatedField<T>>); |
||||
|
||||
template <typename T> |
||||
AddressInfo ExtractFieldInfoSpecific( |
||||
const RepeatedPtrField<T>* field_value, |
||||
internal::ResolvedType<RepeatedPtrField<T>>); |
||||
|
||||
template <typename K, typename V> |
||||
AddressInfo ExtractFieldInfoSpecific(const Map<K, V>* field_value, |
||||
internal::ResolvedType<Map<K, V>>); |
||||
|
||||
static internal::once_flag register_once_; |
||||
static FieldAccessListener* field_listener_; |
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldAccessListener); |
||||
}; |
||||
|
||||
template <typename T> |
||||
inline FieldAccessListener::AddressInfo FieldAccessListener::ExtractFieldInfo( |
||||
const T* field_value) { |
||||
return ExtractFieldInfoSpecific(field_value, internal::ResolvedType<T>()); |
||||
} |
||||
|
||||
|
||||
template <typename T> |
||||
inline FieldAccessListener::AddressInfo |
||||
FieldAccessListener::ExtractFieldInfoSpecific(const T* field_value, |
||||
internal::ResolvedType<T>) { |
||||
static_assert(std::is_trivial<T>::value, |
||||
"This overload should be chosen only for trivial types"); |
||||
return FieldAccessListener::AddressInfo{FieldAccessListener::DataAnnotation( |
||||
static_cast<const void*>(field_value), sizeof(*field_value))}; |
||||
} |
||||
|
||||
inline FieldAccessListener::AddressInfo |
||||
FieldAccessListener::ExtractFieldInfoSpecific( |
||||
const std::string* field_value, internal::ResolvedType<std::string>) { |
||||
return FieldAccessListener::AddressInfo{FieldAccessListener::DataAnnotation( |
||||
static_cast<const void*>(field_value->c_str()), field_value->length())}; |
||||
} |
||||
|
||||
inline FieldAccessListener::AddressInfo |
||||
FieldAccessListener::ExtractFieldInfoSpecific( |
||||
const internal::ArenaStringPtr* field_value, |
||||
internal::ResolvedType<internal::ArenaStringPtr>) { |
||||
return FieldAccessListener::ExtractFieldInfoSpecific( |
||||
field_value->GetPointer(), internal::ResolvedType<std::string>()); |
||||
} |
||||
|
||||
template <typename T> |
||||
inline FieldAccessListener::AddressInfo |
||||
FieldAccessListener::ExtractFieldInfoSpecific( |
||||
const RepeatedField<T>* field_value, |
||||
internal::ResolvedType<RepeatedField<T>>) { |
||||
// TODO(jianzhouzh): This can cause data races. Synchronize this if needed.
|
||||
FieldAccessListener::AddressInfo address_info; |
||||
address_info.reserve(field_value->size()); |
||||
for (int i = 0, ie = field_value->size(); i < ie; ++i) { |
||||
auto sub = ExtractFieldInfoSpecific(&field_value->Get(i), |
||||
internal::ResolvedType<T>()); |
||||
address_info.insert(address_info.end(), sub.begin(), sub.end()); |
||||
} |
||||
return address_info; |
||||
} |
||||
|
||||
template <typename T> |
||||
inline FieldAccessListener::AddressInfo |
||||
FieldAccessListener::ExtractFieldInfoSpecific( |
||||
const RepeatedPtrField<T>* field_value, |
||||
internal::ResolvedType<RepeatedPtrField<T>>) { |
||||
FieldAccessListener::AddressInfo address_info; |
||||
// TODO(jianzhouzh): This can cause data races. Synchronize this if needed.
|
||||
address_info.reserve(field_value->size()); |
||||
for (int i = 0, ie = field_value->size(); i < ie; ++i) { |
||||
auto sub = ExtractFieldInfoSpecific(&field_value->Get(i), |
||||
internal::ResolvedType<T>()); |
||||
address_info.insert(address_info.end(), sub.begin(), sub.end()); |
||||
} |
||||
return address_info; |
||||
} |
||||
|
||||
template <typename K, typename V> |
||||
inline FieldAccessListener::AddressInfo |
||||
FieldAccessListener::ExtractFieldInfoSpecific( |
||||
const Map<K, V>* field_value, internal::ResolvedType<Map<K, V>>) { |
||||
// TODO(jianzhouzh): This can cause data races. Synchronize this if needed.
|
||||
FieldAccessListener::AddressInfo address_info; |
||||
address_info.reserve(field_value->size()); |
||||
for (auto it = field_value->begin(); it != field_value->end(); ++it) { |
||||
auto sub_first = |
||||
ExtractFieldInfoSpecific(&it->first, internal::ResolvedType<K>()); |
||||
auto sub_second = |
||||
ExtractFieldInfoSpecific(&it->second, internal::ResolvedType<V>()); |
||||
address_info.insert(address_info.end(), sub_first.begin(), sub_first.end()); |
||||
address_info.insert(address_info.end(), sub_second.begin(), |
||||
sub_second.end()); |
||||
} |
||||
return address_info; |
||||
} |
||||
|
||||
inline FieldAccessListener::AddressInfo |
||||
FieldAccessListener::ExtractFieldInfoSpecific(const Message* field_value, |
||||
internal::ResolvedType<Message>) { |
||||
// TODO(jianzhouzh): implement and adjust all annotations in the compiler.
|
||||
return {}; |
||||
} |
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_FIELD_ACCESS_LISTENER_H__
|
Loading…
Reference in new issue