[m-rev.] for review: Thread-safe alternative to strerror.

Peter Wang novalazy at gmail.com
Tue Jun 24 15:09:29 AEST 2014


Branches: master, 14.01

Add MR_strerror as a thread-safe alternative to strerror.
The current implementation wraps strerror_r(), strerror_s()
or sys_errlist as appropriate for the platform.  Bug #340.

configure.ac:
runtime/mercury_conf.h.in:
	Check for strerror_r, strerror_s.

	Delete irrelevant code in the sockets test for the external debugger.

runtime/mercury_runtime_util.c:
runtime/mercury_runtime_util.h:
	Add MR_strerror and use it.

library/io.m:
	Use MR_strerror.  In particular, mercury_output_error was not
	thread-safe.

	Pass errno to mercury_output_error explicitly for clarity.

	Delete req_lock parameter in ML_maybe_make_err_msg macro which is not
	needed any more.

compiler/prog_event.m:
runtime/mercury_deep_profiling.c:
runtime/mercury_misc.c:
runtime/mercury_term_size.c:
runtime/mercury_trace_base.c:
trace/mercury_trace_cmd_developer.c:
trace/mercury_trace_cmd_exp.c:
trace/mercury_trace_cmd_misc.c:
trace/mercury_trace_declarative.c:
trace/mercury_trace_external.c:
trace/mercury_trace_internal.c:
	Use MR_strerror.

compiler/notes/coding_standards.html:
	Update coding standard.

extras/net/sockets.m:
extras/net/tcp.m:
	Use MR_strerror.

NEWS:
	Announce change.

diff --git a/NEWS b/NEWS
index c5aacac..5b13316 100644
--- a/NEWS
+++ b/NEWS
@@ -15,6 +15,7 @@ This is a bug-fix release.
 * We have added workarounds for problems with (arguably broken)
   system headers on MinGW and MinGW64 systems.
 * The MinGW port now builds in the absence of POSIX threads library.
+* We now use thread-safe alternatives to strerror().
 
 Changes to the Mercury compiler:
 
diff --git a/compiler/notes/coding_standards.html b/compiler/notes/coding_standards.html
index 94ee830..752a924 100644
--- a/compiler/notes/coding_standards.html
+++ b/compiler/notes/coding_standards.html
@@ -174,7 +174,7 @@ Error messages from the runtime system should begin with the text
 
 If a system call or C library function that sets errno fails,
 the error message should be printed with perror()
-or should contain strerror(errno).
+or should contain MR_strerror(errno, errbuf, sizeof(errbuf)).
 If it was a function manipulating some file,
 the error message should include the filename.
 
diff --git a/compiler/prog_event.m b/compiler/prog_event.m
index 9546508..eb943de 100644
--- a/compiler/prog_event.m
+++ b/compiler/prog_event.m
@@ -185,6 +185,7 @@ read_specs_file_2(MR_AllocSiteInfoPtr alloc_id, MR_String specs_file_name,
 {
     int         spec_fd;
     MR_String   problem;
+    char        errbuf[MR_STRERROR_SIZE];
 
     /*
     ** There are race conditions between opening the file, stat'ing the file
@@ -195,7 +196,7 @@ read_specs_file_2(MR_AllocSiteInfoPtr alloc_id, MR_String specs_file_name,
     spec_fd = open(specs_file_name, O_RDONLY);
     if (spec_fd < 0) {
         problem = MR_make_string(alloc_id, ""could not open %s: %s"",
-            specs_file_name, strerror(errno));
+            specs_file_name, MR_strerror(errno, errbuf, sizeof(errbuf)));
     } else {
         problem = read_specs_file_3(alloc_id, specs_file_name,
             term_file_name, spec_fd);
@@ -256,11 +257,13 @@ read_specs_file_4(MR_AllocSiteInfoPtr alloc_id, MR_String specs_file_name,
                 specs_file_name);
         } else {
             FILE *term_fp;
+            char errbuf[MR_STRERROR_SIZE];
 
             term_fp = fopen(term_file_name, ""w"");
             if (term_fp == NULL) {
                 problem = MR_make_string(alloc_id, ""could not open %s: %s"",
-                    term_file_name, strerror(errno));
+                    term_file_name,
+                    MR_strerror(errno, errbuf, sizeof(errbuf)));
             } else {
                 MR_print_event_set(term_fp, event_set);
                 fclose(term_fp);
diff --git a/configure.ac b/configure.ac
index 720500a..dede274 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1285,7 +1285,8 @@ mercury_check_for_functions \
         sysconf getpagesize gethostname \
         mprotect memalign posix_memalign memmove \
         sigaction siginterrupt setitimer \
-        snprintf _snprintf vsnprintf _vsnprintf strerror \
+        snprintf _snprintf vsnprintf _vsnprintf \
+        strerror strerror_r strerror_s \
         open close dup dup2 fdopen fileno fstat stat lstat isatty \
         getpid setpgid fork execlp wait kill \
         grantpt unlockpt ptsname tcgetattr tcsetattr ioctl \
@@ -5107,37 +5108,17 @@ AC_TRY_LINK([
         */
 
         fd = socket(addr_family, SOCK_STREAM, 0);
-        if (fd < 0) {
-            fprintf(stderr, "Mercury runtime: socket() failed: %s\n",
-                strerror(errno));
-            fatal_error("cannot open socket for debugger");
-        } else if (MR_debug_socket) {
-            fprintf(stderr,"Mercury runtime: creation of socket ok\n");
-        }
 
         /*
         ** Connect to the socket
         */
-        if (connect(fd, addr, len) < 0) {
-            fprintf(stderr, "Mercury runtime: connect() failed: %s\n",
-                strerror(errno));
-            fatal_error("can't connect to debugger socket");
-        } else if (MR_debug_socket) {
-            fprintf(stderr, "Mercury runtime: connection to socket: ok\n");
-        }
+        connect(fd, addr, len);
 
         /*
         ** Convert the socket fd to a Mercury stream
         */
         file_in = fdopen(fd, "r");
         file_out = fdopen(fd, "w");
-        if ((file_in == NULL)||(file_out == NULL)) {
-            fprintf(stderr, "Mercury runtime: fdopen() failed: %s\n",
-                strerror(errno));
-            fatal_error("cannot open debugger socket");
-        } else if (MR_debug_socket) {
-            fprintf(stderr, "Mercury runtime: fdopen(): ok\n");
-        }
     }
     changequote([,])
 ],[mercury_cv_sockets_work=yes],[mercury_cv_sockets_work=no]))
diff --git a/extras/net/sockets.m b/extras/net/sockets.m
index 6d7acf1..5dc1ce8 100644
--- a/extras/net/sockets.m
+++ b/extras/net/sockets.m
@@ -293,12 +293,14 @@
     shutdown(Fd, 2);
 ").
 
