*/
/*
- * To make sure we don't leak OpenSSL handles on abort, we keep OSSLDigest
- * objects in a linked list, allocated in TopMemoryContext. We use the
- * ResourceOwner mechanism to free them on abort.
+ * To make sure we don't leak OpenSSL handles, we use the ResourceOwner
+ * mechanism to free them on abort.
*/
typedef struct OSSLDigest
{
EVP_MD_CTX *ctx;
ResourceOwner owner;
- struct OSSLDigest *next;
- struct OSSLDigest *prev;
} OSSLDigest;
-static OSSLDigest *open_digests = NULL;
-static bool digest_resowner_callback_registered = false;
+/* ResourceOwner callbacks to hold OpenSSL digest handles */
+static void ResOwnerReleaseOSSLDigest(Datum res);
-static void
-free_openssl_digest(OSSLDigest *digest)
+static const ResourceOwnerDesc ossldigest_resowner_desc =
{
- EVP_MD_CTX_destroy(digest->ctx);
- if (digest->prev)
- digest->prev->next = digest->next;
- else
- open_digests = digest->next;
- if (digest->next)
- digest->next->prev = digest->prev;
- pfree(digest);
+ .name = "pgcrypto OpenSSL digest handle",
+ .release_phase = RESOURCE_RELEASE_BEFORE_LOCKS,
+ .release_priority = RELEASE_PRIO_FIRST,
+ .ReleaseResource = ResOwnerReleaseOSSLDigest,
+ .DebugPrint = NULL, /* default message is fine */
+};
+
+/* Convenience wrappers over ResourceOwnerRemember/Forget */
+static inline void
+ResourceOwnerRememberOSSLDigest(ResourceOwner owner, OSSLDigest *digest)
+{
+ ResourceOwnerRemember(owner, PointerGetDatum(digest), &ossldigest_resowner_desc);
+}
+static inline void
+ResourceOwnerForgetOSSLDigest(ResourceOwner owner, OSSLDigest *digest)
+{
+ ResourceOwnerForget(owner, PointerGetDatum(digest), &ossldigest_resowner_desc);
}
-/*
- * Close any open OpenSSL handles on abort.
- */
static void
-digest_free_callback(ResourceReleasePhase phase,
- bool isCommit,
- bool isTopLevel,
- void *arg)
+free_openssl_digest(OSSLDigest *digest)
{
- OSSLDigest *curr;
- OSSLDigest *next;
-
- if (phase != RESOURCE_RELEASE_AFTER_LOCKS)
- return;
-
- next = open_digests;
- while (next)
- {
- curr = next;
- next = curr->next;
-
- if (curr->owner == CurrentResourceOwner)
- {
- if (isCommit)
- elog(WARNING, "pgcrypto digest reference leak: digest %p still referenced", curr);
- free_openssl_digest(curr);
- }
- }
+ EVP_MD_CTX_destroy(digest->ctx);
+ if (digest->owner != NULL)
+ ResourceOwnerForgetOSSLDigest(digest->owner, digest);
+ pfree(digest);
}
static unsigned
OpenSSL_add_all_algorithms();
}
- if (!digest_resowner_callback_registered)
- {
- RegisterResourceReleaseCallback(digest_free_callback, NULL);
- digest_resowner_callback_registered = true;
- }
-
md = EVP_get_digestbyname(name);
if (md == NULL)
return PXE_NO_HASH;
+ ResourceOwnerEnlarge(CurrentResourceOwner);
+
/*
* Create an OSSLDigest object, an OpenSSL MD object, and a PX_MD object.
* The order is crucial, to make sure we don't leak anything on
digest->algo = md;
digest->ctx = ctx;
digest->owner = CurrentResourceOwner;
- digest->next = open_digests;
- digest->prev = NULL;
- open_digests = digest;
+ ResourceOwnerRememberOSSLDigest(digest->owner, digest);
/* The PX_MD object is allocated in the current memory context. */
h = palloc(sizeof(*h));
return 0;
}
+/* ResourceOwner callbacks for OSSLDigest */
+
+static void
+ResOwnerReleaseOSSLDigest(Datum res)
+{
+ OSSLDigest *digest = (OSSLDigest *) DatumGetPointer(res);
+
+ digest->owner = NULL;
+ free_openssl_digest(digest);
+}
+
/*
* Ciphers
*
* OSSLCipher contains the state for using a cipher. A separate OSSLCipher
* object is allocated in each px_find_cipher() call.
*
- * To make sure we don't leak OpenSSL handles on abort, we keep OSSLCipher
- * objects in a linked list, allocated in TopMemoryContext. We use the
- * ResourceOwner mechanism to free them on abort.
+ * To make sure we don't leak OpenSSL handles, we use the ResourceOwner
+ * mechanism to free them on abort.
*/
typedef struct OSSLCipher
{
const struct ossl_cipher *ciph;
ResourceOwner owner;
- struct OSSLCipher *next;
- struct OSSLCipher *prev;
} OSSLCipher;
-static OSSLCipher *open_ciphers = NULL;
-static bool cipher_resowner_callback_registered = false;
+/* ResourceOwner callbacks to hold OpenSSL cipher state */
+static void ResOwnerReleaseOSSLCipher(Datum res);
-static void
-free_openssl_cipher(OSSLCipher *od)
+static const ResourceOwnerDesc osslcipher_resowner_desc =
{
- EVP_CIPHER_CTX_free(od->evp_ctx);
- if (od->prev)
- od->prev->next = od->next;
- else
- open_ciphers = od->next;
- if (od->next)
- od->next->prev = od->prev;
- pfree(od);
+ .name = "pgcrypto OpenSSL cipher handle",
+ .release_phase = RESOURCE_RELEASE_BEFORE_LOCKS,
+ .release_priority = RELEASE_PRIO_FIRST,
+ .ReleaseResource = ResOwnerReleaseOSSLCipher,
+ .DebugPrint = NULL, /* default message is fine */
+};
+
+/* Convenience wrappers over ResourceOwnerRemember/Forget */
+static inline void
+ResourceOwnerRememberOSSLCipher(ResourceOwner owner, OSSLCipher *od)
+{
+ ResourceOwnerRemember(owner, PointerGetDatum(od), &osslcipher_resowner_desc);
+}
+static inline void
+ResourceOwnerForgetOSSLCipher(ResourceOwner owner, OSSLCipher *od)
+{
+ ResourceOwnerForget(owner, PointerGetDatum(od), &osslcipher_resowner_desc);
}
-/*
- * Close any open OpenSSL cipher handles on abort.
- */
static void
-cipher_free_callback(ResourceReleasePhase phase,
- bool isCommit,
- bool isTopLevel,
- void *arg)
+free_openssl_cipher(OSSLCipher *od)
{
- OSSLCipher *curr;
- OSSLCipher *next;
-
- if (phase != RESOURCE_RELEASE_AFTER_LOCKS)
- return;
-
- next = open_ciphers;
- while (next)
- {
- curr = next;
- next = curr->next;
-
- if (curr->owner == CurrentResourceOwner)
- {
- if (isCommit)
- elog(WARNING, "pgcrypto cipher reference leak: cipher %p still referenced", curr);
- free_openssl_cipher(curr);
- }
- }
+ EVP_CIPHER_CTX_free(od->evp_ctx);
+ if (od->owner != NULL)
+ ResourceOwnerForgetOSSLCipher(od->owner, od);
+ pfree(od);
}
/* Common routines for all algorithms */
if (i->name == NULL)
return PXE_NO_CIPHER;
- if (!cipher_resowner_callback_registered)
- {
- RegisterResourceReleaseCallback(cipher_free_callback, NULL);
- cipher_resowner_callback_registered = true;
- }
+ ResourceOwnerEnlarge(CurrentResourceOwner);
/*
* Create an OSSLCipher object, an EVP_CIPHER_CTX object and a PX_Cipher.
od->evp_ctx = ctx;
od->owner = CurrentResourceOwner;
- od->next = open_ciphers;
- od->prev = NULL;
- open_ciphers = od;
+ ResourceOwnerRememberOSSLCipher(od->owner, od);
if (i->ciph->cipher_func)
od->evp_ciph = i->ciph->cipher_func();
*res = c;
return 0;
}
+
+/* ResourceOwner callbacks for OSSLCipher */
+
+static void
+ResOwnerReleaseOSSLCipher(Datum res)
+{
+ free_openssl_cipher((OSSLCipher *) DatumGetPointer(res));
+}