8000 Change pgcrypto to use the new ResourceOwner mechanism. · postgrespro/postgres@cd694f6 · GitHub
[go: up one dir, main page]

Skip to content
  • Commit cd694f6

    Browse files
    committed
    Change pgcrypto to use the new ResourceOwner mechanism.
    This is a nice example of how extensions can now use ResourceOwners to track extension-specific resource kinds Reviewed-by: Peter Eisentraut, Andres Freund Discussion: https://www.postgresql.org/message-id/d746cead-a1ef-7efe-fb47-933311e876a3%40iki.fi
    1 parent 954e435 commit cd694f6

    File tree

    1 file changed

    +78
    -103
    lines changed

    1 file changed

    +78
    -103
    lines changed

    contrib/pgcrypto/openssl.c

    Lines changed: 78 additions & 103 deletions
    Original file line numberDiff line numberDiff line change
    @@ -50,64 +50,48 @@
    5050
    */
    5151

    5252
    /*
    53-
    * To make sure we don't leak OpenSSL handles on abort, we keep OSSLDigest
    54-
    * objects in a linked list, allocated in TopMemoryContext. We use the
    55-
    * ResourceOwner mechanism to free them on abort.
    53+
    * To make sure we don't leak OpenSSL handles, we use the ResourceOwner
    54+
    * mechanism to free them on abort.
    5655
    */
    5756
    typedef struct OSSLDigest
    5857
    {
    5958
    const EVP_MD *algo;
    6059
    EVP_MD_CTX *ctx;
    6160

    6261
    ResourceOwner owner;
    63-
    struct OSSLDigest *next;
    64-
    struct OSSLDigest *prev;
    6562
    } OSSLDigest;
    6663

    67-
    static OSSLDigest *open_digests = NULL;
    68-
    static bool digest_resowner_callback_registered = false;
    64+
    /* ResourceOwner callbacks to hold OpenSSL digest handles */
    65+
    static void ResOwnerReleaseOSSLDigest(Datum res);
    6966

    70-
    static void
    71-
    free_openssl_digest(OSSLDigest *digest)
    67+
    static const ResourceOwnerDesc ossldigest_resowner_desc =
    7268
    {
    73-
    EVP_MD_CTX_destroy(digest->ctx);
    74-
    if (digest->prev)
    75-
    digest->prev->next = digest->next;
    76-
    else
    77-
    open_digests = digest->next;
    78-
    if (digest->next)
    79-
    digest->next->prev = digest->prev;
    80-
    pfree(digest);
    69+
    .name = "pgcrypto OpenSSL digest handle",
    70+
    .release_phase = RESOURCE_RELEASE_BEFORE_LOCKS,
    71+
    .release_priority = RELEASE_PRIO_FIRST,
    72+
    .ReleaseResource = ResOwnerReleaseOSSLDigest,
    73+
    .DebugPrint = NULL, /* default message is fine */
    74+
    };
    75+
    76+
    /* Convenience wrappers over ResourceOwnerRemember/Forget */
    77+
    static inline void
    78+
    ResourceOwnerRememberOSSLDigest(ResourceOwner owner, OSSLDigest *digest)
    79+
    {
    80+
    ResourceOwnerRemember(owner, PointerGetDatum(digest), &ossldigest_resowner_desc);
    81+
    }
    82+
    static inline void
    83+
    ResourceOwnerForgetOSSLDigest(ResourceOwner owner, OSSLDigest *digest)
    84+
    {
    85+
    ResourceOwnerForget(owner, PointerGetDatum(digest), &ossldigest_resowner_desc);
    8186
    }
    8287

    83-
    /*
    84-
    * Close any open OpenSSL handles on abort.
    85-
    */
    8688
    static void
    87-
    digest_free_callback(ResourceReleasePhase phase,
    88-
    bool isCommit,
    89-
    bool isTopLevel,
    90-
    void *arg)
    89+
    free_openssl_digest(OSSLDigest *digest)
    9190
    {
    92-
    OSSLDigest *curr;
    93-
    OSSLDigest *next;
    94-
    95-
    if (phase != RESOURCE_RELEASE_AFTER_LOCKS)
    96-
    return;
    97-
    98-
    next = open_digests;
    99-
    while (next)
    100-
    {
    101-
    curr = next;
    102-
    next = curr->next;
    103-
    104-
    if (curr->owner == CurrentResourceOwner)
    105-
    {
    106-
    if (isCommit)
    107-
    elog(WARNING, "pgcrypto digest reference leak: digest %p still referenced", curr);
    108-
    free_openssl_digest(curr);
    109-
    }
    110-
    }
    91+
    EVP_MD_CTX_destroy(digest->ctx);
    92+
    if (digest->owner != NULL)
    93+
    ResourceOwnerForgetOSSLDigest(digest->owner, digest);
    94+
    pfree(digest);
    11195
    }
    11296

    11397
    static unsigned
    @@ -188,16 +172,12 @@ px_find_digest(const char *name, PX_MD **res)
    188172
    OpenSSL_add_all_algorithms();
    189173
    }
    190174

    191-
    if (!digest_resowner_callback_registered)
    192-
    {
    193-
    RegisterResourceReleaseCallback(digest_free_callback, NULL);
    194-
    digest_resowner_callback_registered = true;
    195-
    }
    196-
    197175
    md = EVP_get_digestbyname(name);
    198176
    if (md == NULL)
    199177
    return PXE_NO_HASH;
    200178

    179+
    ResourceOwnerEnlarge(CurrentResourceOwner);
    180+
    201181
    /*
    202182
    * Create an OSSLDigest object, an OpenSSL MD object, and a PX_MD object.
    203183
    * The order is crucial, to make sure we don't leak anything on
    @@ -221,9 +201,7 @@ px_find_digest(const char *name, PX_MD **res)
    221201
    digest->algo = md;
    222202
    digest->ctx = ctx;
    223203
    digest->owner = CurrentResourceOwner;
    224-
    digest->next = open_digests;
    225-
    digest->prev = NULL;
    226-
    open_digests = digest;
    204+
    ResourceOwnerRememberOSSLDigest(digest->owner, digest);
    227205

    228206
    /* The PX_MD object is allocated in the current memory context. */
    229207
    h = palloc(sizeof(*h));
    @@ -239,6 +217,17 @@ px_find_digest(const char *name, PX_MD **res)
    239217
    return 0;
    240218
    }
    241219

    220+
    /* ResourceOwner callbacks for OSSLDigest */
    221+
    222+
    static void
    223+
    ResOwnerReleaseOSSLDigest(Datum res)
    224+
    {
    225+
    OSSLDigest *digest = (OSSLDigest *) DatumGetPointer(res);
    226+
    227+
    digest->owner = NULL;
    228+
    free_openssl_digest(digest);
    229+
    }
    230+
    242231
    /*
    243232
    * Ciphers
    244233
    *
    @@ -266,9 +255,8 @@ struct ossl_cipher
    266255
    * OSSLCipher contains the state for using a cipher. A separate OSSLCipher
    267256
    * object is allocated in each px_find_cipher() call.
    268257
    *
    269-
    * To make sure we don't leak OpenSSL handles on abort, we keep OSSLCipher
    270-
    * objects in a linked list, allocated in TopMemoryContext. We use the
    271-
    * ResourceOwner mechanism to free them on abort.
    258+
    * To make sure we don't leak OpenSSL handles, we use the ResourceOwner
    259+
    * mechanism to free them on abort.
    272260
    */
    273261
    typedef struct OSSLCipher
    274262
    {
    @@ -281,54 +269,39 @@ typedef struct OSSLCipher
    281269
    const struct ossl_cipher *ciph;
    282270

    283271
    ResourceOwner owner;
    284-
    struct OSSLCipher *next;
    285-
    struct OSSLCipher *prev;
    286272
    } OSSLCipher;
    287273

    288-
    static OSSLCipher *open_ciphers = NULL;
    289-
    static bool cipher_resowner_callback_registered = false;
    274+
    /* ResourceOwner callbacks to hold OpenSSL cipher state */
    275+
    static void ResOwnerReleaseOSSLCipher(Datum res);
    290276

    291-
    static void
    292-
    free_openssl_cipher(OSSLCipher *od)
    277+
    static const ResourceOwnerDesc osslcipher_resowner_desc =
    293278
    {
    294-
    EVP_CIPHER_CTX_free(od->evp_ctx);
    295-
    if (od->prev)
    296-
    od->prev->next = od->next;
    297-
    else
    298-
    open_ciphers = od->next;
    299-
    if (od->next)
    300-
    od->next->prev = od->prev;
    301-
    pfree(od);
    279+
    .name = "pgcrypto OpenSSL cipher handle",
    280+
    .release_phase = RESOURCE_RELEASE_BEFORE_LOCKS,
    281+
    .release_priority = RELEASE_PRIO_FIRST,
    282+
    .ReleaseResource = ResOwnerReleaseOSSLCipher,
    283+
    .DebugPrint = NULL, /* default message is fine */
    284+
    };
    285+
    286+
    /* Convenience wrappers over ResourceOwnerRemember/Forget */
    287+
    static inline void
    288+
    ResourceOwnerRememberOSSLCipher(ResourceOwner owner, OSSLCipher *od)
    289+
    {
    290+
    ResourceOwnerRemember(owner, PointerGetDatum(od), &osslcipher_resowner_desc);
    291+
    }
    292+
    static inline void
    293+
    ResourceOwnerForgetOSSLCipher(ResourceOwner owner, OSSLCipher *od)
    294+
    {
    295+
    ResourceOwnerForget(owner, PointerGetDatum(od), &osslcipher_resowner_desc);
    302296
    }
    303297

    304-
    /*
    305-
    * Close any open OpenSSL cipher handles on abort.
    306-
    */
    307298
    static void
    308-
    cipher_free_callback(ResourceReleasePhase phase,
    309-
    bool isCommit,
    310-
    bool isTopLevel,
    311-
    void *arg)
    299+
    free_openssl_cipher(OSSLCipher *od)
    312300
    {
    313-
    OSSLCipher *curr;
    314-
    OSSLCipher *next;
    315-
    316-
    if (phase != RESOURCE_RELEASE_AFTER_LOCKS)
    317-
    return;
    318-
    319-
    next = open_ciphers;
    320-
    while (next)
    321-
    {
    322-
    curr = next;
    323-
    next = curr->next;
    324-
    325-
    if (curr->owner == CurrentResourceOwner)
    326-
    {
    327-
    if (isCommit)
    328-
    elog(WARNING, "pgcrypto cipher reference leak: cipher %p still referenced", curr);
    329-
    free_openssl_cipher(curr);
    330-
    }
    331-
    }
    301+
    EVP_CIPHER_CTX_free(od->evp_ctx);
    302+
    if (od->owner != NULL)
    303+
    ResourceOwnerForgetOSSLCipher(od->owner, od);
    304+
    pfree(od);
    332305
    }
    333306

    334307
    /* Common routines for all algorithms */
    @@ -782,11 +755,7 @@ px_find_cipher(const char *name, PX_Cipher **res)
    782755
    if (i->name == NULL)
    783756
    return PXE_NO_CIPHER;
    784757

    785-
    if (!cipher_resowner_callback_registered)
    786-
    {
    787-
    RegisterResourceReleaseCallback(cipher_free_callback, NULL);
    788-
    cipher_resowner_callback_registered = true;
    789-
    }
    758+
    ResourceOwnerEnlarge(CurrentResourceOwner);
    790759

    791760
    /*
    792761
    * Create an OSSLCipher object, an EVP_CIPHER_CTX object and a PX_Cipher.
    @@ -806,9 +775,7 @@ px_find_cipher(const char *name, PX_Cipher **res)
    806775

    807776
    od->evp_ctx = ctx;
    808777
    od->owner = CurrentResourceOwner;
    809-
    od->next = open_ciphers;
    810-
    od->prev = NULL;
    811-
    open_ciphers = od;
    778+
    ResourceOwnerRememberOSSLCipher(od->owner, od);
    812779

    813780
    if (i->ciph->cipher_func)
    814781
    od->evp_ciph = i->ciph->cipher_func();
    @@ -827,3 +794,11 @@ px_find_cipher(const char *name, PX_Cipher **res)
    827794
    *res = c;
    828795
    return 0;
    829796
    }
    797+
    798+
    /* ResourceOwner callbacks for OSSLCipher */
    799+
    800+
    static void
    801+
    ResOwnerReleaseOSSLCipher(Datum res)
    802+
    {
    803+
    free_openssl_cipher((OSSLCipher *) DatumGetPointer(res));
    804+
    }

    0 commit comments

    Comments
     (0)
    0