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