-    % XXX thread safe?
 :- pragma foreign_proc("C",
     error_message(Err::out, _IO0::di, _IO::uo),
-    [will_not_call_mercury, promise_pure, tabled_for_io],
+    [will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
 "
-    MR_make_aligned_string_copy(Err, strerror(socket_errno));
+    char errbuf[MR_STRERROR_SIZE];
+
+    MR_make_aligned_string_copy(Err,
+        MR_strerror(socket_errno, errbuf, sizeof(errbuf)));
 ").
 
 %-----------------------------------------------------------------------------%
diff --git a/extras/net/tcp.m b/extras/net/tcp.m
index 4036526..567233c 100644
--- a/extras/net/tcp.m
+++ b/extras/net/tcp.m
@@ -624,8 +624,11 @@ socket_fd(Tcp) = socket_fd_c(Tcp ^ handle).
     tcp.get_error(Errno::in, Msg::out),
     [will_not_call_mercury, thread_safe, promise_pure],
 "
+    char errbuf[MR_STRERROR_SIZE];
+
     MR_save_transient_hp();
-    MR_make_aligned_string_copy(Msg, strerror(Errno));
+    MR_make_aligned_string_copy(Msg,
+        MR_strerror(Errno, errbuf, sizeof(errbuf)));
     MR_restore_transient_hp();
 ").
 
@@ -679,9 +682,12 @@ socket_fd(Tcp) = socket_fd_c(Tcp ^ handle).
 
 :- pragma foreign_proc("C",
     error_message(Errno::in) = (Err::out),
-    [promise_pure, will_not_call_mercury],
+    [promise_pure, will_not_call_mercury, thread_safe],
 "
-    MR_make_aligned_string_copy(Err, strerror(Errno));
+    char errbuf[MR_STRERROR_SIZE];
+
+    MR_make_aligned_string_copy(Err,
+        MR_strerror(Errno, errbuf, sizeof(errbuf)));
 ").
 
 :- pred throw_tcp_exception(string::in) is erroneous.
diff --git a/library/io.m b/library/io.m
index 501f1e7..7765dbb 100644
--- a/library/io.m
+++ b/library/io.m
@@ -2546,7 +2546,7 @@ io.check_err(Stream, Res, !IO) :-
     }
 
     ML_maybe_make_err_msg(RetVal != 0, errno, ""read failed: "",
-        MR_ALLOC_ID, MR_TRUE, RetStr);
+        MR_ALLOC_ID, RetStr);
 ").
 
 :- pragma foreign_proc("C#",
@@ -2626,10 +2626,10 @@ io.make_err_msg(Msg0, Msg, !IO) :-
 
 :- pragma foreign_proc("C",
     make_err_msg(Error::in, Msg0::in, Msg::out, _IO0::di, _IO::uo),
-    [will_not_call_mercury, promise_pure, tabled_for_io,
+    [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
         does_not_affect_liveness, no_sharing],
 "
-    ML_maybe_make_err_msg(MR_TRUE, Error, Msg0, MR_ALLOC_ID, MR_FALSE, Msg);
+    ML_maybe_make_err_msg(MR_TRUE, Error, Msg0, MR_ALLOC_ID, Msg);
 ").
 
 :- pragma foreign_proc("C#",
@@ -2849,7 +2849,7 @@ io.file_modification_time(File, Result, !IO) :-
         Status = 1;
     } else {
         ML_maybe_make_err_msg(MR_TRUE, errno, ""stat() failed: "",
-            MR_ALLOC_ID, MR_TRUE, Msg);
+            MR_ALLOC_ID, Msg);
         Status = 0;
         Time = 0;   /* Dummy value -- will not be used. */
     }
@@ -3948,7 +3948,7 @@ io.file_id(FileName, Result, !IO) :-
         Status = 1;
     } else {
         ML_maybe_make_err_msg(MR_TRUE, errno, ""stat() failed: "",
-            MR_ALLOC_ID, MR_TRUE, Msg);
+            MR_ALLOC_ID, Msg);
         Status = 0;
     }
 #else
@@ -5659,6 +5659,7 @@ io.get_io_output_stream_type(Type, !IO) :-
 #include ""mercury_file.h""
 #include ""mercury_heap.h""
 #include ""mercury_misc.h""
+#include ""mercury_runtime_util.h""
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -5703,7 +5704,7 @@ int             mercury_next_stream_id(void);
 MercuryFilePtr  mercury_open(const char *filename, const char *openmode,
                     MR_AllocSiteInfoPtr alloc_id);
 void            mercury_io_error(MercuryFilePtr mf, const char *format, ...);
-void            mercury_output_error(MercuryFilePtr mf);
+void            mercury_output_error(MercuryFilePtr mf, int errnum);
 void            mercury_print_string(MercuryFilePtr mf, const char *s);
 int             mercury_get_byte(MercuryFilePtr mf);
 void            mercury_close(MercuryFilePtr mf);
@@ -7069,10 +7070,12 @@ mercury_io_error(MercuryFilePtr mf, const char *format, ...)
 :- pragma foreign_code("C", "
 
 void
-mercury_output_error(MercuryFilePtr mf)
+mercury_output_error(MercuryFilePtr mf, int errnum)
 {
+    char errbuf[MR_STRERROR_SIZE];
+
     mercury_io_error(mf, ""error writing to output file: %s"",
-        strerror(errno));
+        MR_strerror(errnum, errbuf, sizeof(errbuf)));
 }
 
 ").
@@ -7083,7 +7086,7 @@ void
 mercury_print_string(MercuryFilePtr mf, const char *s)
 {
     if (ML_fprintf(mf, ""%s"", s) < 0) {
-        mercury_output_error(mf);
+        mercury_output_error(mf, errno);
     }
     while (*s) {
         if (*s++ == '\\n') {
@@ -7342,6 +7345,8 @@ static const MercuryFile MR_closed_stream = {
 void
 mercury_close(MercuryFilePtr mf)
 {
+    char errbuf[MR_STRERROR_SIZE];
+
     /*
     ** On some systems attempting to close a file stream that has been
     ** previously closed will lead to a segmentation fault.  We check
@@ -7353,7 +7358,8 @@ mercury_close(MercuryFilePtr mf)
     }
 
     if (MR_CLOSE(*mf) < 0) {
-        mercury_io_error(mf, ""error closing file: %s"", strerror(errno));
+        mercury_io_error(mf, ""error closing file: %s"",
+            MR_strerror(errno, errbuf, sizeof(errbuf)));
     }
 
 #ifdef MR_NEW_MERCURYFILE_STRUCT
@@ -7760,7 +7766,7 @@ io.putback_byte(binary_input_stream(Stream), Character, !IO) :-
     size_t  i;
     if (Character <= 0x7f) {
         if (MR_PUTCH(*out, Character) < 0) {
-            mercury_output_error(out);
+            mercury_output_error(out, errno);
         }
         if (Character == '\\n') {
             MR_line_number(*out)++;
@@ -7769,7 +7775,7 @@ io.putback_byte(binary_input_stream(Stream), Character, !IO) :-
         len = MR_utf8_encode(buf, Character);
         for (i = 0; i < len; i++) {
             if (MR_PUTCH(*out, buf[i]) < 0) {
-                mercury_output_error(out);
+                mercury_output_error(out, errno);
                 break;
             }
         }
@@ -7783,7 +7789,7 @@ io.putback_byte(binary_input_stream(Stream), Character, !IO) :-
 "
     MercuryFilePtr out = mercury_current_text_output();
     if (ML_fprintf(out, ""%"" MR_INTEGER_LENGTH_MODIFIER ""d"", Val) < 0) {
-        mercury_output_error(out);
+        mercury_output_error(out, errno);
     }
 ").
 
@@ -7798,7 +7804,7 @@ io.putback_byte(binary_input_stream(Stream), Character, !IO) :-
     MR_sprintf_float(buf, Val);
     out = mercury_current_text_output();
     if (ML_fprintf(out, ""%s"", buf) < 0) {
-        mercury_output_error(out);
+        mercury_output_error(out, errno);
     }
 ").
 
@@ -7811,7 +7817,7 @@ io.putback_byte(binary_input_stream(Stream), Character, !IO) :-
     if (MR_PUTCH(*mercury_current_binary_output(),
         (int) ((unsigned char) Byte)) < 0)
     {
-        mercury_output_error(mercury_current_text_output());
+        mercury_output_error(mercury_current_text_output(), errno);
     }
 ").
 
@@ -7830,7 +7836,7 @@ io.write_bitmap(Bitmap, Start, NumBytes, !IO) :-
 "
     MercuryFilePtr out = mercury_current_text_output();
     if (MR_FLUSH(*out) < 0) {
-        mercury_output_error(out);
+        mercury_output_error(out, errno);
     }
 ").
 
@@ -7841,7 +7847,7 @@ io.write_bitmap(Bitmap, Start, NumBytes, !IO) :-
 "
     MercuryFilePtr out = mercury_current_binary_output();
     if (MR_FLUSH(*out) < 0) {
-        mercury_output_error(out);
+        mercury_output_error(out, errno);
     }
 ").
 
@@ -8101,7 +8107,7 @@ io.write_char(output_stream(Stream), Character, !IO) :-
 "
     if (Character <= 0x7f) {
         if (MR_PUTCH(*Stream, Character) < 0) {
-            mercury_output_error(Stream);
+            mercury_output_error(Stream, errno);
         }
         if (Character == '\\n') {
             MR_line_number(*Stream)++;
@@ -8113,7 +8119,7 @@ io.write_char(output_stream(Stream), Character, !IO) :-
         len = MR_utf8_encode(buf, Character);
         for (i = 0; i < len; i++) {
             if (MR_PUTCH(*Stream, buf[i]) < 0) {
-                mercury_output_error(Stream);
+                mercury_output_error(Stream, errno);
                 break;
             }
         }
@@ -8130,7 +8136,7 @@ io.write_int(output_stream(Stream), Val, !IO) :-
         does_not_affect_liveness, no_sharing],
 "
     if (ML_fprintf(Stream, ""%"" MR_INTEGER_LENGTH_MODIFIER ""d"", Val) < 0) {
-        mercury_output_error(Stream);
+        mercury_output_error(Stream, errno);
     }
 ").
 
@@ -8146,7 +8152,7 @@ io.write_float(output_stream(Stream), Val, !IO) :-
     char buf[MR_SPRINTF_FLOAT_BUF_SIZE];
     MR_sprintf_float(buf, Val);
     if (ML_fprintf(Stream, ""%s"", buf) < 0) {
-        mercury_output_error(Stream);
+        mercury_output_error(Stream, errno);
     }
 ").
 
@@ -8161,7 +8167,7 @@ io.write_byte(binary_output_stream(Stream), Byte, !IO) :-
 "
     /* call putc with a strictly non-negative byte-sized integer */
     if (MR_PUTCH(*Stream, (int) ((unsigned char) Byte)) < 0) {
-        mercury_output_error(Stream);
+        mercury_output_error(Stream, errno);
     }
 ").
 
@@ -8221,7 +8227,7 @@ io.flush_output(output_stream(Stream), !IO) :-
         does_not_affect_liveness, no_sharing],
 "
     if (MR_FLUSH(*Stream) < 0) {
-        mercury_output_error(Stream);
+        mercury_output_error(Stream, errno);
     }
 ").
 
@@ -8235,7 +8241,7 @@ io.flush_binary_output(binary_output_stream(Stream), !IO) :-
         does_not_affect_liveness, no_sharing],
 "
     if (MR_FLUSH(*Stream) < 0) {
-        mercury_output_error(Stream);
+        mercury_output_error(Stream, errno);
     }
 ").
 
@@ -9694,7 +9700,7 @@ io.close_binary_output(binary_output_stream(Stream), !IO) :-
         Status = 127;
         ML_maybe_make_err_msg(MR_TRUE, errno,
             ""error invoking system command: "",
-            MR_ALLOC_ID, MR_TRUE, Msg);
+            MR_ALLOC_ID, Msg);
     } else {
         /* Wait for the spawned process to exit. */
         do {
@@ -9704,7 +9710,7 @@ io.close_binary_output(binary_output_stream(Stream), !IO) :-
             Status = 127;
             ML_maybe_make_err_msg(MR_TRUE, errno,
                 ""error invoking system command: "",
-                MR_ALLOC_ID, MR_TRUE, Msg);
+                MR_ALLOC_ID, Msg);
         } else {
             Status = st;
             Msg = MR_make_string_const("""");
@@ -9728,7 +9734,7 @@ io.close_binary_output(binary_output_stream(Stream), !IO) :-
         Status = 127;
         ML_maybe_make_err_msg(MR_TRUE, errno,
             ""error invoking system command: "",
-            MR_ALLOC_ID, MR_TRUE, Msg);
+            MR_ALLOC_ID, Msg);
     } else {
         Msg = MR_make_string_const("""");
     }
@@ -10267,7 +10273,7 @@ io.make_temp(Dir, Prefix, Name, !IO) :-
     if (fd == -1) {
         ML_maybe_make_err_msg(MR_TRUE, errno,
             ""error opening temporary file: "", MR_ALLOC_ID,
-            MR_TRUE, ErrorMessage);
+            ErrorMessage);
         Error = -1;
     } else {
         do {
@@ -10275,7 +10281,7 @@ io.make_temp(Dir, Prefix, Name, !IO) :-
         } while (err == -1 && MR_is_eintr(errno));
         ML_maybe_make_err_msg(err, errno,
             ""error closing temporary file: "", MR_ALLOC_ID,
-            MR_TRUE, ErrorMessage);
+            ErrorMessage);
         Error = err;
     }
 #else
@@ -10324,7 +10330,7 @@ io.make_temp(Dir, Prefix, Name, !IO) :-
     if (fd == -1) {
         ML_maybe_make_err_msg(MR_TRUE, errno,
             ""error opening temporary file: "", MR_ALLOC_ID,
-            MR_TRUE, ErrorMessage);
+            ErrorMessage);
         Error = -1;
     }  else {
         do {
@@ -10332,7 +10338,7 @@ io.make_temp(Dir, Prefix, Name, !IO) :-
         } while (err == -1 && MR_is_eintr(errno));
         ML_maybe_make_err_msg(err, errno,
             ""error closing temporary file: "", MR_ALLOC_ID,
-            MR_TRUE, ErrorMessage);
+            ErrorMessage);
         Error = err;
     }
 #endif
