]> git.ipfire.org Git - thirdparty/squid.git/blob - src/security/LockingPointer.h
Source Format Enforcement (#763)
[thirdparty/squid.git] / src / security / LockingPointer.h
1 /*
2 * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9 #ifndef SQUID_SRC_SECURITY_LOCKINGPOINTER_H
10 #define SQUID_SRC_SECURITY_LOCKINGPOINTER_H
11
12 #include "base/HardFun.h"
13
14 #if USE_OPENSSL
15 #include "compat/openssl.h"
16 #if HAVE_OPENSSL_CRYPTO_H
17 #include <openssl/crypto.h>
18 #endif
19
20 // Macro to be used to define the C++ wrapper function of a sk_*_pop_free
21 // openssl family functions. The C++ function suffixed with the _free_wrapper
22 // extension
23 #define sk_free_wrapper(sk_object, argument, freefunction) \
24 extern "C++" inline void sk_object ## _free_wrapper(argument a) { \
25 sk_object ## _pop_free(a, freefunction); \
26 }
27
28 #endif /* USE_OPENSSL */
29
30 // Macro to be used to define the C++ equivalent function of an extern "C"
31 // function. The C++ function suffixed with the _cpp extension
32 #define CtoCpp1(function, argument) \
33 extern "C++" inline void function ## _cpp(argument a) { \
34 function(a); \
35 }
36
37 namespace Security
38 {
39
40 inline bool nilFunction(const void *) { return false; }
41 typedef HardFun<bool, const void *, nilFunction> NilFunctor;
42
43 /**
44 * A shared pointer to a reference-counting Object with library-specific
45 * absorption, locking, and unlocking implementations. The API largely
46 * follows std::shared_ptr.
47 *
48 * The constructor and the resetWithoutLocking() method import a raw Object pointer.
49 * Normally, reset() would lock(), but libraries like OpenSSL
50 * pre-lock objects before they are fed to LockingPointer, necessitating
51 * this resetWithoutLocking() customization hook.
52 */
53 template <typename T, void (*UnLocker)(T *t), class Locker = NilFunctor>
54 class LockingPointer
55 {
56 public:
57 /// a helper label to simplify this objects API definitions below
58 typedef Security::LockingPointer<T, UnLocker, Locker> SelfType;
59
60 /// constructs a nil smart pointer
61 constexpr LockingPointer(): raw(nullptr) {}
62
63 /// constructs a nil smart pointer from nullptr
64 constexpr LockingPointer(std::nullptr_t): raw(nullptr) {}
65
66 /**
67 * Construct directly from a (possibly nil) raw pointer. If the supplied
68 * pointer is not nil, it is expected that its producer has already created
69 * one reference lock for the object pointed to, and our destructor will do
70 * the matching unlock.
71 */
72 explicit LockingPointer(T *t): raw(nullptr) {
73 // de-optimized for clarity about non-locking
74 resetWithoutLocking(t);
75 }
76
77 /// use the custom UnLocker to unlock any value still stored.
78 ~LockingPointer() { unlock(); }
79
80 // copy semantics are okay only when adding a lock reference
81 LockingPointer(const SelfType &o) : raw(nullptr) {
82 resetAndLock(o.get());
83 }
84 const SelfType &operator =(const SelfType &o) {
85 resetAndLock(o.get());
86 return *this;
87 }
88
89 LockingPointer(SelfType &&o) : raw(nullptr) {
90 resetWithoutLocking(o.release());
91 }
92 SelfType &operator =(SelfType &&o) {
93 if (o.get() != raw)
94 resetWithoutLocking(o.release());
95 return *this;
96 }
97
98 bool operator !() const { return !raw; }
99 explicit operator bool() const { return raw; }
100 bool operator ==(const SelfType &o) const { return (o.get() == raw); }
101 bool operator !=(const SelfType &o) const { return (o.get() != raw); }
102
103 T *operator ->() const { return raw; }
104
105 /// Returns raw and possibly nullptr pointer
106 T *get() const { return raw; }
107
108 /// Reset raw pointer - unlock any previous one and save new one without locking.
109 void resetWithoutLocking(T *t) {
110 unlock();
111 raw = t;
112 }
113
114 void resetAndLock(T *t) {
115 if (t != get()) {
116 resetWithoutLocking(t);
117 lock(t);
118 }
119 }
120
121 /// Forget the raw pointer - unlock if any value was set. Become a nil pointer.
122 void reset() { unlock(); }
123
124 /// Forget the raw pointer without unlocking it. Become a nil pointer.
125 T *release() {
126 T *ret = raw;
127 raw = nullptr;
128 return ret;
129 }
130
131 private:
132 /// The lock() method increments Object's reference counter.
133 void lock(T *t) {
134 if (t) {
135 Locker doLock;
136 doLock(t);
137 }
138 }
139
140 /// Become a nil pointer. Decrements any pointed-to Object's reference counter
141 /// using UnLocker which ideally destroys the object when the counter reaches zero.
142 void unlock() {
143 if (raw) {
144 UnLocker(raw);
145 raw = nullptr;
146 }
147 }
148
149 /**
150 * Normally, no other code will have this raw pointer.
151 *
152 * However, OpenSSL does some strange and not always consistent things.
153 * OpenSSL library may keep its own internal raw pointers and manage
154 * their reference counts independently, or it may not. This varies between
155 * API functions, though it is usually documented.
156 *
157 * This means the caller code needs to be carefully written to use the correct
158 * reset method and avoid the raw-pointer constructor unless OpenSSL function
159 * producing the pointer is clearly documented as incrementing a lock for it.
160 */
161 T *raw;
162 };
163
164 } // namespace Security
165
166 #endif /* SQUID_SRC_SECURITY_LOCKINGPOINTER_H */
167