After looking around Parrot and realizing that there were several other places where strerror is used, I'm trying a different approach. The attached patch adds config/gen/platform/generic/strerror.c, which contains a new function Parrot_strerror. This is just a wrapper to abstract away the non-reentrancy and platform-specific semantics of strerror. After a reconfigure, Parrot builds successfully and all tests pass on Ubuntu/x86.

I would like comments on whether the patch puts its code in the correct places and if it's a generally good idea. If both these are true, I'll go ahead testing on other platforms and converting other instances of strerror.

Christoph
Index: src/pmc/file.pmc
===================================================================
--- src/pmc/file.pmc	(revision 31046)
+++ src/pmc/file.pmc	(working copy)
@@ -22,9 +22,15 @@
 #  include <direct.h>
 #endif
 
+#define ERRBUF_SIZE 128
+
 #include "parrot/parrot.h"
 
-/* RT#46681 apparently, strerror_r is thread-safe and should be used instead.*/
+#  define THROW_FILE_EXCEPTION(interp)  \
+    { \
+        STRING *errstr = Parrot_strerror((interp), errno); \
+        Parrot_ex_throw_from_c_args((interp), NULL, EXCEPTION_LIBRARY_ERROR, "%Ss", errstr); \
+    }
 
 static PMC *File_PMC;
 pmclass File singleton {
@@ -73,9 +79,14 @@
 #endif
         string_cstring_free(cpath);
 
-        if (error)
+        if (error && errno == ENOENT) {
             RETURN(INTVAL 0);
+        }
+        else if (error) {
+            THROW_FILE_EXCEPTION(INTERP);
+        }
 
+
         RETURN(INTVAL 1);
     }
 
@@ -89,6 +100,7 @@
 
 */
 
+
     METHOD is_dir(STRING *path) {
         struct stat info;
         char *cpath = string_to_cstring(interp, path);
@@ -100,9 +112,7 @@
         string_cstring_free(cpath);
 
         if (error) {
-            char *errmsg = strerror(errno);
-            Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_EXTERNAL_ERROR,
-                errmsg);
+            THROW_FILE_EXCEPTION(INTERP);
         }
 
         if (S_ISDIR(info.st_mode))
@@ -132,9 +142,7 @@
         string_cstring_free(cpath);
 
         if (error) {
-            char *errmsg = strerror(errno);
-            Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_EXTERNAL_ERROR,
-                errmsg);
+            THROW_FILE_EXCEPTION(INTERP);
         }
 
         if (S_ISREG(info.st_mode))
@@ -155,20 +163,20 @@
 
     METHOD is_link(STRING *path) {
 #ifdef WIN32
-        /* I love win32 implementations */
+        /* I love win32. */
         RETURN(INTVAL 0);
 #else
         struct stat info;
+        char *cpath;
+        int error;
 
-        char *cpath = string_to_cstring(interp, path);
-        int error   = lstat(cpath, &info);
+        cpath = string_to_cstring(interp, path);
+        error = lstat(cpath, &info);
 
         string_cstring_free(cpath);
 
         if (error) {
-            char *errmsg = strerror(errno);
-            Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_EXTERNAL_ERROR,
-                errmsg);
+            THROW_FILE_EXCEPTION(INTERP);
         }
 
         if (S_ISLNK(info.st_mode))
@@ -197,11 +205,13 @@
     METHOD copy(STRING *from, STRING *to) {
 #define CHUNK_SIZE 1024
 
+        char errmsg[ERRBUF_SIZE];
         char *cfrom  = string_to_cstring(interp, from);
         FILE *source = fopen(cfrom, "rb");
 
         string_cstring_free(cfrom);
 
+
         if (source) {
             char *cto    = string_to_cstring(interp, to);
             FILE *target = fopen(cto, "w+b");
@@ -226,16 +236,12 @@
                 fclose(target);
             }
             else {
-                char *errmsg = strerror(errno);
-                Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_EXTERNAL_ERROR,
-                    errmsg);
+                THROW_FILE_EXCEPTION(INTERP);
             }
             fclose(source);
         }
         else {
-            char *errmsg = strerror(errno);
-            Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_EXTERNAL_ERROR,
-                errmsg);
+            THROW_FILE_EXCEPTION(INTERP);
         }
 #undef CHUNK_SIZE
     }
