diff --git a/NEWS b/NEWS index 0b81e2af9..47be2cc66 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,7 @@ This is a bug-fix release. * The MinGW port now builds in the absence of POSIX threads library. * Low-level C parallel grades now work on Windows instead of crashing at startup. +* We now use thread-safe alternatives to strerror(). * A problem that caused string.format/[23] to sometimes return incorrect results when formatting floats with the 'g' conversion specifier has been fixed. This bug only affected the non-C backends. (Bug #342) diff --git a/compiler/notes/coding_standards.html b/compiler/notes/coding_standards.html index 94ee830a2..752a92415 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 9546508ed..158b006a9 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_BUF_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_BUF_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 720500a9f..dede27452 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 6d7acf1ab..a128842ad 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_BUF_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 4036526fb..87995bcfa 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_BUF_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_BUF_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 501f1e745..7ebf6ad9a 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 #include @@ -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_BUF_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_BUF_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 /* -** 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_BUF_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 d8b8560df..d44ce455b 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 124e37810..7000a7811 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_BUF_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_BUF_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 2d784805e..fc7a6ce81 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 #include @@ -87,11 +88,13 @@ MR_fatal_error(const char *fmt, ...) { va_list args; int error = errno; + char errbuf[MR_STRERROR_BUF_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 5c565e565..e9cfd888c 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 -#ifndef MR_HAVE_STRERROR - -/* -** Apparently SunOS 4.1.3 doesn't have strerror() -** (!%^&!^% non-ANSI systems, grumble...) -*/ - -extern int sys_nerr; -extern char *sys_errlist[]; - -char * -strerror(int errnum) +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) + /* + ** 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. + */ 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_BUF_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_BUF_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_BUF_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 d40fb2bd0..a21559488 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 -#ifndef MR_HAVE_STRERROR -extern char *strerror(int errnum); -#endif +/* +** A reasonable buffer size for MR_strerror(). +*/ +#define MR_STRERROR_BUF_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 78d558f1c..bc267fcdc 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_BUF_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 d5fbe9a48..879a73e0a 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_BUF_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_BUF_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 73b7e7b68..1872713f1 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_BUF_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_BUF_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_BUF_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 7d7c82b4b..0b57c54f5 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_BUF_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 d0a1ab619..9c2e9dcfd 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_BUF_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 00c169737..8931d1f1b 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_BUF_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 5c881eae1..54495d637 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 #include @@ -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_BUF_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 11e041a68..4f47582f7 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_BUF_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_BUF_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;