// 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 #include #include #include #include #include #include #include #include #include #include #include namespace google { namespace protobuf { namespace internal { template 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; using AddressInfoExtractor = std::function; enum class FieldAccessType { kAdd, // add_(f) kAddMutable, // add_() kGet, // () and (i) kClear, // clear_() kHas, // has_() kList, // () kMutable, // mutable_() kMutableList, // mutable_() kRelease, // release_() kSet, // set_() and set_(i) kSize, // _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 AddressInfo ExtractFieldInfo(const T* field_value); private: template AddressInfo ExtractFieldInfoSpecific(const T* field_value, internal::ResolvedType); AddressInfo ExtractFieldInfoSpecific(const Message* field_value, internal::ResolvedType); AddressInfo ExtractFieldInfoSpecific(const std::string* field_value, internal::ResolvedType); AddressInfo ExtractFieldInfoSpecific( const internal::ArenaStringPtr* field_value, internal::ResolvedType); template AddressInfo ExtractFieldInfoSpecific( const RepeatedField* field_value, internal::ResolvedType>); template AddressInfo ExtractFieldInfoSpecific( const RepeatedPtrField* field_value, internal::ResolvedType>); template AddressInfo ExtractFieldInfoSpecific(const Map* field_value, internal::ResolvedType>); static internal::once_flag register_once_; static FieldAccessListener* field_listener_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldAccessListener); }; template inline FieldAccessListener::AddressInfo FieldAccessListener::ExtractFieldInfo( const T* field_value) { return ExtractFieldInfoSpecific(field_value, internal::ResolvedType()); } template inline FieldAccessListener::AddressInfo FieldAccessListener::ExtractFieldInfoSpecific(const T* field_value, internal::ResolvedType) { static_assert(std::is_trivial::value, "This overload should be chosen only for trivial types"); return FieldAccessListener::AddressInfo{FieldAccessListener::DataAnnotation( static_cast(field_value), sizeof(*field_value))}; } inline FieldAccessListener::AddressInfo FieldAccessListener::ExtractFieldInfoSpecific( const std::string* field_value, internal::ResolvedType) { return FieldAccessListener::AddressInfo{FieldAccessListener::DataAnnotation( static_cast(field_value->c_str()), field_value->length())}; } inline FieldAccessListener::AddressInfo FieldAccessListener::ExtractFieldInfoSpecific( const internal::ArenaStringPtr* field_value, internal::ResolvedType) { return FieldAccessListener::ExtractFieldInfoSpecific( field_value->GetPointer(), internal::ResolvedType()); } template inline FieldAccessListener::AddressInfo FieldAccessListener::ExtractFieldInfoSpecific( const RepeatedField* field_value, internal::ResolvedType>) { // 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()); address_info.insert(address_info.end(), sub.begin(), sub.end()); } return address_info; } template inline FieldAccessListener::AddressInfo FieldAccessListener::ExtractFieldInfoSpecific( const RepeatedPtrField* field_value, internal::ResolvedType>) { 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()); address_info.insert(address_info.end(), sub.begin(), sub.end()); } return address_info; } template inline FieldAccessListener::AddressInfo FieldAccessListener::ExtractFieldInfoSpecific( const Map* field_value, internal::ResolvedType>) { // 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()); auto sub_second = ExtractFieldInfoSpecific(&it->second, internal::ResolvedType()); 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) { // TODO(jianzhouzh): implement and adjust all annotations in the compiler. return {}; } } // namespace protobuf } // namespace google #endif // GOOGLE_PROTOBUF_FIELD_ACCESS_LISTENER_H__