From 723553bdc16695ecc686a2ffdff6d15bd600b676 Mon Sep 17 00:00:00 2001 From: Janne Blomqvist Date: Sat, 22 Jan 2011 00:42:17 +0200 Subject: [PATCH] PR 46267 strerror thread safety From-SVN: r169110 --- libgfortran/ChangeLog | 14 ++++++++++++++ libgfortran/config.h.in | 3 +++ libgfortran/configure | 2 +- libgfortran/configure.ac | 2 +- libgfortran/intrinsics/gerror.c | 21 +++++++++++---------- libgfortran/io/unix.c | 10 ---------- libgfortran/libgfortran.h | 9 +++++---- libgfortran/runtime/error.c | 42 ++++++++++++++++++++++++++++++++++++++--- 8 files changed, 74 insertions(+), 29 deletions(-) diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog index cab2d1501e0..6aa03e640ea 100644 --- a/libgfortran/ChangeLog +++ b/libgfortran/ChangeLog @@ -1,3 +1,17 @@ +2011-01-22 Janne Blomqvist + + PR libfortran/46267 + * config.h.in: Regenerated. + * configure: Regenerated. + * configure.ac: Check presence of strerror_r. + * intrinsics/gerror.c (gerror): Use gf_strerror, modify logic. + * io/unix.c (get_oserror): Remove. + * libgfortran.h (gf_strerror): Add prototype. + (get_oserror): Remove prototype. + * runtime/error.c (gf_strerror): New function. + (os_error): Use gf_strerror instead of get_oserror. + (generate_errror): Likewise. + 2011-01-17 Janne Blomqvist PR libfortran/47296 diff --git a/libgfortran/config.h.in b/libgfortran/config.h.in index bd6db109c63..c5a2d8a1dc1 100644 --- a/libgfortran/config.h.in +++ b/libgfortran/config.h.in @@ -708,6 +708,9 @@ /* Define to 1 if you have the `strerror' function. */ #undef HAVE_STRERROR +/* Define to 1 if you have the `strerror_r' function. */ +#undef HAVE_STRERROR_R + /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H diff --git a/libgfortran/configure b/libgfortran/configure index b8f0a7174a9..ec63cdb1e91 100755 --- a/libgfortran/configure +++ b/libgfortran/configure @@ -15636,7 +15636,7 @@ _ACEOF fi done -for ac_func in localtime_r gmtime_r +for ac_func in localtime_r gmtime_r strerror_r do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" diff --git a/libgfortran/configure.ac b/libgfortran/configure.ac index 7b28f127433..4f137e43253 100644 --- a/libgfortran/configure.ac +++ b/libgfortran/configure.ac @@ -249,7 +249,7 @@ AC_CHECK_FUNCS(chdir strerror getlogin gethostname kill link symlink perror) AC_CHECK_FUNCS(sleep time ttyname signal alarm ctime clock access fork execl) AC_CHECK_FUNCS(wait setmode execvp pipe dup2 close fdopen strcasestr getrlimit) AC_CHECK_FUNCS(gettimeofday stat fstat lstat getpwuid vsnprintf dup getcwd) -AC_CHECK_FUNCS(localtime_r gmtime_r) +AC_CHECK_FUNCS(localtime_r gmtime_r strerror_r) # Check for glibc backtrace functions AC_CHECK_FUNCS(backtrace backtrace_symbols) diff --git a/libgfortran/intrinsics/gerror.c b/libgfortran/intrinsics/gerror.c index ccb5c3efd41..6feadc9b7c7 100644 --- a/libgfortran/intrinsics/gerror.c +++ b/libgfortran/intrinsics/gerror.c @@ -43,16 +43,17 @@ PREFIX(gerror) (char * msg, gfc_charlen_type msg_len) int p_len; char *p; - memset (msg, ' ', msg_len); /* Blank the string. */ - - p = strerror (errno); - if (p == NULL) - return; - + p = gf_strerror (errno, msg, msg_len); p_len = strlen (p); - if (msg_len < p_len) - memcpy (msg, p, msg_len); - else - memcpy (msg, p, p_len); + /* The returned pointer p might or might not be the same as the msg + argument. */ + if (p != msg) + { + if (msg_len < p_len) + p_len = msg_len; + memcpy (msg, p, p_len); + } + if (msg_len > p_len) + memset (&msg[p_len], ' ', msg_len - p_len); } #endif diff --git a/libgfortran/io/unix.c b/libgfortran/io/unix.c index fa64e20b026..950b7a25b1f 100644 --- a/libgfortran/io/unix.c +++ b/libgfortran/io/unix.c @@ -256,16 +256,6 @@ flush_if_preconnected (stream * s) } -/* get_oserror()-- Get the most recent operating system error. For - * unix, this is errno. */ - -const char * -get_oserror (void) -{ - return strerror (errno); -} - - /******************************************************************** Raw I/O functions (read, write, seek, tell, truncate, close). diff --git a/libgfortran/libgfortran.h b/libgfortran/libgfortran.h index ac8649235ae..c9d3f371eab 100644 --- a/libgfortran/libgfortran.h +++ b/libgfortran/libgfortran.h @@ -1,5 +1,6 @@ /* Common declarations for all of libgfortran. - Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 + Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, + 2011 Free Software Foundation, Inc. Contributed by Paul Brook , and Andy Vaught @@ -738,9 +739,6 @@ extern void internal_error (st_parameter_common *, const char *) __attribute__ ((noreturn)); internal_proto(internal_error); -extern const char *get_oserror (void); -internal_proto(get_oserror); - extern const char *translate_error (int); internal_proto(translate_error); @@ -756,6 +754,9 @@ internal_proto(notify_std); extern notification notification_std(int); internal_proto(notification_std); +extern char *gf_strerror (int, char *, size_t); +internal_proto(gf_strerror); + /* fpu.c */ extern void set_fpu (void); diff --git a/libgfortran/runtime/error.c b/libgfortran/runtime/error.c index 1baf9d35d1f..06c144ae153 100644 --- a/libgfortran/runtime/error.c +++ b/libgfortran/runtime/error.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2002, 2003, 2005, 2006, 2007, 2009, 2010 +/* Copyright (C) 2002, 2003, 2005, 2006, 2007, 2009, 2010, 2011 Free Software Foundation, Inc. Contributed by Andy Vaught @@ -141,6 +141,36 @@ gfc_xtoa (GFC_UINTEGER_LARGEST n, char *buffer, size_t len) return p; } + +/* Hopefully thread-safe wrapper for a strerror_r() style function. */ + +char * +gf_strerror (int errnum, + char * buf __attribute__((unused)), + size_t buflen __attribute__((unused))) +{ +#ifdef HAVE_STRERROR_R + /* TODO: How to prevent the compiler warning due to strerror_r of + the untaken branch having the wrong return type? */ + if (__builtin_classify_type (strerror_r (0, buf, 0)) == 5) + { + /* GNU strerror_r() */ + return strerror_r (errnum, buf, buflen); + } + else + { + /* POSIX strerror_r () */ + strerror_r (errnum, buf, buflen); + return buf; + } +#else + /* strerror () is not necessarily thread-safe, but should at least + be available everywhere. */ + return strerror (errnum); +#endif +} + + /* show_locus()-- Print a line number and filename describing where * something went wrong */ @@ -192,6 +222,8 @@ recursion_check (void) } +#define STRERR_MAXSZ 256 + /* os_error()-- Operating system error. We get a message from the * operating system, show it and leave. Some operating system errors * are caught and processed by the library. If not, we come here. */ @@ -199,8 +231,10 @@ recursion_check (void) void os_error (const char *message) { + char errmsg[STRERR_MAXSZ]; recursion_check (); - st_printf ("Operating system error: %s\n%s\n", get_oserror (), message); + st_printf ("Operating system error: %s\n%s\n", + gf_strerror (errno, errmsg, STRERR_MAXSZ), message); sys_exit (1); } iexport(os_error); @@ -389,6 +423,7 @@ translate_error (int code) void generate_error (st_parameter_common *cmp, int family, const char *message) { + char errmsg[STRERR_MAXSZ]; /* If there was a previous error, don't mask it with another error message, EOF or EOR condition. */ @@ -402,7 +437,8 @@ generate_error (st_parameter_common *cmp, int family, const char *message) if (message == NULL) message = - (family == LIBERROR_OS) ? get_oserror () : translate_error (family); + (family == LIBERROR_OS) ? gf_strerror (errno, errmsg, STRERR_MAXSZ) : + translate_error (family); if (cmp->flags & IOPARM_HAS_IOMSG) cf_strcpy (cmp->iomsg, cmp->iomsg_len, message); -- 2.11.4.GIT