1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2023 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 // This header provides support for a per thread 'reflection mode'. 9 // 10 // Some protocol buffer optimizations use interceptors to determine which 11 // fields are effectively used in the application. These optimizations are 12 // disabled if certain reflection calls are intercepted as the assumption is 13 // then that any field data can be accessed. 14 // 15 // The 'reflection mode' defined in this header is intended to be used by 16 // logic such as ad-hoc profilers to indicate that any scoped reflection usage 17 // is not originating from, or affecting application code. This reflection mode 18 // can then be used by such interceptors to ignore any reflection calls not 19 // affecting the application behavior. 20 21 #ifndef GOOGLE_PROTOBUF_REFLECTION_MODE_H__ 22 #define GOOGLE_PROTOBUF_REFLECTION_MODE_H__ 23 24 #include <cstddef> 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 // The ReflectionModes are ordered in observability levels: 34 // kDefault: Lowest level. All reflection calls are observable. 35 // kDebugString: Middle level. Only reflection calls in Message::DebugString are 36 // observable. 37 // kDiagnostics: Highest level. No reflection calls are observable. 38 enum class ReflectionMode { 39 kDefault, 40 kDebugString, 41 kDiagnostics, 42 }; 43 44 // Returns the current ReflectionMode of protobuf for the current thread. This 45 // reflection mode can be used by interceptors to ignore any reflection calls 46 // not affecting the application behavior. 47 // Always returns `kDefault' if the current platform does not support thread 48 // local data. 49 ReflectionMode GetReflectionMode(); 50 51 // Scoping class to set the specific ReflectionMode for a given scope. 52 class PROTOBUF_EXPORT ScopedReflectionMode final { 53 public: 54 // Sets the current reflection mode, which will be restored at destruction. 55 // The reflection mode can only be 'elevated' in observability levels. 56 // For instance, if the current mode is `kDiagnostics` then scope will remain 57 // unchanged regardless of `mode`. 58 explicit ScopedReflectionMode(ReflectionMode mode); 59 60 // Restores the previous reflection mode. 61 ~ScopedReflectionMode(); 62 63 // Returns the scoped ReflectionMode for the current thread. 64 // See `GetReflectionMode()` for more information on purpose and usage. 65 static ReflectionMode current_reflection_mode(); 66 67 // ScopedReflectionMode is only intended to be used as a locally scoped 68 // instance to set a reflection mode for the code scoped by this instance. 69 ScopedReflectionMode(const ScopedReflectionMode&) = delete; 70 ScopedReflectionMode& operator=(const ScopedReflectionMode&) = delete; 71 72 private: 73 #if !defined(PROTOBUF_NO_THREADLOCAL) 74 const ReflectionMode previous_mode_; 75 #if defined(PROTOBUF_USE_DLLS) && defined(_WIN32) 76 // Thread local variables cannot be exposed through MSVC DLL interface but we 77 // can wrap them in static functions. 78 static ReflectionMode& reflection_mode(); 79 #else 80 PROTOBUF_CONSTINIT static PROTOBUF_THREAD_LOCAL ReflectionMode 81 reflection_mode_; 82 #endif // PROTOBUF_USE_DLLS && _MSC_VER 83 #endif // !PROTOBUF_NO_THREADLOCAL 84 }; 85 86 #if !defined(PROTOBUF_NO_THREADLOCAL) 87 88 #if defined(PROTOBUF_USE_DLLS) && defined(_WIN32) 89 ScopedReflectionMode(ReflectionMode mode)90inline ScopedReflectionMode::ScopedReflectionMode(ReflectionMode mode) 91 : previous_mode_(reflection_mode()) { 92 if (mode > reflection_mode()) { 93 reflection_mode() = mode; 94 } 95 } 96 ~ScopedReflectionMode()97inline ScopedReflectionMode::~ScopedReflectionMode() { 98 reflection_mode() = previous_mode_; 99 } 100 current_reflection_mode()101inline ReflectionMode ScopedReflectionMode::current_reflection_mode() { 102 return reflection_mode(); 103 } 104 105 #else 106 ScopedReflectionMode(ReflectionMode mode)107inline ScopedReflectionMode::ScopedReflectionMode(ReflectionMode mode) 108 : previous_mode_(reflection_mode_) { 109 if (mode > reflection_mode_) { 110 reflection_mode_ = mode; 111 } 112 } 113 ~ScopedReflectionMode()114inline ScopedReflectionMode::~ScopedReflectionMode() { 115 reflection_mode_ = previous_mode_; 116 } 117 current_reflection_mode()118inline ReflectionMode ScopedReflectionMode::current_reflection_mode() { 119 return reflection_mode_; 120 } 121 122 #endif // PROTOBUF_USE_DLLS && _MSC_VER 123 124 #else 125 ScopedReflectionMode(ReflectionMode mode)126inline ScopedReflectionMode::ScopedReflectionMode(ReflectionMode mode) {} ~ScopedReflectionMode()127inline ScopedReflectionMode::~ScopedReflectionMode() {} current_reflection_mode()128inline ReflectionMode ScopedReflectionMode::current_reflection_mode() { 129 return ReflectionMode::kDefault; 130 } 131 132 #endif // !PROTOBUF_NO_THREADLOCAL 133 GetReflectionMode()134inline ReflectionMode GetReflectionMode() { 135 return ScopedReflectionMode::current_reflection_mode(); 136 } 137 138 } // namespace internal 139 } // namespace protobuf 140 } // namespace google 141 142 #include "google/protobuf/port_undef.inc" 143 144 #endif // GOOGLE_PROTOBUF_REFLECTION_MODE_H__ 145