@@ -259,9 +265,7 @@
         string_cstring_free(cto);
 
         if (error) {
-            char *errmsg = strerror(errno);
-            Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_EXTERNAL_ERROR,
-                errmsg);
+            THROW_FILE_EXCEPTION(INTERP);
         }
     }
 }
Index: config/gen/platform/win32/string.h
===================================================================
--- config/gen/platform/win32/string.h	(revision 31046)
+++ config/gen/platform/win32/string.h	(working copy)
@@ -12,6 +12,8 @@
 #  if _MSC_VER >= 1400
 #    define strdup _strdup
 #  endif
+/* This is only useful with msvc.  gcc/mingw can use strerror_r. */
+#  define strerror_r(errnum, buf, buflen) strerror_s((buf), (buflen), (errnum))
 #endif
 
 #endif /* PARROT_PLATFORM_WIN32_STRING_H_GUARD */
Index: config/gen/platform/platform_interface.h
===================================================================
--- config/gen/platform/platform_interface.h	(revision 31046)
+++ config/gen/platform/platform_interface.h	(working copy)
@@ -14,6 +14,7 @@
 ** I/O:
 */
 
+
 /*
 ** Math:
 */
@@ -130,6 +131,7 @@
 void Parrot_Exec_OS_Command(Interp*, struct parrot_string_t *);
 INTVAL Parrot_Run_OS_Command_Argv(Interp*, struct PMC *);
 void Parrot_Exec_OS_Command_Argv(Interp*, struct PMC *);
+struct parrot_string_t *Parrot_strerror(Interp* , INTVAL errnum);
 
 #endif /* PARROT_PLATFORM_INTERFACE_H_GUARD */
 
Index: config/gen/platform/generic/strerror.c
===================================================================
--- config/gen/platform/generic/strerror.c	(revision 0)
+++ config/gen/platform/generic/strerror.c	(revision 0)
@@ -0,0 +1,85 @@
+/*
+ * $Id$
+ * Copyright (C) 2007-2008, The Perl Foundation.
+ */
+
+/*
+
+=head1 NAME
+
+config/gen/platform/generic/strerror.c
+
+=head1 DESCRIPTION
+
+error reporting stuff
+
+=head2 Function
+
+=over 4
+
+=cut
+
+*/
+
+
+/*
+
+=item C<STRING *
+Parrot_strerror(PARROT_INTERP, INTVAL)>
+
+Provide a wrapper around strerror_r which translates error numbers into error
+messages in Parrot STRINGs.
+
+=cut
+
+*/
+
+#define ERRBUF_SIZE 512
+
+PARROT_API
+STRING *
+Parrot_strerror(PARROT_INTERP, INTVAL errnum)
+{
+    STRING *errstr;
+#ifdef _GNU_SOURCE
+    /* GNU strerror_r DTRT for unknown error codes */
+    char buf[ERRBUF_SIZE];
+    char *errmsg = strerror_r(errno, buf, ERRBUF_SIZE);
+    errstr = string_printf(interp, "%s", errmsg);
+#else
+    /* use POSIXy strerror_r (*nix) or strerror_s macro (msvc)*/
+    char errmsg[ERRBUF_SIZE];
+    int err_status;
+    err_status = strerror_r(errno, errmsg, ERRBUF_SIZE);
+    /* Linux's POSIXy strerror_r returns -1 on error, others return an error code */
+    if (err_status == -1)
+        err_status = errno;
+
+    if (err_status == 0 || err_status == ERANGE) {
+        errstr = string_printf(interp, "%s", errmsg);
+    }
+    else if (err_status == EINVAL){
+        errstr = string_printf(interp, "unknown error message (%d)", errno);
+    }
+    else {
+        errstr = string_printf(interp,
+                "unknown error message from strerror_r (%d)", err_status);
+    }
+#endif
+    return errstr;
+}
+
+/*
+
+=back
+
+=cut
+
+*/
+
+/*
+ * Local variables:
+ *   c-file-style: "parrot"
+ * End:
+ * vim: expandtab shiftwidth=4:
+ */
Index: config/gen/platform.pm
===================================================================
--- config/gen/platform.pm	(revision 31046)
+++ config/gen/platform.pm	(working copy)
@@ -206,6 +206,7 @@
         math.c
         memalign.c
         signal.c
+        strerror.c
         itimer.c
         memexec.c
         exec.c

Reply via email to