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_FIELD_ACCESS_LISTENER_H__
32 #define GOOGLE_PROTOBUF_FIELD_ACCESS_LISTENER_H__
33
34 #include <cstddef>
35 #include <functional>
36 #include <string>
37 #include <type_traits>
38 #include <utility>
39 #include <vector>
40
41 #include <google/protobuf/stubs/common.h>
42 #include <google/protobuf/arenastring.h>
43 #include <google/protobuf/descriptor.h>
44 #include <google/protobuf/map.h>
45 #include <google/protobuf/stubs/once.h>
46 #include <google/protobuf/repeated_field.h>
47
48
49 namespace google {
50 namespace protobuf {
51 namespace internal {
52 template <typename T>
53 struct ResolvedType {
54 using type = T;
55 };
56 } // namespace internal
57 // Tracks the events of field accesses for all protos
58 // that are built with --inject_field_listener_events. This is a global
59 // interface which you must implement yourself and register with
60 // RegisterListener() function. All events consist of Descriptors,
61 // FieldAccessTypes and the underlying storage for tracking the memory which is
62 // accessed where possible and makes sense. Users are responsible for the
63 // implementations to be thread safe.
64 class FieldAccessListener {
65 public:
66 FieldAccessListener() = default;
67 virtual ~FieldAccessListener() = default;
68
69 // The memory annotations of the proto fields that are touched by the
70 // accessors. They are returned as if the operation completes.
71 struct DataAnnotation {
72 DataAnnotation() = default;
DataAnnotationDataAnnotation73 DataAnnotation(const void* other_address, size_t other_size)
74 : address(other_address), size(other_size) {}
75 const void* address = nullptr;
76 size_t size = 0;
77 };
78 using AddressInfo = std::vector<DataAnnotation>;
79 using AddressInfoExtractor = std::function<AddressInfo()>;
80
81 enum class FieldAccessType {
82 kAdd, // add_<field>(f)
83 kAddMutable, // add_<field>()
84 kGet, // <field>() and <repeated_field>(i)
85 kClear, // clear_<field>()
86 kHas, // has_<field>()
87 kList, // <repeated_field>()
88 kMutable, // mutable_<field>()
89 kMutableList, // mutable_<repeated_field>()
90 kRelease, // release_<field>()
91 kSet, // set_<field>() and set_<repeated_field>(i)
92 kSize, // <repeated_field>_size()
93 };
94
95 static FieldAccessListener* GetListener();
96
97 // Registers the field listener, can be called only once, |listener| must
98 // outlive all proto accesses (in most cases, the lifetime of the program).
99 static void RegisterListener(FieldAccessListener* listener);
100
101 // All field accessors noted in FieldAccessType have this call.
102 // |extractor| extracts the address info from the field
103 virtual void OnFieldAccess(const AddressInfoExtractor& extractor,
104 const FieldDescriptor* descriptor,
105 FieldAccessType access_type) = 0;
106
107 // Side effect calls.
108 virtual void OnDeserializationAccess(const Message* message) = 0;
109 virtual void OnSerializationAccess(const Message* message) = 0;
110 virtual void OnReflectionAccess(const Descriptor* descriptor) = 0;
111 virtual void OnByteSizeAccess(const Message* message) = 0;
112 // We can probably add more if we need to, like {Merge,Copy}{From}Access.
113
114 // Extracts all the addresses from the underlying fields.
115 template <typename T>
116 AddressInfo ExtractFieldInfo(const T* field_value);
117
118
119 private:
120 template <typename T>
121 AddressInfo ExtractFieldInfoSpecific(const T* field_value,
122 internal::ResolvedType<T>);
123
124 AddressInfo ExtractFieldInfoSpecific(const Message* field_value,
125 internal::ResolvedType<Message>);
126
127 AddressInfo ExtractFieldInfoSpecific(const std::string* field_value,
128 internal::ResolvedType<std::string>);
129
130 AddressInfo ExtractFieldInfoSpecific(
131 const internal::ArenaStringPtr* field_value,
132 internal::ResolvedType<internal::ArenaStringPtr>);
133
134 template <typename T>
135 AddressInfo ExtractFieldInfoSpecific(
136 const RepeatedField<T>* field_value,
137 internal::ResolvedType<RepeatedField<T>>);
138
139 template <typename T>
140 AddressInfo ExtractFieldInfoSpecific(
141 const RepeatedPtrField<T>* field_value,
142 internal::ResolvedType<RepeatedPtrField<T>>);
143
144 template <typename K, typename V>
145 AddressInfo ExtractFieldInfoSpecific(const Map<K, V>* field_value,
146 internal::ResolvedType<Map<K, V>>);
147
148 static internal::once_flag register_once_;
149 static FieldAccessListener* field_listener_;
150 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldAccessListener);
151 };
152
153 template <typename T>
ExtractFieldInfo(const T * field_value)154 inline FieldAccessListener::AddressInfo FieldAccessListener::ExtractFieldInfo(
155 const T* field_value) {
156 return ExtractFieldInfoSpecific(field_value, internal::ResolvedType<T>());
157 }
158
159
160 template <typename T>
161 inline FieldAccessListener::AddressInfo
ExtractFieldInfoSpecific(const T * field_value,internal::ResolvedType<T>)162 FieldAccessListener::ExtractFieldInfoSpecific(const T* field_value,
163 internal::ResolvedType<T>) {
164 static_assert(std::is_trivial<T>::value,
165 "This overload should be chosen only for trivial types");
166 return FieldAccessListener::AddressInfo{FieldAccessListener::DataAnnotation(
167 static_cast<const void*>(field_value), sizeof(*field_value))};
168 }
169
170 inline FieldAccessListener::AddressInfo
ExtractFieldInfoSpecific(const std::string * field_value,internal::ResolvedType<std::string>)171 FieldAccessListener::ExtractFieldInfoSpecific(
172 const std::string* field_value, internal::ResolvedType<std::string>) {
173 return FieldAccessListener::AddressInfo{FieldAccessListener::DataAnnotation(
174 static_cast<const void*>(field_value->c_str()), field_value->length())};
175 }
176
177 inline FieldAccessListener::AddressInfo
ExtractFieldInfoSpecific(const internal::ArenaStringPtr * field_value,internal::ResolvedType<internal::ArenaStringPtr>)178 FieldAccessListener::ExtractFieldInfoSpecific(
179 const internal::ArenaStringPtr* field_value,
180 internal::ResolvedType<internal::ArenaStringPtr>) {
181 return FieldAccessListener::ExtractFieldInfoSpecific(
182 field_value->GetPointer(), internal::ResolvedType<std::string>());
183 }
184
185 template <typename T>
186 inline FieldAccessListener::AddressInfo
ExtractFieldInfoSpecific(const RepeatedField<T> * field_value,internal::ResolvedType<RepeatedField<T>>)187 FieldAccessListener::ExtractFieldInfoSpecific(
188 const RepeatedField<T>* field_value,
189 internal::ResolvedType<RepeatedField<T>>) {
190 // TODO(jianzhouzh): This can cause data races. Synchronize this if needed.
191 FieldAccessListener::AddressInfo address_info;
192 address_info.reserve(field_value->size());
193 for (int i = 0, ie = field_value->size(); i < ie; ++i) {
194 auto sub = ExtractFieldInfoSpecific(&field_value->Get(i),
195 internal::ResolvedType<T>());
196 address_info.insert(address_info.end(), sub.begin(), sub.end());
197 }
198 return address_info;
199 }
200
201 template <typename T>
202 inline FieldAccessListener::AddressInfo
ExtractFieldInfoSpecific(const RepeatedPtrField<T> * field_value,internal::ResolvedType<RepeatedPtrField<T>>)203 FieldAccessListener::ExtractFieldInfoSpecific(
204 const RepeatedPtrField<T>* field_value,
205 internal::ResolvedType<RepeatedPtrField<T>>) {
206 FieldAccessListener::AddressInfo address_info;
207 // TODO(jianzhouzh): This can cause data races. Synchronize this if needed.
208 address_info.reserve(field_value->size());
209 for (int i = 0, ie = field_value->size(); i < ie; ++i) {
210 auto sub = ExtractFieldInfoSpecific(&field_value->Get(i),
211 internal::ResolvedType<T>());
212 address_info.insert(address_info.end(), sub.begin(), sub.end());
213 }
214 return address_info;
215 }
216
217 template <typename K, typename V>
218 inline FieldAccessListener::AddressInfo
ExtractFieldInfoSpecific(const Map<K,V> * field_value,internal::ResolvedType<Map<K,V>>)219 FieldAccessListener::ExtractFieldInfoSpecific(
220 const Map<K, V>* field_value, internal::ResolvedType<Map<K, V>>) {
221 // TODO(jianzhouzh): This can cause data races. Synchronize this if needed.
222 FieldAccessListener::AddressInfo address_info;
223 address_info.reserve(field_value->size());
224 for (auto it = field_value->begin(); it != field_value->end(); ++it) {
225 auto sub_first =
226 ExtractFieldInfoSpecific(&it->first, internal::ResolvedType<K>());
227 auto sub_second =
228 ExtractFieldInfoSpecific(&it->second, internal::ResolvedType<V>());
229 address_info.insert(address_info.end(), sub_first.begin(), sub_first.end());
230 address_info.insert(address_info.end(), sub_second.begin(),
231 sub_second.end());
232 }
233 return address_info;
234 }
235
236 inline FieldAccessListener::AddressInfo
ExtractFieldInfoSpecific(const Message * field_value,internal::ResolvedType<Message>)237 FieldAccessListener::ExtractFieldInfoSpecific(const Message* field_value,
238 internal::ResolvedType<Message>) {
239 // TODO(jianzhouzh): implement and adjust all annotations in the compiler.
240 return {};
241 }
242
243 } // namespace protobuf
244 } // namespace google
245
246 #endif // GOOGLE_PROTOBUF_FIELD_ACCESS_LISTENER_H__
247