41a6c3
diff --git a/modules/aaa/mod_auth_digest.c b/modules/aaa/mod_auth_digest.c
41a6c3
index 44b5fc8..6a50ba7 100644
41a6c3
--- a/modules/aaa/mod_auth_digest.c
41a6c3
+++ b/modules/aaa/mod_auth_digest.c
41a6c3
@@ -261,6 +261,26 @@ static void log_error_and_cleanup(char *msg, apr_status_t sts, server_rec *s)
41a6c3
     cleanup_tables(NULL);
41a6c3
 }
41a6c3
 
41a6c3
+/* RMM helper functions that behave like single-step malloc/free. */
41a6c3
+
41a6c3
+static void *rmm_malloc(apr_rmm_t *rmm, apr_size_t size)
41a6c3
+{
41a6c3
+    apr_rmm_off_t offset = apr_rmm_malloc(rmm, size);
41a6c3
+
41a6c3
+    if (!offset) {
41a6c3
+        return NULL;
41a6c3
+    }
41a6c3
+
41a6c3
+    return apr_rmm_addr_get(rmm, offset);
41a6c3
+}
41a6c3
+
41a6c3
+static apr_status_t rmm_free(apr_rmm_t *rmm, void *alloc)
41a6c3
+{
41a6c3
+    apr_rmm_off_t offset = apr_rmm_offset_get(rmm, alloc);
41a6c3
+
41a6c3
+    return apr_rmm_free(rmm, offset);
41a6c3
+}
41a6c3
+
41a6c3
 #if APR_HAS_SHARED_MEMORY
41a6c3
 
41a6c3
 static int initialize_tables(server_rec *s, apr_pool_t *ctx)
41a6c3
@@ -299,8 +319,8 @@ static int initialize_tables(server_rec *s, apr_pool_t *ctx)
41a6c3
         return !OK;
41a6c3
     }
41a6c3
 
41a6c3
-    client_list = apr_rmm_addr_get(client_rmm, apr_rmm_malloc(client_rmm, sizeof(*client_list) +
41a6c3
-                                                          sizeof(client_entry*)*num_buckets));
41a6c3
+    client_list = rmm_malloc(client_rmm, sizeof(*client_list) +
41a6c3
+                                         sizeof(client_entry *) * num_buckets);
41a6c3
     if (!client_list) {
41a6c3
         log_error_and_cleanup("failed to allocate shared memory", -1, s);
41a6c3
         return !OK;
41a6c3
@@ -322,7 +342,7 @@ static int initialize_tables(server_rec *s, apr_pool_t *ctx)
41a6c3
 
41a6c3
     /* setup opaque */
41a6c3
 
41a6c3
-    opaque_cntr = apr_rmm_addr_get(client_rmm, apr_rmm_malloc(client_rmm, sizeof(*opaque_cntr)));
41a6c3
+    opaque_cntr = rmm_malloc(client_rmm, sizeof(*opaque_cntr));
41a6c3
     if (opaque_cntr == NULL) {
41a6c3
         log_error_and_cleanup("failed to allocate shared memory", -1, s);
41a6c3
         return !OK;
41a6c3
@@ -339,7 +359,7 @@ static int initialize_tables(server_rec *s, apr_pool_t *ctx)
41a6c3
 
41a6c3
     /* setup one-time-nonce counter */
41a6c3
 
41a6c3
-    otn_counter = apr_rmm_addr_get(client_rmm, apr_rmm_malloc(client_rmm, sizeof(*otn_counter)));
41a6c3
+    otn_counter = rmm_malloc(client_rmm, sizeof(*otn_counter));
41a6c3
     if (otn_counter == NULL) {
41a6c3
         log_error_and_cleanup("failed to allocate shared memory", -1, s);
41a6c3
         return !OK;
41a6c3
@@ -779,7 +799,7 @@ static client_entry *get_client(unsigned long key, const request_rec *r)
41a6c3
  * last entry in each bucket and updates the counters. Returns the
41a6c3
  * number of removed entries.
41a6c3
  */
41a6c3
-static long gc(void)
41a6c3
+static long gc(server_rec *s)
41a6c3
 {
41a6c3
     client_entry *entry, *prev;
41a6c3
     unsigned long num_removed = 0, idx;
41a6c3
@@ -789,6 +809,12 @@ static long gc(void)
41a6c3
     for (idx = 0; idx < client_list->tbl_len; idx++) {
41a6c3
         entry = client_list->table[idx];
41a6c3
         prev  = NULL;
41a6c3
+
41a6c3
+        if (!entry) {
41a6c3
+            /* This bucket is empty. */
41a6c3
+            continue;
41a6c3
+        }
41a6c3
+
41a6c3
         while (entry->next) {   /* find last entry */
41a6c3
             prev  = entry;
41a6c3
             entry = entry->next;
41a6c3
@@ -800,8 +826,16 @@ static long gc(void)
41a6c3
             client_list->table[idx] = NULL;
41a6c3
         }
41a6c3
         if (entry) {                    /* remove entry */
41a6c3
-            apr_rmm_free(client_rmm, apr_rmm_offset_get(client_rmm, entry));
41a6c3
+            apr_status_t err;
41a6c3
+
41a6c3
+            err = rmm_free(client_rmm, entry);
41a6c3
             num_removed++;
41a6c3
+
41a6c3
+            if (err) {
41a6c3
+                /* Nothing we can really do but log... */
41a6c3
+                ap_log_error(APLOG_MARK, APLOG_ERR, err, s, APLOGNO()
41a6c3
+                             "Failed to free auth_digest client allocation");
41a6c3
+            }
41a6c3
         }
41a6c3
     }
41a6c3
 
41a6c3
@@ -835,16 +869,16 @@ static client_entry *add_client(unsigned long key, client_entry *info,
41a6c3
 
41a6c3
     /* try to allocate a new entry */
41a6c3
 
41a6c3
-    entry = apr_rmm_addr_get(client_rmm, apr_rmm_malloc(client_rmm, sizeof(client_entry)));
41a6c3
+    entry = rmm_malloc(client_rmm, sizeof(client_entry));
41a6c3
     if (!entry) {
41a6c3
-        long num_removed = gc();
41a6c3
+        long num_removed = gc(s);
41a6c3
         ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(01766)
41a6c3
                      "gc'd %ld client entries. Total new clients: "
41a6c3
                      "%ld; Total removed clients: %ld; Total renewed clients: "
41a6c3
                      "%ld", num_removed,
41a6c3
                      client_list->num_created - client_list->num_renewed,
41a6c3
                      client_list->num_removed, client_list->num_renewed);
41a6c3
-        entry = apr_rmm_addr_get(client_rmm, apr_rmm_malloc(client_rmm, sizeof(client_entry)));
41a6c3
+        entry = rmm_malloc(client_rmm, sizeof(client_entry));
41a6c3
         if (!entry) {
41a6c3
             ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01767)
41a6c3
                          "unable to allocate new auth_digest client");
41a6c3