From 52e401106794acc8ca9f654e8c9d22159f4e9bab Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Sun, 13 Jan 2008 00:38:40 -0500 Subject: [svn-r14403] Description: Add work-around to allow reading files that were produced with a buggy earlier version of the library, which could create objects with the wrong object header message count. There is now a configure flag "--enable-strict-format-checks" which triggers a failure on reading a file with this sort of corruption (when enabled) and allows the object to be read (when disabled). The default value for the "strict-format-checks" flag is yes when the "debug" flag is enabled and no when the "debug" flag is disabled. Note that if strict format checks are disabled (allowing objects with this particular kind of corruption to be read) and the file is opened with write access, the library will re-write the object header for the corrupt object with the correct # of object header messages. This closes bugzilla bug #1010. Tested on: Linux/32 2.6 (kagiso) FreeBSD/64 6.2 (liberty) --- MANIFEST | 1 + configure | 55 ++++++++++++++++++++++++++++++++++++++---- configure.in | 38 +++++++++++++++++++++++++++++ src/H5O.c | 4 ++-- src/H5Ocache.c | 21 ++++++++++++++--- src/H5Opkg.h | 1 + src/H5config.h.in | 3 +++ test/tbad_msg_count.h5 | Bin 0 -> 1984 bytes test/tmisc.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 176 insertions(+), 10 deletions(-) create mode 100644 test/tbad_msg_count.h5 diff --git a/MANIFEST b/MANIFEST index c992f64..a715e8f 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1391,6 +1391,7 @@ ./test/tarray.c ./test/tarrold.h5 ./test/tattr.c +./test/tbad_msg_count.h5 ./test/tbogus.h5 ./test/tconfig.c ./test/tcoords.c diff --git a/configure b/configure index 17f700b..002d856 100755 --- a/configure +++ b/configure @@ -882,6 +882,7 @@ CC_VERSION ROOT DYNAMIC_DIRS HL +STRICT_FORMAT_CHECKS SEARCH SETX LIBOBJS @@ -1512,6 +1513,9 @@ Optional Features: specify a comma-separated list of filters or the word no. The default is all internal I/O filters. --enable-hl Enable the high level library [default=yes] + --enable-strict-format-checks + Enable strict file format checks, default=yes if + debug flag is enabled, no otherwise Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -5289,7 +5293,7 @@ test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes case $host in *-*-irix6*) # Find out which ABI we are using. - echo '#line 5292 "configure"' > conftest.$ac_ext + echo '#line 5296 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -5846,7 +5850,7 @@ chmod -w . save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -o out/conftest2.$ac_objext" compiler_c_o=no -if { (eval echo configure:5849: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then +if { (eval echo configure:5853: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings if test -s out/conftest.err; then @@ -7721,7 +7725,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext < conftest.$ac_ext <&5 +echo $ECHO_N "checking Whether to perform strict file format checks... $ECHO_C" >&6; }; +# Check whether --enable-strict-format-checks was given. +if test "${enable_strict_format_checks+set}" = set; then + enableval=$enable_strict_format_checks; STRICT_CHECKS=$enableval +fi + + +if test "X-$STRICT_CHECKS" = X- ; then + if test -z "$DEBUG_PKG" ; then + STRICT_CHECKS=no + else + STRICT_CHECKS=yes + fi +fi + +case "X-$STRICT_CHECKS" in + X-yes) + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + STRICT_FORMAT_CHECKS=yes + +cat >>confdefs.h <<\_ACEOF +#define STRICT_FORMAT_CHECKS 1 +_ACEOF + + ;; + X-no|*) + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + STRICT_FORMAT_CHECKS=no + ;; +esac + + COMMENCE=config/commence CONCLUDE=config/conclude @@ -37201,13 +37242,14 @@ CC_VERSION!$CC_VERSION$ac_delim ROOT!$ROOT$ac_delim DYNAMIC_DIRS!$DYNAMIC_DIRS$ac_delim HL!$HL$ac_delim +STRICT_FORMAT_CHECKS!$STRICT_FORMAT_CHECKS$ac_delim SEARCH!$SEARCH$ac_delim SETX!$SETX$ac_delim LIBOBJS!$LIBOBJS$ac_delim LTLIBOBJS!$LTLIBOBJS$ac_delim _ACEOF - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 22; then + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 23; then break elif $ac_last_try; then { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 @@ -38000,6 +38042,9 @@ IF_YES_NO "$GASS" PRINT_N " GPFS" IF_YES_NO "$GPFS" +PRINT_N " Strict File Format Checks" +IF_ENABLED_DISABLED "$STRICT_FORMAT_CHECKS" + PRINT_N " HDF5 v1.4 Compatibility" IF_YES_NO "$HDF5_V1_4_COMPAT" diff --git a/configure.in b/configure.in index 43401ef..8014b90 100644 --- a/configure.in +++ b/configure.in @@ -2390,6 +2390,41 @@ else echo "no" fi + +dnl ---------------------------------------------------------------------- +dnl Enable strict file format checks +dnl +AC_SUBST([STRICT_FORMAT_CHECKS]) +AC_MSG_CHECKING([Whether to perform strict file format checks]); +AC_ARG_ENABLE([strict-format-checks], + [AC_HELP_STRING([--enable-strict-format-checks], + [Enable strict file format checks, default=yes if + debug flag is enabled, no otherwise])], + [STRICT_CHECKS=$enableval]) + +dnl Default to yes if debug is enabled +if test "X-$STRICT_CHECKS" = X- ; then + if test -z "$DEBUG_PKG" ; then + STRICT_CHECKS=no + else + STRICT_CHECKS=yes + fi +fi + +case "X-$STRICT_CHECKS" in + X-yes) + AC_MSG_RESULT([yes]) + STRICT_FORMAT_CHECKS=yes + AC_DEFINE([STRICT_FORMAT_CHECKS], [1], + [Define if strict file format checks are enabled]) + ;; + X-no|*) + AC_MSG_RESULT([no]) + STRICT_FORMAT_CHECKS=no + ;; +esac + + dnl ---------------------------------------------------------------------- dnl Build the Makefiles. Almost every Makefile.in will begin with the line dnl `@COMMENCE@' and end with the line `@CONCLUDE@'. These lines insert @@ -2672,6 +2707,9 @@ IF_YES_NO "$GASS" PRINT_N " GPFS" IF_YES_NO "$GPFS" +PRINT_N " Strict File Format Checks" +IF_ENABLED_DISABLED "$STRICT_FORMAT_CHECKS" + PRINT_N " HDF5 v1.4 Compatibility" IF_YES_NO "$HDF5_V1_4_COMPAT" diff --git a/src/H5O.c b/src/H5O.c index 764f2c4..b02ebbb 100644 --- a/src/H5O.c +++ b/src/H5O.c @@ -2175,7 +2175,7 @@ done: * *------------------------------------------------------------------------- */ -static herr_t +herr_t H5O_alloc_msgs(H5O_t *oh, size_t min_alloc) { size_t old_alloc; /* Old number of messages allocated */ @@ -2183,7 +2183,7 @@ H5O_alloc_msgs(H5O_t *oh, size_t min_alloc) H5O_mesg_t *new_mesg; /* Pointer to new message array */ herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_NOAPI_NOINIT(H5O_alloc_msgs) + FUNC_ENTER_NOAPI(H5O_alloc_msgs, FAIL) /* check args */ HDassert(oh); diff --git a/src/H5Ocache.c b/src/H5Ocache.c index 5e12fdc..c507a6a 100644 --- a/src/H5Ocache.c +++ b/src/H5Ocache.c @@ -312,9 +312,10 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1, oh->mesg[mesgno].dirty = TRUE; merged_null_msgs++; } else { - /* new message */ - if (oh->nmesgs >= nmesgs) - HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "corrupt object header - too many messages"); + /* Check if we need to extend message table to hold the new message */ + if(oh->nmesgs >= oh->alloc_nmesgs) + if(H5O_alloc_msgs(oh, (size_t)1) < 0) + HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "can't allocate more space for messages") mesgno = oh->nmesgs++; oh->mesg[mesgno].type = H5O_msg_class_g[id]; oh->mesg[mesgno].dirty = FALSE; @@ -346,9 +347,23 @@ H5O_load(H5F_t *f, hid_t dxpl_id, haddr_t addr, const void UNUSED * _udata1, if(merged_null_msgs) oh->cache_info.is_dirty = TRUE; +/* Don't check for the incorrect # of object header messages bug unless we've + * enabled strict format checking. This allows for older files, created with + * a version of the library that had a bug in tracking the correct # of header + * messages to be read in without the library fussing about things. -QAK + */ +#ifdef H5_STRICT_FORMAT_CHECKS /* Sanity check for the correct # of messages in object header */ if((oh->nmesgs + skipped_msgs + merged_null_msgs) != nmesgs) HGOTO_ERROR(H5E_OHDR, H5E_CANTLOAD, NULL, "corrupt object header - too few messages") +#else /* H5_STRICT_FORMAT_CHECKS */ + /* Check for incorrect # of messages in object header and if we have write + * access on the file, flag the object header as dirty, so it gets fixed. + */ + if((oh->nmesgs + skipped_msgs + merged_null_msgs) != nmesgs && + (H5F_get_intent(f) & H5F_ACC_RDWR)) + oh->cache_info.is_dirty = TRUE; +#endif /* H5_STRICT_FORMAT_CHECKS */ /* Set return value */ ret_value = oh; diff --git a/src/H5Opkg.h b/src/H5Opkg.h index 80bf320..43b06a7 100644 --- a/src/H5Opkg.h +++ b/src/H5Opkg.h @@ -204,6 +204,7 @@ H5_DLL herr_t H5O_free_mesg(H5O_mesg_t *mesg); H5_DLL void * H5O_read_real(const H5G_entry_t *ent, const H5O_msg_class_t *type, int sequence, void *mesg, hid_t dxpl_id); H5_DLL void * H5O_free_real(const H5O_msg_class_t *type, void *mesg); +H5_DLL herr_t H5O_alloc_msgs(H5O_t *oh, size_t min_alloc); /* Shared object operators */ H5_DLL void * H5O_shared_read(H5F_t *f, hid_t dxpl_id, H5O_shared_t *shared, diff --git a/src/H5config.h.in b/src/H5config.h.in index 56794cd..85456f5 100644 --- a/src/H5config.h.in +++ b/src/H5config.h.in @@ -505,6 +505,9 @@ /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS +/* Define if strict file format checks are enabled */ +#undef STRICT_FORMAT_CHECKS + /* Define if your system supports pthread_attr_setscope(&attribute, PTHREAD_SCOPE_SYSTEM) call. */ #undef SYSTEM_SCOPE_THREADS diff --git a/test/tbad_msg_count.h5 b/test/tbad_msg_count.h5 new file mode 100644 index 0000000..ca5eb65 Binary files /dev/null and b/test/tbad_msg_count.h5 differ diff --git a/test/tmisc.c b/test/tmisc.c index 88c9ea2..3e38b8f 100644 --- a/test/tmisc.c +++ b/test/tmisc.c @@ -279,6 +279,13 @@ unsigned m13_rdata[MISC13_DIM1][MISC13_DIM2]; /* Data read from dataset #define MISC25B_FILE "mergemsg.h5" #define MISC25B_GROUP "grp1" +/* Definitions for misc. test #27 */ +/* (Note that this test file is generated by the "gen_bad_ohdr.c" code in + * the 1.8 branch/trunk) + */ +#define MISC27_FILE "tbad_msg_count.h5" +#define MISC27_GROUP "Group" + /**************************************************************** ** ** test_misc1(): test unlinking a dataset from a group and immediately @@ -4186,6 +4193,60 @@ test_misc25b(void) CHECK(ret, FAIL, "H5Fclose"); } /* end test_misc25a() */ + +/**************************************************************** +** +** test_misc27(): Ensure that objects with incorrect # of object +** header messages are handled appropriately. +** +** (Note that this test file is generated by the "gen_bad_ohdr.c" code, +** in the 1.8 branch/trunk) +** +****************************************************************/ +static void +test_misc27(void) +{ + hid_t fid; /* File ID */ + hid_t gid; /* Group ID */ + char testfile[512]=""; /* Character buffer for corrected test file name */ + char *srcdir = HDgetenv("srcdir"); /* Pointer to the directory the source code is located within */ + herr_t ret; /* Generic return value */ + + /* Output message about test being performed */ + MESSAGE(5, ("Corrupt object header handling\n")); + + /* Generate the correct name for the test file, by prepending the source path */ + if(srcdir && ((HDstrlen(srcdir) + HDstrlen(MISC27_FILE) + 1) < sizeof(testfile))) { + HDstrcpy(testfile, srcdir); + HDstrcat(testfile, "/"); + } + HDstrcat(testfile, MISC27_FILE); + + /* Open the file */ + fid = H5Fopen(testfile, H5F_ACC_RDONLY, H5P_DEFAULT); + CHECK(fid, FAIL, "H5Fopen"); + +#ifdef H5_STRICT_FORMAT_CHECKS + /* Open group with incorrect # of object header messages (should fail) */ + H5E_BEGIN_TRY { + gid = H5Gopen(fid, MISC27_GROUP); + } H5E_END_TRY; + VERIFY(gid, FAIL, "H5Gopen"); +#else /* H5_STRICT_FORMAT_CHECKS */ + /* Open group with incorrect # of object header messages */ + gid = H5Gopen(fid, MISC27_GROUP); + CHECK(gid, FAIL, "H5Gopen"); + + /* Close group */ + ret = H5Gclose(gid); + CHECK(ret, FAIL, "H5Gclose"); +#endif /* H5_STRICT_FORMAT_CHECKS */ + + /* Close file */ + ret = H5Fclose(fid); + CHECK(ret, FAIL, "H5Fclose"); +} /* end test_misc27() */ + /**************************************************************** ** ** test_misc(): Main misc. test routine. @@ -4225,6 +4286,8 @@ test_misc(void) test_misc24(); /* Test inappropriate API opens of objects */ test_misc25a(); /* Exercise null object header message merge bug */ test_misc25b(); /* Exercise null object header message merge bug on existing file */ + /* misc. test #26 only in 1.8 branch/trunk */ + test_misc27(); /* Test opening file with object that has bad # of object header messages */ } /* test_misc() */ -- cgit v0.12