From 563a8dd1401c2f3c04b897f2a727d7d6ac9b141f Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Sun, 23 Jan 2005 22:26:37 -0500 Subject: [svn-r9861] Purpose: Bug fix Description: Add detect vasprintf() routine and use it instead of vsnprintf() when formatting error descriptions if it's available. Added configure test to detect "broken" vsnprintf() implementations which don't return the correct number of character for strings that are too long to fit into the buffer provided (currently a problem on the SGIs and probably the HP). Re-wrote error formatting code in H5Epush_stack() to handle broken vsnprintf() implementations, etc. Platforms tested: IRIX64 6.5 (modi4) h5committest --- configure | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++++- configure.in | 46 +++++++++++++++- src/H5E.c | 18 ++++++- src/H5config.h.in | 7 +++ src/H5private.h | 1 + 5 files changed, 222 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 5525439..bc4a442 100755 --- a/configure +++ b/configure @@ -30855,7 +30855,7 @@ done -for ac_func in signal snprintf vsnprintf strdup system waitpid +for ac_func in signal snprintf vasprintf strdup system waitpid do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 @@ -30931,6 +30931,157 @@ fi done + +for ac_func in vsnprintf +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. */ +#include +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +char (*f) (); + +#ifdef F77_DUMMY_MAIN +# ifdef __cplusplus + extern "C" +# endif + int F77_DUMMY_MAIN() { return 1; } +#endif +int +main () +{ +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +f = $ac_func; +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +eval "$as_ac_var=no" +fi +rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + echo "$as_me:$LINENO: checking if vsnprintf returns correct value" >&5 +echo $ECHO_N "checking if vsnprintf returns correct value... $ECHO_C" >&6 + + if test "${hdf5_cv_vsnprintf_works+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then + { { echo "$as_me:$LINENO: error: cannot run test program while cross compiling" >&5 +echo "$as_me: error: cannot run test program while cross compiling" >&2;} + { (exit 1); exit 1; }; } +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +#include "confdefs.h" + +#include +#include +#include + +int test_vsnprintf(const char *fmt,...) +{ + va_list ap; + char *s = malloc(16); + int ret; + + va_start(ap, fmt); + ret=vsnprintf(s,16,"%s",ap); + va_end(ap); + + return(ret==15 ? 1 : 0); +} + +int main(void) +{ + exit(test_vsnprintf("%s","A string that is longer than 16 characters")); +} + +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + hdf5_cv_vsnprintf_works=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +cat conftest.$ac_ext >&5 +( exit $ac_status ) +hdf5_cv_vsnprintf_works=no +fi +rm -f core core.* *.core conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi + + + if test ${hdf5_cv_vsnprintf_works} = "yes"; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define VSNPRINTF_WORKS 1 +_ACEOF + + else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + fi + +fi +done + + echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 if test "${ac_cv_prog_cc_stdc+set}" = set; then diff --git a/configure.in b/configure.in index 0725202..09ae750 100644 --- a/configure.in +++ b/configure.in @@ -1644,7 +1644,51 @@ dnl Check for functions. dnl AC_CHECK_FUNCS(fork frexpf frexpl gethostname getpwuid getrusage) AC_CHECK_FUNCS(BSDgettimeofday longjmp setsysinfo sigaction) -AC_CHECK_FUNCS(signal snprintf vsnprintf strdup system waitpid) +AC_CHECK_FUNCS(signal snprintf vasprintf strdup system waitpid) + +dnl Check for vsnprintf() separately, so we can detect situations where it +dnl doesn't return the correct size for formatted strings that are too large +dnl for the buffer provided +AC_CHECK_FUNCS(vsnprintf, + + dnl Check if vsnprintf() returns correct size for strings that don't fit + dnl into the size allowed. If vsnprintf() works correctly on this platform, + dnl it should return a value larger than 15 for the test below + AC_MSG_CHECKING([if vsnprintf returns correct value]) + + AC_CACHE_VAL([hdf5_cv_vsnprintf_works], + AC_TRY_RUN([ +#include +#include +#include + +int test_vsnprintf(const char *fmt,...) +{ + va_list ap; + char *s = malloc(16); + int ret; + + va_start(ap, fmt); + ret=vsnprintf(s,16,"%s",ap); + va_end(ap); + + return(ret==15 ? 1 : 0); +} + +int main(void) +{ + exit(test_vsnprintf("%s","A string that is longer than 16 characters")); +} + ],[hdf5_cv_vsnprintf_works=yes],[hdf5_cv_vsnprintf_works=no],)) + + if test ${hdf5_cv_vsnprintf_works} = "yes"; then + AC_MSG_RESULT([yes]) + AC_DEFINE([VSNPRINTF_WORKS], [1], + [Define if vsnprintf() returns the correct value for formatted strings that don't fit into size allowed]) + else + AC_MSG_RESULT([no]) + fi + ,) dnl ---------------------------------------------------------------------- dnl Check compiler characteristics diff --git a/src/H5E.c b/src/H5E.c index f55a92b..31d212f 100644 --- a/src/H5E.c +++ b/src/H5E.c @@ -1513,13 +1513,24 @@ H5Epush_stack(hid_t err_stack, const char *file, const char *func, unsigned line /* Format the description */ va_start(ap, fmt); +#ifdef H5_HAVE_VASPRINTF + /* Use the vasprintf() routine, since it does what we're trying to do below */ + if(HDvasprintf(&tmp,fmt,ap)<0) + HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") +#else /* H5_HAVE_VASPRINTF */ /* Allocate space for the formatted description buffer */ tmp_len=128; if((tmp=H5MM_malloc((size_t)tmp_len))==NULL) HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") /* If the description doesn't fit into the initial buffer size, allocate more space and try again */ - while((desc_len=HDvsnprintf(tmp, (size_t)tmp_len, fmt, ap))>tmp_len) { + while((desc_len=HDvsnprintf(tmp, (size_t)tmp_len, fmt, ap)) +#ifdef H5_VSNPRINTF_WORKS + > +#else /* H5_VSNPRINTF_WORKS */ + >= +#endif /* H5_VSNPRINTF_WORKS */ + (tmp_len-1)) { /* shutdown & restart the va_list */ va_end(ap); va_start(ap, fmt); @@ -1528,10 +1539,15 @@ H5Epush_stack(hid_t err_stack, const char *file, const char *func, unsigned line H5MM_xfree(tmp); /* Allocate a description of the appropriate length */ +#ifdef H5_VSNPRINTF_WORKS tmp_len = desc_len+1; +#else /* H5_VSNPRINTF_WORKS */ + tmp_len = 2 * desc_len; +#endif /* H5_VSNPRINTF_WORKS */ if((tmp=H5MM_malloc((size_t)tmp_len))==NULL) HGOTO_ERROR (H5E_RESOURCE, H5E_NOSPACE, FAIL, "memory allocation failed") } /* end while */ +#endif /* H5_HAVE_VASPRINTF */ va_end(ap); diff --git a/src/H5config.h.in b/src/H5config.h.in index 6edc4fd..ab57f34 100644 --- a/src/H5config.h.in +++ b/src/H5config.h.in @@ -366,6 +366,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H +/* Define to 1 if you have the `vasprintf' function. */ +#undef HAVE_VASPRINTF + /* Define to 1 if you have the `vsnprintf' function. */ #undef HAVE_VSNPRINTF @@ -553,6 +556,10 @@ correct precision. */ #undef ULLONG_TO_LDOUBLE_PRECISION_WORKS +/* Define if vsnprintf() returns the correct value for formatted strings that + don't fit into size allowed */ +#undef VSNPRINTF_WORKS + /* Define if the HDF5 v1.6 compatibility functions are to be compiled in */ #undef WANT_H5_V1_6_COMPAT diff --git a/src/H5private.h b/src/H5private.h index fe4cbaa..95694c6 100644 --- a/src/H5private.h +++ b/src/H5private.h @@ -838,6 +838,7 @@ H5_DLL int64_t HDstrtoll (const char *s, const char **rest, int base); #define HDva_arg(A,T) va_arg(A,T) #define HDva_end(A) va_end(A) #define HDva_start(A,P) va_start(A,P) +#define HDvasprintf(RET,FMT,A) vasprintf(RET,FMT,A) #define HDvfprintf(F,FMT,A) vfprintf(F,FMT,A) #define HDvprintf(FMT,A) vprintf(FMT,A) #define HDvsprintf(S,FMT,A) vsprintf(S,FMT,A) -- cgit v0.12