C++ API: H5::FileAccPropList issue

H5::FileAccPropList copy constructor issue when using H5::FileAccPropList::DEFAULT

For some reason, we need to use the Core VFD to get memory-only HDF5 access. While playing with the C++ API, we found something strange in the H5::FileAccPropList(const FileAccPropList& original) constructor usage. The reference documentation states:

original - IN: FileAccPropList instance to copy

for the original parameter.

As a consequence, we had used this constructor with the H5::FileAccPropList::DEFAULT, thinking that we would have a sane copy to start with, modifying it afterward to fit our needs (use the Core VFD and so on).

Unfortunately, by using this constructor with H5::FileAccPropList::DEFAULT, our modifications on the FileAccPropList are in fact repercuted on the H5::FileAccPropList::DEFAULT global variable, making further implicit usage of this global variable unpredictable.

Here is a minimal use case of the issue (we assume here we have a table.h5 file around):

#include <iostream>
#include <fstream>
#include <stdexcept>

#include <H5Cpp.h>
int main(int argc, char** argv) {
  H5::Exception::dontPrint();

  std::ifstream is("./table.h5", std::ifstream::binary);
  if (is) {
    H5::H5File h5f;
    // get length of file:
    is.seekg(0, is.end);
    int length = is.tellg();
    is.seekg(0, is.beg);
    unsigned char* buffer = new unsigned char[length];
    is.read(reinterpret_cast<char*>(buffer), length);

    if (!is) {
      throw std::runtime_error("Failed to read table.h5 file!");
    }
    is.close();

    try {
      const H5::FileAccPropList fapl(H5::FileAccPropList::DEFAULT);
      std::cout << "Using H5::FileAccPropList fapl(H5::FileAccPropList::DEFAULT),\n"
                << "fapl will have the very same id than H5::FileAccPropList::DEFAULT:" << std::endl;
      std::cout << "fapl.getId() = " << fapl.getId() << std::endl;
      std::cout << "H5::FileAccPropList::DEFAULT.getId() = "
                << H5::FileAccPropList::DEFAULT.getId() << std::endl;
      fapl.setCore(10240, false);
      H5Pset_file_image(fapl.getId(), buffer, length);
      h5f.openFile("nonesuch", H5F_ACC_RDONLY, fapl);
    } catch (H5::Exception& err) {
      std::cerr << "Failed to load table.h5 file to a memory buffer and use it as a H5File\n";
    }
    delete[] buffer;
  }

  std::cout << "Thus, previous modifications on fapl will result in modification\n"
            << "on H5::FileAccPropList::DEFAULT and the next call to H5File ctor for which\n"
            << "we really want the default behavior will fail!!!" << std::endl;

  {
    try {
      H5::H5File h5f("./table.h5", H5F_ACC_RDONLY);
    } catch (H5::Exception& err) {

      std::cerr << std::string("HDF5 Error in ")
                              + err.getFuncName()
                              + ": "
                              + err.getDetailMsg();
    }
  }

  std::cout << "The solution is to use const H5::FileAccPropList fapl;\n"
            << "instead of const H5::FileAccPropList fapl(H5::FileAccPropList::DEFAULT);"
            << std::endl;

  return 0;
}

We figured out a solution by not using the H5::FileAccPropList::DEFAULT variable but we are not sure if this is an API issue or just a documentation problem, so we choose to share this here.

Another issue: FileAccPropList H5::H5File::getAccessPlist() returns a copy of the actual FileAccPropList

We discover another issue by investigating the first one.

Consider the following code

//--------------------------------------------------------------------------
// Function:    H5File::getAccessPlist
///\brief       Returns the access property list of this file
///\return      FileAccPropList object
///\exception   H5::FileIException
// Programmer   Binh-Minh Ribler - 2000
//--------------------------------------------------------------------------
FileAccPropList H5File::getAccessPlist() const
{
    hid_t access_plist_id = H5Fget_access_plist(id);
[...]

The documentation states that we’ll get the current access property list of the given file, but, when we use getId on the returned FileAccPropList we obtain an incremented hid_t!!!

Consulting the C source H5F.c, we find the following documentation block:

/*-------------------------------------------------------------------------
 * Function:	H5Fget_access_plist
 *
 * Purpose:	Returns a copy of the file access property list of the
 *		specified file.
 *
 *              NOTE: Make sure that, if you are going to overwrite
 *              information in the copied property list that was
 *              previously opened and assigned to the property list, then
 *              you must close it before overwriting the values.
 *
 * Return:	Success:	Object ID for a copy of the file access
 *				property list.
 *
 *		Failure:	FAIL
 *
 * Programmer:	Robb Matzke
 *              Wednesday, February 18, 1998
 *
 *-------------------------------------------------------------------------
 */

We don’t push further our investigations but the API doesn’t behave as expected, at least to our appreciation.

Let us know if this is the result of a misuse of the API or if we can help to adapt/fix the API or the associated documentation.

Best regards,
Renaud

Hi Renaud,

In issue #1, const H5::FileAccPropList fapl; should be used to make a default FileAccPropList
which can be used for specific settings. H5::FileAccPropList(const FileAccPropList& original) is a copy constructor, dealing with compilers making copies of objects. If you want to make a copy of an existing property
list, you can use c onst
H5::FileAccPropList fapl(original.getId()) or the member H5::FileAccPropList::copy.

In issue #2,
H5Fget_access_plist returns a copy of the original file access property list, thus the id is not the same as the original’s id.

Thank you,

Binh-Minh

Hi Binh-Minh and thank you for your responses,

Issue 1

Of course, we now use const H5::FileAccPropList fapl;.

What I find odd is that the copy constructor H5::FileAccPropList(const FileAccPropList& original), when used with H5::FileAccPropList::DEFAULT as in the following code:

      const H5::FileAccPropList fapl(H5::FileAccPropList::DEFAULT);
      const H5::FileAccPropList fapl2(H5::FileAccPropList::DEFAULT);
      const H5::FileAccPropList fapl3(H5::FileAccPropList::DEFAULT);

      std::cout << "fapl.getId() = " << fapl.getId() << std::endl;
      std::cout << "fapl2.getId() = " << fapl2.getId() << std::endl;
      std::cout << "fapl3.getId() = " << fapl3.getId() << std::endl;

doesn’t act as a copy constructor (the returned ids are the same, the one of the global H5::FileAccPropList::DEFAULT). My point is that it is unexpected and undocumented. Could you confirm that?

Maybe, for new users, it will be of use to document this or find a way to prevent them to make the same mistakes than me.

Issue 2

Exactly my point. As a consequence, the C++ API documentation is, at least, inaccurate:

Returns the access property list of this file

Isn’t it? My expectation, when using getFaccPropList will be to get the current FileAccPropList, not a copy, right!?

Could you confirm the documentation discrepancies?

Maybe this unexpected behavior can be fixed in the next release?

Renaud

Hi Renaud,

The document will be updated appropriately on both issues.

Thank you for your help,