From 5b3223c7c569a3a20103c36ea8b38ae744033d2b Mon Sep 17 00:00:00 2001
From: Allen Byrne <byrn@hdfgroup.org>
Date: Wed, 9 Mar 2011 15:00:20 -0500
Subject: [svn-r20216] Valgrind fix for memory leak in h5tools_dump_xxx which
 is fixed by adding a new function; htri_t H5Tdetect_vlen_str(hid_t tid) to
 h5tools. This needs to be called before any H5Aread/H5Dread and if TRUE, then
 call vlen_reclaim function after the corresponding h5tools_dump_xxx().

Tested: local linux and valgrind
---
 tools/h5dump/h5dump.c | 25 +++++++++++++++++++++--
 tools/h5ls/h5ls.c     | 12 +++++++++++
 tools/lib/h5tools.c   | 56 +++++++++++++++++++++++++++++++++++++++++++++++++--
 tools/lib/h5tools.h   |  1 +
 4 files changed, 90 insertions(+), 4 deletions(-)

diff --git a/tools/h5dump/h5dump.c b/tools/h5dump/h5dump.c
index bebc892..cf02a47 100644
--- a/tools/h5dump/h5dump.c
+++ b/tools/h5dump/h5dump.c
@@ -2545,11 +2545,18 @@ dump_data(hid_t obj_id, int obj_data, struct subset_t *sset, int display_index)
             char        string_prefix[64];
             h5tool_format_t    string_dataformat;
 
+            /* VL data special information */
+            unsigned int        vl_data = 0; /* contains VL datatypes */
+
             type = H5Aget_type(obj_id);
             p_type = h5tools_get_native_type(type);
 
             ndims = H5Sget_simple_extent_dims(space, size, NULL);
 
+            /* Check if we have VL data in the dataset's datatype */
+            if (H5Tdetect_vlen_str(p_type) == TRUE)
+                vl_data = TRUE;
+
             for (i = 0; i < ndims; i++)
                 nelmts *= size[i];
 
@@ -2590,6 +2597,10 @@ dump_data(hid_t obj_id, int obj_data, struct subset_t *sset, int display_index)
             status = h5tools_dump_mem(stdout, outputformat, obj_id, p_type,
                                     space, buf, depth);
 
+            /* Reclaim any VL memory, if necessary */
+            if (vl_data)
+                H5Dvlen_reclaim(p_type, space, H5P_DEFAULT, buf);
+
             free(buf);
             H5Tclose(p_type);
             H5Tclose(type);
