Error cleaning up after H5get_class_name() in HDF5 1.10.2-snap10

I’m not sure what I’m doing wrong, because I thought I was following the rules, but the following small program fails with a segfault:

#include "hdf5.h"

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc __attribute__((unused)), char **argv __attribute__((unused)))
{
  /* Create a new property list. */
  hid_t const fprop = H5Pcreate(H5P_FILE_ACCESS);
  assert(fprop > 0);
  hid_t const classID = H5Pget_class(fprop);
  assert(classID > 0);
  char * buf = H5Pget_class_name(classID);
  assert(buf != NULL);
  printf("%s\n", buf);
  free(buf);
  H5Pclose(fprop);
  return 0;
}

The reference manual clearly states, " The pointer to the name must be freed by the user after each successful call."

Running under the debugger, I get a backtrace which indicates the segfault was caused by the call to free(); if I run with valgrind, I get the following complaint:

==60068== Invalid free() / delete / delete[] / realloc()
==60068==    at 0x4C2ACDD: free (vg_replace_malloc.c:530)
==60068==    by 0x400B35: main (test-get_class_name.c:24)
==60068==  Address 0x75a1b00 is 48 bytes inside a block of size 68 alloc'd
==60068==    at 0x4C29BE3: malloc (vg_replace_malloc.c:299)
==60068==    by 0x5177DCE: H5MM_malloc (H5MM.c:292)
==60068==    by 0x51782F0: H5MM_xstrdup (H5MM.c:465)
==60068==    by 0x525C982: H5P_get_class_name (H5Pint.c:5033)
==60068==    by 0x51FDEF7: H5Pget_class_name (H5P.c:1574)
==60068==    by 0x400AF9: main (test-get_class_name.c:21)
==60068== 
==60068== 
==60068== Process terminating with default action of signal 6 (SIGABRT)
==60068==    at 0x5F281F7: raise (in /usr/lib64/libc-2.17.so)
==60068==    by 0x5F298E7: abort (in /usr/lib64/libc-2.17.so)
==60068==    by 0x5F21265: __assert_fail_base (in /usr/lib64/libc-2.17.so)
==60068==    by 0x5F21311: __assert_fail (in /usr/lib64/libc-2.17.so)
==60068==    by 0x5177BFA: H5MM_final_sanity_check (H5MM.c:232)
==60068==    by 0x4E7CF66: H5_term_library (H5.c:403)
==60068==    by 0x5F2BA68: __run_exit_handlers (in /usr/lib64/libc-2.17.so)
==60068==    by 0x5F2BAB4: exit (in /usr/lib64/libc-2.17.so)
==60068==    by 0x5F14C0B: (below main) (in /usr/lib64/libc-2.17.so)

There seem to be three possibilities:

  1. The HDF5 code and documentation are correct, but I’m doing something wrong and/or interpreting the documentation incorrectly.
  2. The HDF5 code is correct, but the documentation is wrong and I should not free the buffer.
  3. The documentation is correct and I should free the buffer, but the HDF5 code is incorrect.

Note that removal of the free() call results in an abort() with the following complaint:

test-get_class_name: /home/greenc/work/cet-is/test-products/hdf5/v1_10_2_snap10/source/hdf5-1.10.2-snap10/src/H5MM.c:232: H5MM_final_sanity_check: Assertion `0 == H5MM_curr_alloc_bytes_s' failed.

Help!

It appears, based on experimentation, that the actual problem is:

  1. Documentation is misleading: despite saying “must be freed by the user,” one must actually call the HDF5 function H5free_memory().

Assuming that this is the correct explanation, can I request that the reference documentation is updated to include an explicit reference to H5free_memory(), instead of leaving the insufficiently hard-bitten user to wrongly infer that they should use the more usual C library function free()?

You need to use HDF5 free instead of free.

I am not sure if H5free_memory() is defined in H5private.h now or not. In HDF5-1.8.11 version, it is defined in H5private.h which is not right as I thought.

Haiying

In the sources I currently have access to:

[greenc@woof] ~/tmp/t2 $ ack -l '^H5_DLL herr_t H5free' hdf5
hdf5/v1_8_16/Linux64bit+2.6-2.12-e10-zlib/include/H5public.h
hdf5/v1_10_0/Linux64bit+2.6-2.12-e10-nofcpp-prof/include/H5public.h
hdf5/v1_10_1/Linux64bit+2.6-2.12-e14-mpich-prof/include/H5public.h
hdf5/v1_10_2_snap10/Linux64bit+3.10-2.17-e17-mpich-debug/include/H5public.h

Best,
Chris.

H5free_memory() is the right way to free memory that the HDF5 library allocates and returns to the application.

Quincey

H5free_memory() is a public API call that was added several years ago. It ensures that the free() call matches the HDF5 library’s re/m/calloc() call. This is mainly of interest to Windows users since the C runtime (CRT) resides in a non-OS, Visual-Studio-specific shared library and i’s very easy to get a mismatch. For example, if you use a release build of the HDF5 library and are building a debug application, the CRTs won’t match and you’ll get memory issues. Ditto if you use a version of HDF5 that was built with Visual Studio 2015 but are building your application with a different version. Unix-y systems generally don’t have this problem unless you are using a specialized memory library.

Note that this is only important when freeing memory that the HDF5 library allocated. Very few HDF5 API calls do this.

Thanks for this, Dana. It appears that in (at least) 1.10.2-snap10, there’s a problem in Linux because for H5Pget_class_name()HDF5 allocates a block of memory with (presumably) malloc() and then hands the user a pointer into the middle of it. An attempt to use free() triggers the checking mechanisms to be found in modern glibc.
My request would be for a tweak to the reference documentation of get_class_name() (and any other user-callable function which returns memory the user must clean up) to state explicitly that it should be cleaned up using H5free_memory() rather than free().