summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dist/api_err.py43
-rw-r--r--dist/s_string.ok1
-rw-r--r--dist/s_symbols.list1
-rw-r--r--examples/c/ex_all.c16
-rw-r--r--src/conn/api_strerror.c56
-rw-r--r--src/include/extern.h1
-rw-r--r--src/include/wiredtiger.in19
-rw-r--r--src/os_posix/os_errno.c27
-rw-r--r--src/os_win/os_errno.c27
9 files changed, 155 insertions, 36 deletions
diff --git a/dist/api_err.py b/dist/api_err.py
index cb2c8cc588e..d45e6988ed2 100644
--- a/dist/api_err.py
+++ b/dist/api_err.py
@@ -78,7 +78,7 @@ for line in open('../src/include/wiredtiger.in', 'r'):
tfile.close()
compare_srcfile(tmp_file, '../src/include/wiredtiger.in')
-# Output the wiredtiger_strerror code.
+# Output the wiredtiger_strerror and wiredtiger_sterror_r code.
tmp_file = '__tmp'
tfile = open(tmp_file, 'w')
tfile.write('''/* DO NOT EDIT: automatically built by dist/api_err.py. */
@@ -87,37 +87,52 @@ tfile.write('''/* DO NOT EDIT: automatically built by dist/api_err.py. */
/*
* wiredtiger_strerror --
- *\tReturn a string for any error value.
+ *\tReturn a string for any error value in a static buffer.
*/
const char *
wiredtiger_strerror(int error)
{
-\tstatic char errbuf[64];
-\tchar *p;
+\tstatic char buf[128];
-\tif (error == 0)
-\t\treturn ("Successful return: 0");
+\tif (wiredtiger_strerror_r(error, buf, sizeof(buf)) != 0)
+\t\t(void)snprintf(buf, sizeof(buf), "error return: %d", error);
+\treturn (buf);
+}
+
+/*
+ * wiredtiger_strerror_r --
+ *\tReturn a string for any error value, thread-safe version.
+ */
+int
+wiredtiger_strerror_r(int error, char *buf, size_t buflen)
+{
+\tconst char *p;
+
+\t/* Require at least 2 bytes, printable character and trailing nul. */
+\tif (buflen < 2)
+\t\treturn (ENOMEM);
\tswitch (error) {
+\tcase 0:
+\t\tp = "Successful return: 0";
+\t\tbreak;
''')
for err in errors:
tfile.write('\tcase ' + err.name + ':\n')
- tfile.write('\t\treturn ("' + err.name + ': ' + err.desc + '");\n')
+ tfile.write('\t\tp = "' + err.name + ': ' + err.desc + '";\n')
+ tfile.write('\t\tbreak;\n')
tfile.write('''\
\tdefault:
-\t\tif (error > 0 && (p = strerror(error)) != NULL)
-\t\t\treturn (p);
-\t\tbreak;
+\t\treturn (__wt_strerror_r(error, buf, buflen));
\t}
\t/*
-\t * !!!
-\t * Not thread-safe, but this is never supposed to happen.
+\t * Return success if anything printed (we checked if the buffer had
+\t * space for at least one character).
\t */
-\t(void)snprintf(errbuf, sizeof(errbuf), "Unknown error: %d", error);
-\treturn (errbuf);
+\treturn (snprintf(buf, buflen, "%s", p) > 0 ? 0 : ENOMEM);
}
''')
tfile.close()
diff --git a/dist/s_string.ok b/dist/s_string.ok
index 94f3ea6b6a5..786a787c5f3 100644
--- a/dist/s_string.ok
+++ b/dist/s_string.ok
@@ -436,6 +436,7 @@ btmem
btree
btrees
buf
+buflen
bufs
bufsz
builtin
diff --git a/dist/s_symbols.list b/dist/s_symbols.list
index d3803bc3afa..8f469e94433 100644
--- a/dist/s_symbols.list
+++ b/dist/s_symbols.list
@@ -8,6 +8,7 @@ wiredtiger_pack_start
wiredtiger_pack_str
wiredtiger_pack_uint
wiredtiger_strerror
+wiredtiger_strerror_r
wiredtiger_struct_pack
wiredtiger_struct_size
wiredtiger_struct_unpack
diff --git a/examples/c/ex_all.c b/examples/c/ex_all.c
index 01966b5196f..bf5a588274b 100644
--- a/examples/c/ex_all.c
+++ b/examples/c/ex_all.c
@@ -342,6 +342,22 @@ cursor_ops(WT_SESSION *session)
/*! [Display an error] */
}
+ {
+ /*! [Display an error thread safe] */
+ const char *key = "non-existent key";
+ cursor->set_key(cursor, key);
+ if ((ret = cursor->remove(cursor)) != 0) {
+ char buf[128];
+
+ if (wiredtiger_strerror_r(ret, buf, sizeof(buf)) != 0)
+ (void)snprintf(
+ buf, sizeof(buf), "error value: %d\n", ret);
+ fprintf(stderr, "cursor.remove: %s\n", buf);
+ return (ret);
+ }
+ /*! [Display an error thread safe] */
+ }
+
/*! [Close the cursor] */
ret = cursor->close(cursor);
/*! [Close the cursor] */
diff --git a/src/conn/api_strerror.c b/src/conn/api_strerror.c
index caf536b24f7..5cabe55d3f6 100644
--- a/src/conn/api_strerror.c
+++ b/src/conn/api_strerror.c
@@ -4,40 +4,60 @@
/*
* wiredtiger_strerror --
- * Return a string for any error value.
+ * Return a string for any error value in a static buffer.
*/
const char *
wiredtiger_strerror(int error)
{
- static char errbuf[64];
- char *p;
+ static char buf[128];
- if (error == 0)
- return ("Successful return: 0");
+ if (wiredtiger_strerror_r(error, buf, sizeof(buf)) != 0)
+ (void)snprintf(buf, sizeof(buf), "error return: %d", error);
+ return (buf);
+}
+
+/*
+ * wiredtiger_strerror_r --
+ * Return a string for any error value, thread-safe version.
+ */
+int
+wiredtiger_strerror_r(int error, char *buf, size_t buflen)
+{
+ const char *p;
+
+ /* Require at least 2 bytes, printable character and trailing nul. */
+ if (buflen < 2)
+ return (ENOMEM);
switch (error) {
+ case 0:
+ p = "Successful return: 0";
+ break;
case WT_ROLLBACK:
- return ("WT_ROLLBACK: conflict between concurrent operations");
+ p = "WT_ROLLBACK: conflict between concurrent operations";
+ break;
case WT_DUPLICATE_KEY:
- return ("WT_DUPLICATE_KEY: attempt to insert an existing key");
+ p = "WT_DUPLICATE_KEY: attempt to insert an existing key";
+ break;
case WT_ERROR:
- return ("WT_ERROR: non-specific WiredTiger error");
+ p = "WT_ERROR: non-specific WiredTiger error";
+ break;
case WT_NOTFOUND:
- return ("WT_NOTFOUND: item not found");
+ p = "WT_NOTFOUND: item not found";
+ break;
case WT_PANIC:
- return ("WT_PANIC: WiredTiger library panic");
+ p = "WT_PANIC: WiredTiger library panic";
+ break;
case WT_RESTART:
- return ("WT_RESTART: restart the operation (internal)");
- default:
- if (error > 0 && (p = strerror(error)) != NULL)
- return (p);
+ p = "WT_RESTART: restart the operation (internal)";
break;
+ default:
+ return (__wt_strerror_r(error, buf, buflen));
}
/*
- * !!!
- * Not thread-safe, but this is never supposed to happen.
+ * Return success if anything printed (we checked if the buffer had
+ * space for at least one character).
*/
- (void)snprintf(errbuf, sizeof(errbuf), "Unknown error: %d", error);
- return (errbuf);
+ return (snprintf(buf, buflen, "%s", p) > 0 ? 0 : ENOMEM);
}
diff --git a/src/include/extern.h b/src/include/extern.h
index 056058f3828..b5c71aa7c15 100644
--- a/src/include/extern.h
+++ b/src/include/extern.h
@@ -431,6 +431,7 @@ extern int __wt_dlopen(WT_SESSION_IMPL *session, const char *path, WT_DLH **dlhp
extern int __wt_dlsym(WT_SESSION_IMPL *session, WT_DLH *dlh, const char *name, int fail, void *sym_ret);
extern int __wt_dlclose(WT_SESSION_IMPL *session, WT_DLH *dlh);
extern int __wt_errno(void);
+extern int __wt_strerror_r(int error, char *buf, size_t buflen);
extern int __wt_exist(WT_SESSION_IMPL *session, const char *filename, int *existp);
extern void __wt_fallocate_config(WT_SESSION_IMPL *session, WT_FH *fh);
extern int __wt_fallocate( WT_SESSION_IMPL *session, WT_FH *fh, wt_off_t offset, wt_off_t len);
diff --git a/src/include/wiredtiger.in b/src/include/wiredtiger.in
index 075514e02b4..20991278440 100644
--- a/src/include/wiredtiger.in
+++ b/src/include/wiredtiger.in
@@ -2019,15 +2019,26 @@ int wiredtiger_open(const char *home,
WT_CONNECTION **connectionp);
/*!
- * Return information about an error as a string; wiredtiger_strerror is a
- * superset of the ISO C99/POSIX 1003.1-2001 function strerror.
+ * Return information about a WiredTiger error as a string, not thread-safe.
*
* @snippet ex_all.c Display an error
*
- * @param err a return value from a WiredTiger, C library or POSIX function
+ * @param error a return value from a WiredTiger call
* @returns a string representation of the error
*/
-const char *wiredtiger_strerror(int err);
+const char *wiredtiger_strerror(int error);
+
+/*!
+ * Return information about a WiredTiger error as a string, thread-safe version.
+ *
+ * @snippet ex_all.c Display an error thread safe
+ *
+ * @param error a return value from a WiredTiger call
+ * @param buf a buffer of at least \c buflen bytes
+ * @param buflen the length of the buffer
+ * @returns zero for success, non-zero to indicate an error.
+ */
+int wiredtiger_strerror_r(int error, char *buf, size_t buflen);
#if !defined(SWIG)
/*!
diff --git a/src/os_posix/os_errno.c b/src/os_posix/os_errno.c
index 9290f7d651f..b0cb288ea74 100644
--- a/src/os_posix/os_errno.c
+++ b/src/os_posix/os_errno.c
@@ -20,3 +20,30 @@ __wt_errno(void)
*/
return (errno == 0 ? WT_ERROR : errno);
}
+
+/*
+ * __wt_strerror_r --
+ * POSIX implementation of strerror_r.
+ */
+int
+__wt_strerror_r(int error, char *buf, size_t buflen)
+{
+ char *p;
+
+ /* Require at least 2 bytes, printable character and trailing nul. */
+ if (buflen < 2)
+ return (ENOMEM);
+
+ /*
+ * POSIX errors are non-negative integers, copy the string into the
+ * user's buffer. Return success if anything printed (we checked if
+ * the buffer had space for at least one character).
+ */
+ if (error > 0 &&
+ (p = strerror(error)) != NULL && snprintf(buf, buflen, "%s", p) > 0)
+ return (0);
+
+ /* Fallback to a generic message, then guess it's a memory problem. */
+ return (
+ snprintf(buf, buflen, "error return: %d", error) > 0 ? 0 : ENOMEM);
+}
diff --git a/src/os_win/os_errno.c b/src/os_win/os_errno.c
index ce50106b0cc..856db1ae96d 100644
--- a/src/os_win/os_errno.c
+++ b/src/os_win/os_errno.c
@@ -25,3 +25,30 @@ __wt_errno(void)
return (err == ERROR_SUCCESS ? WT_ERROR : err);
}
+
+/*
+ * __wt_strerror_r --
+ * Windows implementation of strerror_r.
+ */
+int
+__wt_strerror_r(int error, char *buf, size_t buflen)
+{
+ char *p;
+
+ /* Require at least 2 bytes, printable character and trailing nul. */
+ if (buflen < 2)
+ return (ENOMEM);
+
+ /*
+ * POSIX errors are non-negative integers, copy the string into the
+ * user's buffer. Return success if anything printed (we checked if
+ * the buffer had space for at least one character).
+ */
+ if (error > 0 &&
+ (p = strerror(error)) != NULL && snprintf(buf, buflen, "%s", p) > 0)
+ return (0);
+
+ /* Fallback to a generic message, then guess it's a memory problem. */
+ return (
+ snprintf(buf, buflen, "error return: %d", error) > 0 ? 0 : ENOMEM);
+}