@@ -5502,10 +5513,16 @@ xml_dump_data(hid_t obj_id, int obj_data, struct subset_t UNUSED * sset, int UNU
             H5Tclose(type);
         } else if (H5Tget_class(type) == H5T_STRING) {
             status = xml_print_strs(obj_id, ATTRIBUTE_DATA);
-        } else {
-            /* all other data */
+        } else {  /* all other data */
+            /* VL data special information */
+            unsigned int vl_data = 0; /* contains VL datatypes */
+            
             p_type = h5tools_get_native_type(type);
 
+            /* Check if we have VL data in the dataset's datatype */
+            if (H5Tdetect_vlen_str(p_type) == TRUE)
+                vl_data = TRUE;
+
             H5Tclose(type);
 
             space = H5Aget_space(obj_id);
@@ -5522,6 +5539,10 @@ xml_dump_data(hid_t obj_id, int obj_data, struct subset_t UNUSED * sset, int UNU
                 status = h5tools_dump_mem(stdout, outputformat, obj_id,
                                               p_type, space, buf, depth);
 
+            /* Reclaim any VL memory, if necessary */
+            if (vl_data)
+                H5Dvlen_reclaim(p_type, space, H5P_DEFAULT, buf);
+
             free(buf);
             H5Tclose(p_type);
             H5Sclose(space);
diff --git a/tools/h5ls/h5ls.c b/tools/h5ls/h5ls.c
index 420ff3f..d2233ce 100644
--- a/tools/h5ls/h5ls.c
+++ b/tools/h5ls/h5ls.c
@@ -1449,6 +1449,13 @@ list_attr(hid_t obj, const char *attr_name, const H5A_info_t UNUSED *ainfo,
            p_type = h5tools_get_native_type(type);
 
         if(p_type >= 0) {
+            /* VL data special information */
+            unsigned int        vl_data = 0; /* contains VL datatypes */
+
+            /* Check if we have VL data in the dataset's datatype */
+            if (H5Tdetect_vlen_str(p_type) == TRUE)
+                vl_data = TRUE;
+
             temp_need= nelmts * MAX(H5Tget_size(type), H5Tget_size(p_type));
             assert(temp_need == (hsize_t)((size_t)temp_need));
             need = (size_t)temp_need;
@@ -1456,6 +1463,11 @@ list_attr(hid_t obj, const char *attr_name, const H5A_info_t UNUSED *ainfo,
             assert(buf);
             if(H5Aread(attr, p_type, buf) >= 0)
                h5tools_dump_mem(stdout, &info, attr, p_type, space, buf, -1);
+
+            /* Reclaim any VL memory, if necessary */
+            if (vl_data)
+                H5Dvlen_reclaim(p_type, space, H5P_DEFAULT, buf);
+
             free(buf);
             H5Tclose(p_type);
         } /* end if */
diff --git a/tools/lib/h5tools.c b/tools/lib/h5tools.c
index 00040ad..0286bea 100644
--- a/tools/lib/h5tools.c
+++ b/tools/lib/h5tools.c
@@ -622,6 +622,47 @@ h5tools_ncols(const char *s)
 }
 
 /*-------------------------------------------------------------------------
+ * Function: H5Tdetect_vlen_str
+ *
+ * Purpose: Recursive check for variable length string of a datatype.
+ *
+ * Return: TRUE if type conatains a variable string type, else FALSE
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5Tdetect_vlen_str(hid_t tid)
+{
+    int n = 0;
+    htri_t has_vlen_str = FALSE;
+    H5T_class_t tclass = -1;
+
+    if (H5Tis_variable_str(tid) == TRUE)
+        return TRUE;
+
+    tclass = H5Tget_class(tid);
+    if (tclass == H5T_ARRAY) {
+        hid_t btid = H5Tget_super(tid);
+        has_vlen_str = H5Tdetect_vlen_str(btid);
+        H5Tclose(btid);
+        return has_vlen_str;
+    }
+    else if (tclass == H5T_COMPOUND) {
+        n = H5Tget_nmembers(tid);
+        for (int i = 0; i < n; i++) {
+            hid_t mtid = H5Tget_member_type(tid, i);
+            has_vlen_str = H5Tdetect_vlen_str(mtid);
+            if (has_vlen_str == TRUE) {
+                H5Tclose(mtid);
+                return TRUE;
+            }
+            H5Tclose(mtid);
+        }
+    }
+    return FALSE;
+}
+
+/*-------------------------------------------------------------------------
  * Audience:    Public
  * Chapter:     H5Tools Library
  * Purpose:     Emit a simple prefix to STREAM.
@@ -1976,6 +2017,9 @@ h5tools_print_simple_subset(FILE *stream, const h5tool_format_t *info, h5tools_c
     hsize_t           size_row_block;          /* size for blocks along rows */
     hsize_t           row_counter = 0;
 
+    /* VL data special information */
+    unsigned int        vl_data = 0; /* contains VL datatypes */
+
     if ((size_t) ctx->ndims > NELMTS(sm_size))
         H5E_THROW(FAIL, H5E_tools_min_id_g, "ndims and sm_size comparision failed");
 
@@ -1984,6 +2028,10 @@ h5tools_print_simple_subset(FILE *stream, const h5tool_format_t *info, h5tools_c
 
     size_row_block = sset->block.data[row_dim];
 
+    /* Check if we have VL data in the dataset's datatype */
+    if (H5Tdetect_vlen_str(p_type) == TRUE)
+        vl_data = TRUE;
+
     /* display loop */
     for (; hyperslab_count > 0; temp_start[row_dim] += temp_stride[row_dim], hyperslab_count--) {
         /* jump rows if size of block exceeded
@@ -2067,6 +2115,10 @@ h5tools_print_simple_subset(FILE *stream, const h5tool_format_t *info, h5tools_c
 
             h5tools_dump_simple_data(stream, info, dset, ctx, flags, sm_nelmts, p_type, sm_buf);
 
+            /* Reclaim any VL memory, if necessary */
+            if (vl_data)
+                H5Dvlen_reclaim(p_type, sm_space, H5P_DEFAULT, sm_buf);
+
             if(H5Sclose(sm_space) < 0)
                 H5E_THROW(H5E_tools_g, H5E_tools_min_id_g, "H5Sclose failed");
             if(sm_buf)
@@ -2415,9 +2467,9 @@ h5tools_dump_simple_dset(FILE *stream, const h5tool_format_t *info,
     }
 
     /* Check if we have VL data in the dataset's datatype */
-    if (H5Tdetect_class(p_type, H5T_VLEN) == TRUE)
+    if (H5Tdetect_vlen_str(p_type) == TRUE)
         vl_data = TRUE;
-
+ 
     /*
      * Determine the strip mine size and allocate a buffer. The strip mine is
      * a hyperslab whose size is manageable.
diff --git a/tools/lib/h5tools.h b/tools/lib/h5tools.h
index b3e3dd2..9c100ea 100644
--- a/tools/lib/h5tools.h
+++ b/tools/lib/h5tools.h
@@ -553,6 +553,7 @@ H5TOOLS_DLL hid_t    h5tools_get_native_type(hid_t type);
 H5TOOLS_DLL hid_t    h5tools_get_little_endian_type(hid_t type);
 H5TOOLS_DLL hid_t    h5tools_get_big_endian_type(hid_t type);
 
+H5TOOLS_DLL htri_t   H5Tdetect_vlen_str(hid_t tid);
 
 H5TOOLS_DLL void     h5tools_dump_simple_data(FILE *stream, const h5tool_format_t *info, hid_t container,
                          h5tools_context_t *ctx/*in,out*/, unsigned flags,
-- 
cgit v0.12