@@ -10488,11 +10494,9 @@ io.make_temp(Dir, Prefix, Name, !IO) :-
 #include <errno.h>
 
 /*
-** ML_maybe_make_err_msg(was_error, errno, msg, alloc_id, req_lock, error_msg):
-** if `was_error' is true, then append `msg' and `strerror(errno)'
+** ML_maybe_make_err_msg(was_error, errnum, msg, alloc_id, error_msg):
+** if `was_error' is true, then append `msg' and a message for errnum
 ** to give `error_msg'; otherwise, set `error_msg' to "".
-** `req_lock' must be true iff the caller is marked `thread_safe' as the
-** underlying strerror() function is not thread-safe.
 **
 ** WARNING: this must only be called when the `hp' register is valid.
 ** That means it must only be called from procedures declared
@@ -10503,18 +10507,15 @@ io.make_temp(Dir, Prefix, Name, !IO) :-
 ** invalidated by the function call.
 */
 
-#define ML_maybe_make_err_msg(was_error, error, msg, alloc_id, req_lock,   \\
-            error_msg)                                                     \\
+#define ML_maybe_make_err_msg(was_error, errnum, msg, alloc_id, error_msg) \\
     do {                                                                   \\
-        char    *errno_msg;                                                \\
+        char    errbuf[MR_STRERROR_SIZE];                                  \\
+        const char *errno_msg;                                             \\
         size_t  total_len;                                                 \\
         MR_Word tmp;                                                       \\
                                                                            \\
         if (was_error) {                                                   \\
-            if (req_lock) {                                                \\
-                MR_OBTAIN_GLOBAL_LOCK(""ML_maybe_make_err_msg"");          \\
-            }                                                              \\
-            errno_msg = strerror(error);                                   \\
+            errno_msg = MR_strerror(errnum, errbuf, sizeof(errbuf));       \\
             total_len = strlen(msg) + strlen(errno_msg);                   \\
             MR_offset_incr_hp_atomic_msg(tmp, 0,                           \\
                 (total_len + sizeof(MR_Word)) / sizeof(MR_Word),           \\
@@ -10522,9 +10523,6 @@ io.make_temp(Dir, Prefix, Name, !IO) :-
             (error_msg) = (char *) tmp;                                    \\
             strcpy((error_msg), msg);                                      \\
             strcat((error_msg), errno_msg);                                \\
-            if (req_lock) {                                                \\
-                MR_RELEASE_GLOBAL_LOCK(""ML_maybe_make_err_msg"");         \\
-            }                                                              \\
         } else {                                                           \\
             /*                                                             \\
             ** We can't just return NULL here, because otherwise mdb       \\
@@ -10625,7 +10623,7 @@ io.remove_file(FileName, Result, !IO) :-
     RetVal = remove(FileName);
 #endif
     ML_maybe_make_err_msg(RetVal != 0, errno, ""remove failed: "",
-        MR_ALLOC_ID, MR_TRUE, RetStr);
+        MR_ALLOC_ID, RetStr);
 ").
 
 :- pragma foreign_proc("C#",
@@ -10768,7 +10766,7 @@ io.rename_file(OldFileName, NewFileName, Result, IO0, IO) :-
     RetVal = rename(OldFileName, NewFileName);
 #endif
     ML_maybe_make_err_msg(RetVal != 0, errno, ""rename failed: "",
-        MR_ALLOC_ID, MR_TRUE, RetStr);
+        MR_ALLOC_ID, RetStr);
 ").
 
 :- pragma foreign_proc("C#",
diff --git a/runtime/mercury_conf.h.in b/runtime/mercury_conf.h.in
index d8b8560..d44ce45 100644
--- a/runtime/mercury_conf.h.in
+++ b/runtime/mercury_conf.h.in
@@ -241,6 +241,8 @@
 **	MR_HAVE_MEMALIGN    	we have the memalign() function.
 **	MR_HAVE_POSIX_MEMALIGN  we have the posix_memalign() function.
 **	MR_HAVE_STRERROR    	we have the strerror() function.
+**	MR_HAVE_STRERROR_R    	we have the strerror_r() function.
+**	MR_HAVE_STRERROR_S    	we have the strerror_s() function.
 **	MR_HAVE_SIGINTERRUPT	we have the siginterrupt() function.
 **	MR_HAVE_SETITIMER   	we have the setitimer() function.
 **	MR_HAVE_MEMMOVE   	we have the memmove() function.
@@ -314,6 +316,8 @@
 #undef	MR_HAVE_POSIX_MEMALIGN
 #undef	MR_HAVE_MPROTECT
 #undef	MR_HAVE_STRERROR
+#undef	MR_HAVE_STRERROR_R
+#undef	MR_HAVE_STRERROR_S
 #undef	MR_HAVE_SIGINTERRUPT
 #undef	MR_HAVE_SETITIMER
 #undef	MR_HAVE_MEMMOVE
diff --git a/runtime/mercury_deep_profiling.c b/runtime/mercury_deep_profiling.c
index 124e378..889a6c8 100644
--- a/runtime/mercury_deep_profiling.c
+++ b/runtime/mercury_deep_profiling.c
@@ -24,7 +24,7 @@
 #include "mercury_stack_layout.h"
 #include "mercury_timing.h"
 #include "mercury_prof_time.h"
-#include "mercury_runtime_util.h"   /* for strerror() on some systems */
+#include "mercury_runtime_util.h"
 #include "mercury_deep_profiling.h"
 #include "mercury_deep_profiling_hand.h"
 
@@ -387,6 +387,7 @@ MR_write_out_profiling_tree(void)
     int                     ticks_per_sec;
     unsigned                num_call_seqs;
     long                    table_sizes_offset;
+    char                    errbuf[MR_STRERROR_SIZE];
 
 #ifdef MR_DEEP_PROFILING_STATISTICS
     int                     i;
@@ -396,13 +397,15 @@ MR_write_out_profiling_tree(void)
     deep_fp = fopen(MR_MDPROF_DATA_FILENAME, "wb+");
     if (deep_fp == NULL) {
         MR_fatal_error("cannot open `%s' for writing: %s",
-            MR_MDPROF_DATA_FILENAME, strerror(errno));
+            MR_MDPROF_DATA_FILENAME,
+            MR_strerror(errno, errbuf, sizeof(errbuf)));
     }
 
     procrep_fp = fopen(MR_MDPROF_PROCREP_FILENAME, "wb+");
     if (procrep_fp == NULL) {
         MR_fatal_error("cannot open `%s' for writing: %s",
-            MR_MDPROF_PROCREP_FILENAME, strerror(errno));
+            MR_MDPROF_PROCREP_FILENAME,
+            MR_strerror(errno, errbuf, sizeof(errbuf)));
     }
 
 #ifdef  MR_DEEP_PROFILING_DEBUG
@@ -667,7 +670,10 @@ MR_write_out_profiling_tree(void)
 static void
 MR_deep_data_output_error(const char *op, const char *filename)
 {
-    MR_warning("%s %s: %s", op, filename, strerror(errno));
+    char    errbuf[MR_STRERROR_SIZE];
+
+    MR_warning("%s %s: %s", op, filename,
+        MR_strerror(errno, errbuf, sizeof(errbuf)));
 
     /*
     ** An incomplete profiling data file is useless. Removing it prevents
@@ -677,12 +683,14 @@ MR_deep_data_output_error(const char *op, const char *filename)
 
     if (remove(MR_MDPROF_DATA_FILENAME) != 0) {
         MR_warning("cannot remove %s: %s",
-            MR_MDPROF_DATA_FILENAME, strerror(errno));
+            MR_MDPROF_DATA_FILENAME,
+            MR_strerror(errno, errbuf, sizeof(errbuf)));
     }
 
     if (remove(MR_MDPROF_PROCREP_FILENAME) != 0) {
         MR_warning("cannot remove %s: %s",
-            MR_MDPROF_PROCREP_FILENAME, strerror(errno));
+            MR_MDPROF_PROCREP_FILENAME,
+            MR_strerror(errno, errbuf, sizeof(errbuf)));
     }
 
     exit(1);
diff --git a/runtime/mercury_misc.c b/runtime/mercury_misc.c
index 2d78480..ae92889 100644
--- a/runtime/mercury_misc.c
+++ b/runtime/mercury_misc.c
@@ -14,6 +14,7 @@
 #include    "mercury_string.h"
 #include    "mercury_misc.h"
 #include    "mercury_array_macros.h"
+#include    "mercury_runtime_util.h"
 
 #include    <stdio.h>
 #include    <stdarg.h>
@@ -87,11 +88,13 @@ MR_fatal_error(const char *fmt, ...)
 {
     va_list args;
     int error = errno;
+    char errbuf[MR_STRERROR_SIZE];
 
     fflush(stdout);     /* in case stdout and stderr are the same */
 
     if (error != 0) {
-        fprintf(stderr, "Errno = %d: %s\n", error, strerror(error));
+        fprintf(stderr, "Errno = %d: %s\n", error,
+            MR_strerror(error, errbuf, sizeof(errbuf)));
     }
     fprintf(stderr, "Mercury runtime: ");
     va_start(args, fmt);
diff --git a/runtime/mercury_runtime_util.c b/runtime/mercury_runtime_util.c
index 5c565e5..f523c52 100644
--- a/runtime/mercury_runtime_util.c
+++ b/runtime/mercury_runtime_util.c
@@ -3,6 +3,7 @@
 */
 /*
 ** Copyright (C) 2001-2002, 2006 The University of Melbourne.
+** Copyright (C) 2014 The Mercury team.
 ** This file may only be copied under the terms of the GNU Library General
 ** Public License - see the file COPYING.LIB in the Mercury distribution.
 */
@@ -24,41 +25,75 @@
 
 #include    <errno.h>
 
-#ifndef MR_HAVE_STRERROR
+static void
+generic_strerror(char *buf, size_t buflen, int errnum)
+{
+#if defined(MR_HAVE_SNPRINTF)
+    snprintf(buf, buflen, "Error %d", errnum);
+#elif defined(MR_HAVE__SNPRINTF)
+    /* _snprintf does not guarantee null termination. */
+    _snprintf(buf, buflen, "Error %d", errnum);
+    if (buflen > 0) {
+        buf[buflen - 1] = '\0';
+    }
+#else
+    #error "generic_error: unable to define"
+#endif
+}
 
+const char *
+MR_strerror(int errnum, char *buf, size_t buflen)
+{
+#if defined(MR_HAVE_STRERROR_S)
     /*
-** Apparently SunOS 4.1.3 doesn't have strerror()
-**  (!%^&!^% non-ANSI systems, grumble...)
+    ** MSVC has strerror_s.  It also exists in C11 Annex K and is enabled by
+    ** defining a preprocessor macro __STDC_WANT_LIB_EXT1__
+    */
+    if (strerror_s(buf, buflen, errnum) != 0) {
+        generic_strerror(buf, buflen, errnum);
+    }
+    return buf;
+#elif defined(MR_HAVE_STRERROR_R)
+    /*
+    ** The XSI-compliant strerror_r populates buf unless it fails.
+    ** The GNU-specific strerror_r does not always populate buf.
+    */
+  #if (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE
+    if (strerror_r(errnum, buf, buflen) != 0) {
+        generic_strerror(errnum, buf, buflen);
+    }
+    return buf;
+  #else
+    return strerror_r(errnum, buf, buflen);
+  #endif
+#else
+    /*
+    ** Fallback using deprecated variables. This is used on MinGW at least.
+    **
+    ** strerror_l is another thread-safe alternative, specified in POSIX.
+    ** It is locale-sensitive and takes a locale argument so we don't use it
+    ** for now.
     */
-
-extern  int     sys_nerr;
-extern  char    *sys_errlist[];
-
-char *
-strerror(int errnum)
-{
     if (errnum >= 0 && errnum < sys_nerr && sys_errlist[errnum] != NULL) {
         return sys_errlist[errnum];
     } else {
-        static  char    buf[30];
-
-        sprintf(buf, "Error %d", errnum);
+        generic_strerror(buf, buflen, errnum);
         return buf;
     }
+#endif
 }
 
-#endif  /* MR_HAVE_STRERROR */
-
 FILE *
 MR_checked_fopen(const char *filename, const char *message, const char *mode)
 {
     FILE *file;
+    char errbuf[MR_STRERROR_SIZE];
 
     errno = 0;
     file = fopen(filename, mode);
     if (file == NULL) {
         fprintf(stderr, "Mercury runtime: couldn't %s file `%s': %s\n",
-            message, filename, strerror(errno));
+            message, filename, MR_strerror(errno, errbuf, sizeof(errbuf)));
         exit(EXIT_FAILURE);
     }
     return file;
@@ -67,10 +102,12 @@ MR_checked_fopen(const char *filename, const char *message, const char *mode)
 void
 MR_checked_fclose(FILE *file, const char *filename)
 {
+    char errbuf[MR_STRERROR_SIZE];
+
     errno = 0;
     if (fclose(file) != 0) {
         fprintf(stderr, "Mercury runtime: error closing file `%s': %s\n",
-            filename, strerror(errno));
+            filename, MR_strerror(errno, errbuf, sizeof(errbuf)));
         exit(EXIT_FAILURE);
     }
 }
@@ -78,10 +115,12 @@ MR_checked_fclose(FILE *file, const char *filename)
 void
 MR_checked_atexit(void (*func)(void))
 {
+    char errbuf[MR_STRERROR_SIZE];
+
     errno = 0;
     if (atexit(func) != 0) {
         fprintf(stderr, "Mercury runtime: error in call to atexit: %s\n",
-            strerror(errno));
+            MR_strerror(errno, errbuf, sizeof(errbuf)));
         exit(EXIT_FAILURE);
     }
 }
diff --git a/runtime/mercury_runtime_util.h b/runtime/mercury_runtime_util.h
index d40fb2b..9f41283 100644
--- a/runtime/mercury_runtime_util.h
+++ b/runtime/mercury_runtime_util.h
@@ -1,5 +1,6 @@
 /*
 ** Copyright (C) 2001,2006 The University of Melbourne.
+** Copyright (C) 2014 The Mercury team.
 ** This file may only be copied under the terms of the GNU Library General
 ** Public License - see the file COPYING.LIB in the Mercury distribution.
 */
@@ -9,9 +10,18 @@
 
 #include	<stdio.h>
 
-#ifndef MR_HAVE_STRERROR
-extern	char	*strerror(int errnum);
-#endif
+/*
+** An appropriate buffer size for MR_strerror().
+*/
+#define MR_STRERROR_SIZE    256
+
+/*
+** Thread-safe strerror function. Returns a pointer to a null terminated string
+** describing the error number. The returned pointer may be to the provided
+** buffer, or it may be a pointer into static or thread-local memory.
+** errno may be modified by this call.
+*/
+extern const char *MR_strerror(int errnum, char *buf, size_t buflen);
 
 extern	FILE	*MR_checked_fopen(const char *filename, const char *message,
 			const char *mode);
diff --git a/runtime/mercury_term_size.c b/runtime/mercury_term_size.c
index 78d558f..5acb7b1 100644
--- a/runtime/mercury_term_size.c
+++ b/runtime/mercury_term_size.c
@@ -399,6 +399,7 @@ MR_write_complexity_proc(MR_ComplexityProc *proc)
     int                     num_slots;
     MR_ComplexityPastSlots  *past_slots;
     char                    *cmd_buf;
+    char                    errbuf[MR_STRERROR_SIZE];
 
     full_proc_name_len = strlen(proc->MR_clp_full_proc_name);
     full_proc_name = MR_malloc(100 + full_proc_name_len);
@@ -422,7 +423,8 @@ MR_write_complexity_proc(MR_ComplexityProc *proc)
             if (! MR_have_printed_complexity_dirs_error) {
                 fprintf(stderr, "%s: cannot create %s and %s: %s\n",
                     MR_progname, MR_COMPLEXITY_ARGS_DIR,
-                    MR_COMPLEXITY_DATA_DIR, strerror(errno));
+                    MR_COMPLEXITY_DATA_DIR,
+                    MR_strerror(errno, errbuf, sizeof(errbuf)));
                 /* there is no point in aborting */
                 MR_have_printed_complexity_dirs_error = MR_TRUE;
                 return;
@@ -440,7 +442,8 @@ MR_write_complexity_proc(MR_ComplexityProc *proc)
         fp = fopen(args_filename, "w");
         if (fp == NULL) {
             fprintf(stderr, "%s: cannot open %s: %s\n",
-                MR_progname, args_filename, strerror(errno));
+                MR_progname, args_filename,
+                MR_strerror(errno, errbuf, sizeof(errbuf)));
             /* there is no point in aborting */
             return;
         }
