Another memory leak in PyDarshan
I've come across another memory leak while working with PyDarshan. I'm running the current `main` branch, compiled locally on Ubuntu 20.04, and using Python3.9.14

Running this code will slowly leak memory:
```python
def leak(report_file):
    with darshan.DarshanReport(report_file, read_all=True, lookup_name_records=True) as report:
        pass

for i in range(1_000_000):
    leak("sample.darshan")
```

Running this code without `read_all=True` doesn't leak anymore (as it was fixed in #811):
```python
def no_leak(report_file):
    with darshan.DarshanReport(report_file, read_all=False, lookup_name_records=True) as report:
        for row in report.mod_records('POSIX'):
            pass
```

The issue appears to occur with any darshan file, but here's a [sample](https://github.com/darshan-hpc/darshan/files/9568265/sample.darshan.zip) that is showing the leak.
diff --git a/darshan-util/darshan-logutils.c b/darshan-util/darshan-logutils.c
index 1b0c1d2d..41137bdd 100644
--- a/darshan-util/darshan-logutils.c
+++ b/darshan-util/darshan-logutils.c
@@ -2143,7 +2143,20 @@ void darshan_log_get_name_records(darshan_fd fd,
     HASH_ITER(hlink, name_hash, curr, tmp)
     {
         (*name_records)[i].id = curr->name_record->id;
-        (*name_records)[i].name = curr->name_record->name;
+        /* NOTE: darshan_log_get_namehash() call above returns a
+         * hash table that has allocated name record memory for records
+         * in the log file. This hash table is not exposed to callers,
+         * though, so it's this function's responsibility to destroy the
+         * table and free corresponding memory before returning, as is
+         * done below. This also requires that we strdup() record names
+         * that are returned to callers, who are then responsible for
+         * freeing this memory, just as they are responsible for freeing
+         * the name_records array allocated above.
+         */
+        (*name_records)[i].name = strdup(curr->name_record->name);
+        HASH_DELETE(hlink, name_hash, curr);
+        free(curr->name_record);
+        free(curr);
         i++;
     }
  
@@ -2183,7 +2196,20 @@ void darshan_log_get_filtered_name_records(darshan_fd fd,
     HASH_ITER(hlink, name_hash, curr, tmp)
     {
         (*name_records)[i].id = curr->name_record->id;
-        (*name_records)[i].name = curr->name_record->name;
+        /* NOTE: darshan_log_get_filtered_namehash() call above returns a
+         * hash table that has allocated name record memory for records
+         * in the log file. This hash table is not exposed to callers,
+         * though, so it's this function's responsibility to destroy the
+         * table and free corresponding memory before returning, as is
+         * done below. This also requires that we strdup() record names
+         * that are returned to callers, who are then responsible for
+         * freeing this memory, just as they are responsible for freeing
+         * the name_records array allocated above.
+         */
+        (*name_records)[i].name = strdup(curr->name_record->name);
+        HASH_DELETE(hlink, name_hash, curr);
+        free(curr->name_record);
+        free(curr);
         i++;
     }
  
diff --git a/darshan-util/pydarshan/darshan/backend/cffi_backend.py b/darshan-util/pydarshan/darshan/backend/cffi_backend.py
index d80f274a..fddb3167 100644
--- a/darshan-util/pydarshan/darshan/backend/cffi_backend.py
+++ b/darshan-util/pydarshan/darshan/backend/cffi_backend.py
@@ -242,7 +242,8 @@ def log_get_name_records(log):
 
     for i in range(0, cnt[0]):
         name_records[nrecs[0][i].id] = ffi.string(nrecs[0][i].name).decode("utf-8")
-
+        libdutil.darshan_free(nrecs[0][i].name)
+    libdutil.darshan_free(nrecs[0])
 
     # add to cache
     log['name_records'] = name_records
@@ -277,6 +278,8 @@ def log_lookup_name_records(log, ids=[]):
 
     for i in range(0, cnt[0]):
         name_records[nrecs[0][i].id] = ffi.string(nrecs[0][i].name).decode("utf-8")
+        libdutil.darshan_free(nrecs[0][i].name)
+    libdutil.darshan_free(nrecs[0])
 
     # add to cache
     log['name_records'] = name_records
['darshan-util/pydarshan/darshan/backend/cffi_backend.py', 'darshan-util/darshan-logutils.c']