From patchwork Thu Jan 20 18:11:21 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Janne Blomqvist X-Patchwork-Id: 79746 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id E6AE2B6F1E for ; Fri, 21 Jan 2011 05:11:30 +1100 (EST) Received: (qmail 29086 invoked by alias); 20 Jan 2011 18:11:29 -0000 Received: (qmail 29068 invoked by uid 22791); 20 Jan 2011 18:11:28 -0000 X-SWARE-Spam-Status: No, hits=-2.0 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_LOW, TW_CP, TW_PW, TW_TP, TW_WU X-Spam-Check-By: sourceware.org Received: from mail-iw0-f175.google.com (HELO mail-iw0-f175.google.com) (209.85.214.175) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 20 Jan 2011 18:11:23 +0000 Received: by iwn8 with SMTP id 8so858996iwn.20 for ; Thu, 20 Jan 2011 10:11:21 -0800 (PST) MIME-Version: 1.0 Received: by 10.231.10.200 with SMTP id q8mr2908159ibq.122.1295547081509; Thu, 20 Jan 2011 10:11:21 -0800 (PST) Received: by 10.231.160.68 with HTTP; Thu, 20 Jan 2011 10:11:21 -0800 (PST) Date: Thu, 20 Jan 2011 20:11:21 +0200 Message-ID: Subject: [Patch, libfortran] PR46267 strerror() might not be thread-safe From: Janne Blomqvist To: Fortran List , GCC Patches Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Hello, POSIX does not require strerror() to be thread-safe (although some implementations are), using it is thus a potential error in libgfortran. The attached patch fixes this in the case that strerror_r() is available; thanks to Jakub for the hint about __builtin_classify_type. Regtested on x86_64-unknown-linux-gnu, Ok for trunk? diff --git a/libgfortran/configure.ac b/libgfortran/configure.ac index 7b28f12..4f137e4 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 ccb5c3e..44873f9 100644 --- a/libgfortran/intrinsics/gerror.c +++ b/libgfortran/intrinsics/gerror.c @@ -45,14 +45,13 @@ PREFIX(gerror) (char * msg, gfc_charlen_type msg_len) memset (msg, ' ', msg_len); /* Blank the string. */ - p = strerror (errno); + p = gf_strerror (errno); if (p == NULL) return; p_len = strlen (p); if (msg_len < p_len) - memcpy (msg, p, msg_len); - else - memcpy (msg, p, p_len); + p_len = msg_len; + memcpy (msg, p, p_len); } #endif diff --git a/libgfortran/io/unix.c b/libgfortran/io/unix.c index fa64e20..b7eba0b 100644 --- a/libgfortran/io/unix.c +++ b/libgfortran/io/unix.c @@ -262,7 +262,7 @@ flush_if_preconnected (stream * s) const char * get_oserror (void) { - return strerror (errno); + return gf_strerror (errno); } diff --git a/libgfortran/libgfortran.h b/libgfortran/libgfortran.h index ac86492..d092a54 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 @@ -756,6 +757,9 @@ internal_proto(notify_std); extern notification notification_std(int); internal_proto(notification_std); +extern char *gf_strerror (int); +internal_proto(gf_strerror); + /* fpu.c */ extern void set_fpu (void); diff --git a/libgfortran/runtime/error.c b/libgfortran/runtime/error.c index 1baf9d3..a04f2c5 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() style function. */ + +char * +gf_strerror (int errnum) +{ +#ifdef HAVE_STRERROR_R +#define GF_STRERROR_R_MAXSZ 256 + static __thread char msg[GF_STRERROR_R_MAXSZ]; + /* 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, msg, 0)) == 5) + { + /* GNU strerror_r() */ + return strerror_r (errnum, msg, GF_STRERROR_R_MAXSZ); + } + else + { + /* POSIX strerror_r () */ + strerror_r (errnum, msg, GF_STRERROR_R_MAXSZ); + return msg; + } +#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 */