@@ -458,7 +461,8 @@ MR_write_complexity_proc(MR_ComplexityProc *proc)
         fp = fopen(tmp_filename, "w");
         if (fp == NULL) {
             fprintf(stderr, "%s: cannot open %s: %s\n",
-                MR_progname, tmp_filename, strerror(errno));
+                MR_progname, tmp_filename,
+                MR_strerror(errno, errbuf, sizeof(errbuf)));
             /* there is no point in aborting */
             return;
         }
@@ -484,7 +488,8 @@ MR_write_complexity_proc(MR_ComplexityProc *proc)
     fp = fopen(data_filename, data_filemode);
     if (fp == NULL) {
         fprintf(stderr, "%s: cannot open %s: %s\n",
-            MR_progname, data_filename, strerror(errno));
+            MR_progname, data_filename,
+            MR_strerror(errno, errbuf, sizeof(errbuf)));
         /* there is no point in aborting */
         return;
     }
diff --git a/runtime/mercury_trace_base.c b/runtime/mercury_trace_base.c
index d5fbe9a..d1933a0 100644
--- a/runtime/mercury_trace_base.c
+++ b/runtime/mercury_trace_base.c
@@ -27,7 +27,7 @@ ENDINIT
 #include "mercury_misc.h"
 #include "mercury_hash_table.h"
 #include "mercury_layout_util.h"    /* for MR_generate_proc_name_from_layout */
-#include "mercury_runtime_util.h"   /* for strerror() on some systems */
+#include "mercury_runtime_util.h"   /* for MR_strerror */
 #include "mercury_signal.h"         /* for MR_setup_signal() */
 #include "mercury_builtin_types.h"  /* for type_ctor_infos */
 #include "mercury_array_macros.h"   /* for type_ctor_infos */
@@ -283,6 +283,7 @@ MR_trace_record_label_exec_counts(void *dummy)
     MR_bool     keep;
     char        *slash;
     const char  *program_name;
+    char        errbuf[MR_STRERROR_SIZE];
 
     program_name = MR_copy_string(MR_progname);
     slash = strrchr(program_name, '/');
@@ -364,7 +365,8 @@ MR_trace_record_label_exec_counts(void *dummy)
             summarize = MR_FALSE;
         }
     } else {
-        fprintf(stderr, "%s: %s\n", name, strerror(errno));
+        fprintf(stderr, "%s: %s\n", name,
+            MR_strerror(errno, errbuf, sizeof(errbuf)));
         /*
         ** You can't summarize a file list if you can't create
         ** one of its files.
@@ -934,6 +936,7 @@ MR_trace_report(FILE *fp)
 #ifdef  MR_TRACE_HISTOGRAM
         {
             FILE    *hfp;
+            char    errbuf[MR_STRERROR_SIZE];
 
             hfp = fopen(MR_TRACE_HISTOGRAM_FILENAME, "w");
             if (hfp != NULL) {
@@ -944,11 +947,13 @@ MR_trace_report(FILE *fp)
                         MR_TRACE_HISTOGRAM_FILENAME);
                 } else {
                     fprintf(fp, "Cannot put event histogram into `%s': %s."
-                        MR_TRACE_HISTOGRAM_FILENAME, strerror(errno));
+                        MR_TRACE_HISTOGRAM_FILENAME,
+                        MR_strerror(errno, errbuf, sizeof(errbuf)));
                 }
             } else {
                 fprintf(fp, "Cannot open `%s': %s.\n"
-                    MR_TRACE_HISTOGRAM_FILENAME, strerror(errno));
+                    MR_TRACE_HISTOGRAM_FILENAME,
+                    MR_strerror(errno, errbuf, sizeof(errbuf)));
             }
         }
 #endif  /* MR_TRACE_HISTOGRAM */
diff --git a/trace/mercury_trace_cmd_developer.c b/trace/mercury_trace_cmd_developer.c
index 73b7e7b..2099137 100644
--- a/trace/mercury_trace_cmd_developer.c
+++ b/trace/mercury_trace_cmd_developer.c
@@ -26,6 +26,7 @@
 #include "mercury_tabling.h"
 #include "mercury_trace_base.h"
 #include "mercury_regs.h"
+#include "mercury_runtime_util.h"
 
 #include "mercury_trace_internal.h"
 #include "mercury_trace_cmds.h"
@@ -647,6 +648,7 @@ MR_trace_cmd_stats(char **words, int word_count, MR_TraceCmdInfo *cmd,
     char    *filename;
     FILE    *fp;
     MR_bool should_close;
+    char    errbuf[MR_STRERROR_SIZE];
 
     filename = NULL;
     if (! MR_trace_options_stats(&filename, &words, &word_count)) {
@@ -664,7 +666,7 @@ MR_trace_cmd_stats(char **words, int word_count, MR_TraceCmdInfo *cmd,
         if (fp == NULL) {
             fflush(MR_mdb_out);
             fprintf(MR_mdb_err, "mdb: error opening `%s': %s.\n",
-                filename, strerror(errno));
+                filename, MR_strerror(errno, errbuf, sizeof(errbuf)));
             return KEEP_INTERACTING;
         }
 
@@ -1248,6 +1250,7 @@ MR_trace_cmd_all_procedures(char **words, int word_count,
     MR_bool         uci;
     FILE            *fp;
     char            *module;
+    char            errbuf[MR_STRERROR_SIZE];
 
     MR_register_all_modules_and_procs(MR_mdb_out, MR_TRUE);
 
@@ -1264,14 +1267,14 @@ MR_trace_cmd_all_procedures(char **words, int word_count,
         if (fp == NULL) {
             fflush(MR_mdb_out);
             fprintf(MR_mdb_err, "mdb: error opening `%s': %s.\n",
-                filename, strerror(errno));
+                filename, MR_strerror(errno, errbuf, sizeof(errbuf)));
             return KEEP_INTERACTING;
         }
 
         MR_dump_module_tables(fp, separate, uci, module);
         if (fclose(fp) != 0) {
             fprintf(MR_mdb_err, "mdb: error writing to `%s': %s.\n",
-                filename, strerror(errno));
+                filename, MR_strerror(errno, errbuf, sizeof(errbuf)));
             return KEEP_INTERACTING;
         } else {
             fprintf(MR_mdb_out, "mdb: wrote table to `%s'.\n", filename);
@@ -1292,6 +1295,7 @@ MR_trace_cmd_ambiguity(char **words, int word_count,
     MR_bool         print_types;
     MR_bool         print_functors;
     FILE            *fp;
+    char            errbuf[MR_STRERROR_SIZE];
 
     filename = NULL;
     print_procs = MR_FALSE;
@@ -1317,7 +1321,7 @@ MR_trace_cmd_ambiguity(char **words, int word_count,
             if (fp == NULL) {
                 fflush(MR_mdb_out);
                 fprintf(MR_mdb_err, "mdb: error opening `%s': %s.\n",
-                    filename, strerror(errno));
+                    filename, MR_strerror(errno, errbuf, sizeof(errbuf)));
                 return KEEP_INTERACTING;
             }
         }
diff --git a/trace/mercury_trace_cmd_exp.c b/trace/mercury_trace_cmd_exp.c
index 7d7c82b..17ac665 100644
--- a/trace/mercury_trace_cmd_exp.c
+++ b/trace/mercury_trace_cmd_exp.c
@@ -22,6 +22,7 @@
 
 #include "mercury_std.h"
 #include "mercury_getopt.h"
+#include "mercury_runtime_util.h"
 
 #include "mercury_trace_internal.h"
 #include "mercury_trace_cmds.h"
@@ -65,7 +66,7 @@ MR_trace_cmd_histogram_all(char **words, int word_count,
         if (fp == NULL) {
             fflush(MR_mdb_out);
             fprintf(MR_mdb_err, "mdb: cannot open file `%s' for output: %s.\n",
-                words[1], strerror(errno));
+                words[1], MR_strerror(errno, errbuf, sizeof(errbuf)));
         } else {
             MR_trace_print_histogram(fp, "All-inclusive",
                 MR_trace_histogram_all,
@@ -73,7 +74,7 @@ MR_trace_cmd_histogram_all(char **words, int word_count,
             if (fclose(fp) != 0) {
                 fflush(MR_mdb_out);
                 fprintf(MR_mdb_err, "mdb: error closing file `%s': %s.\n",
-                    words[1], strerror(errno));
+                    words[1], MR_strerror(errno, errbuf, sizeof(errbuf)));
             }
         }
     } else {
@@ -103,7 +104,7 @@ MR_trace_cmd_histogram_exp(char **words, int word_count,
         if (fp == NULL) {
             fflush(MR_mdb_out);
             fprintf(MR_mdb_err, "mdb: cannot open file `%s' for output: %s.\n",
-                words[1], strerror(errno));
+                words[1], MR_strerror(errno, errbuf, sizeof(errbuf)));
         } else {
             MR_trace_print_histogram(fp, "Experimental",
                 MR_trace_histogram_exp,
@@ -111,7 +112,7 @@ MR_trace_cmd_histogram_exp(char **words, int word_count,
             if (fclose(fp) != 0) {
                 fflush(MR_mdb_out);
                 fprintf(MR_mdb_err, "mdb: error closing file `%s': %s.\n",
-                    words[1], strerror(errno));
+                    words[1], MR_strerror(errno, errbuf, sizeof(errbuf)));
             }
         }
     } else {
@@ -233,6 +234,7 @@ MR_trace_print_dice(char *pass_trace_counts_file,
     MR_String   aligned_sort_str;
     MR_String   aligned_module;
     FILE        *fp;
+    char        errbuf[MR_STRERROR_SIZE];
 
     MR_TRACE_USE_HP(
         MR_make_aligned_string(aligned_pass_trace_counts_file,
@@ -264,12 +266,12 @@ MR_trace_print_dice(char *pass_trace_counts_file,
                 if (fclose(fp) != 0) {
                     fflush(MR_mdb_out);
                     fprintf(MR_mdb_err, "mdb: Error closing file `%s': %s\n",
-                        out_file, strerror(errno));
+                        out_file, MR_strerror(errno, errbuf, sizeof(errbuf)));
                 }
             } else {
                 fflush(MR_mdb_out);
                 fprintf(MR_mdb_err, "mdb: Error opening file `%s': %s\n",
-                    out_file, strerror(errno));
+                    out_file, MR_strerror(errno, errbuf, sizeof(errbuf)));
             }
         }
     } else {
diff --git a/trace/mercury_trace_cmd_misc.c b/trace/mercury_trace_cmd_misc.c
index d0a1ab6..4703001 100644
--- a/trace/mercury_trace_cmd_misc.c
+++ b/trace/mercury_trace_cmd_misc.c
@@ -22,6 +22,7 @@
 
 #include "mercury_std.h"
 #include "mercury_getopt.h"
+#include "mercury_runtime_util.h"
 
 #include "mercury_trace_internal.h"
 #include "mercury_trace_cmds.h"
@@ -80,12 +81,13 @@ MR_trace_cmd_save(char **words, int word_count, MR_TraceCmdInfo *cmd,
         FILE    *fp;
         MR_bool found_error;
         MR_Word path_list;
+        char    errbuf[MR_STRERROR_SIZE];
 
         fp = fopen(words[1], "w");
         if (fp == NULL) {
             fflush(MR_mdb_out);
             fprintf(MR_mdb_err, "mdb: error opening `%s': %s.\n",
-                words[1], strerror(errno));
+                words[1], MR_strerror(errno, errbuf, sizeof(errbuf)));
             return KEEP_INTERACTING;
         }
 
@@ -204,7 +206,7 @@ MR_trace_cmd_save(char **words, int word_count, MR_TraceCmdInfo *cmd,
         } else if (fclose(fp) != 0) {
             fflush(MR_mdb_out);
             fprintf(MR_mdb_err, "mdb: error closing `%s': %s.\n",
-                words[1], strerror(errno));
+                words[1], MR_strerror(errno, errbuf, sizeof(errbuf)));
         } else {
             fprintf(MR_mdb_out, "Debugger state saved to %s.\n", words[1]);
         }
diff --git a/trace/mercury_trace_declarative.c b/trace/mercury_trace_declarative.c
index 00c1697..5b81122 100644
--- a/trace/mercury_trace_declarative.c
+++ b/trace/mercury_trace_declarative.c
@@ -120,6 +120,7 @@
 #include "mercury_string.h"
 #include "mercury_timing.h"
 #include "mercury_trace_base.h"
+#include "mercury_runtime_util.h"
 
 #include "mdb.declarative_debugger.mh"
 #include "mdb.declarative_execution.mh"
@@ -1712,9 +1713,11 @@ MR_trace_start_decl_debug(MR_DeclMode mode, const char *outfile,
     if (mode == MR_DECL_DUMP) {
         out = fopen(outfile, "w");
         if (out == NULL) {
+            char    errbuf[MR_STRERROR_SIZE];
+
             fflush(MR_mdb_out);
             fprintf(MR_mdb_err, "mdb: cannot open file `%s' for output: %s.\n",
-                outfile, strerror(errno));
+                outfile, MR_strerror(errno, errbuf, sizeof(errbuf)));
             return MR_FALSE;
         } else {
             MR_trace_store_file = out;
diff --git a/trace/mercury_trace_external.c b/trace/mercury_trace_external.c
index 5c881ea..3dcda04 100644
--- a/trace/mercury_trace_external.c
+++ b/trace/mercury_trace_external.c
@@ -38,6 +38,7 @@
 #include "type_desc.mh"
 
 #include "mercury_deep_copy.h"
+#include "mercury_runtime_util.h"
 
 #include <stdio.h>
 #include <errno.h>
@@ -317,6 +318,7 @@ MR_trace_init_external(void)
     struct sockaddr     *addr;
     MR_Word             debugger_request;
     MR_Integer          debugger_request_type;
+    char                errbuf[MR_STRERROR_SIZE];
 
     /*
     ** MR_external_mmc_options contains the options to pass to mmc
@@ -405,7 +407,7 @@ MR_trace_init_external(void)
     fd = socket(addr_family, SOCK_STREAM, 0);
     if (fd < 0) {
         fprintf(stderr, "Mercury runtime: socket() failed: %s\n",
-            strerror(errno));
+            MR_strerror(errno, errbuf, sizeof(errbuf)));
         MR_fatal_error("cannot open socket for debugger");
     } else if (MR_debug_socket) {
         fprintf(stderr,"Mercury runtime: creation of socket ok\n");
@@ -417,7 +419,7 @@ MR_trace_init_external(void)
 
     if (connect(fd, addr, len) < 0) {
         fprintf(stderr, "Mercury runtime: connect() failed: %s\n",
-            strerror(errno));
+            MR_strerror(errno, errbuf, sizeof(errbuf)));
         MR_fatal_error("can't connect to debugger socket");
     } else if (MR_debug_socket) {
         fprintf(stderr, "Mercury runtime: connection to socket: ok\n");
@@ -431,7 +433,7 @@ MR_trace_init_external(void)
     file_out = fdopen(fd, "w");
     if ((file_in == NULL)||(file_out == NULL)) {
         fprintf(stderr, "Mercury runtime: fdopen() failed: %s\n",
-            strerror(errno));
+            MR_strerror(errno, errbuf, sizeof(errbuf)));
         MR_fatal_error("cannot open debugger socket");
     } else if (MR_debug_socket) {
         fprintf(stderr, "Mercury runtime: fdopen(): ok\n");
diff --git a/trace/mercury_trace_internal.c b/trace/mercury_trace_internal.c
index 11e041a..57e099c 100644
--- a/trace/mercury_trace_internal.c
+++ b/trace/mercury_trace_internal.c
@@ -22,6 +22,7 @@
 #include "mercury_signal.h"
 #include "mercury_builtin_types.h"
 #include "mercury_deep_profiling.h"
+#include "mercury_runtime_util.h"
 
 #include "mercury_event_spec.h"
 
@@ -277,12 +278,13 @@ MR_try_fopen(const char *filename, const char *mode, FILE *default_file)
         return default_file;
     } else {
         FILE    *f;
+        char    errbuf[MR_STRERROR_SIZE];
 
         f = fopen(filename, mode);
         if (f == NULL) {
             fflush(MR_mdb_out);
             fprintf(MR_mdb_err, "mdb: error opening `%s': %s\n",
-                filename, strerror(errno));
+                filename, MR_strerror(errno, errbuf, sizeof(errbuf)));
             return default_file;
         } else {
             return f;
@@ -683,6 +685,7 @@ MR_trace_source(const char *filename, MR_bool ignore_errors,
     char** args, int num_args)
 {
     FILE    *fp;
+    char    errbuf[MR_STRERROR_SIZE];
 
     if ((fp = fopen(filename, "r")) != NULL) {
         MR_trace_source_from_open_file(fp, args, num_args);
@@ -692,7 +695,8 @@ MR_trace_source(const char *filename, MR_bool ignore_errors,
 
     if (! ignore_errors) {
         fflush(MR_mdb_out);
-        fprintf(MR_mdb_err, "%s: %s.\n", filename, strerror(errno));
+        fprintf(MR_mdb_err, "%s: %s.\n",
+            filename, MR_strerror(errno, errbuf, sizeof(errbuf)));
     }
 
     return MR_FALSE;
-- 
1.8.4



More information about the reviews mailing list