Welcome! Log In Create A New Profile

Advanced

[nginx] Improved maximum errno detection.

Maxim Dounin
March 01, 2021 01:44PM
details: https://hg.nginx.org/nginx/rev/8cc5b0365ee5
branches:
changeset: 7784:8cc5b0365ee5
user: Maxim Dounin <mdounin@mdounin.ru>
date: Mon Mar 01 20:00:43 2021 +0300
description:
Improved maximum errno detection.

Previously, systems without sys_nerr (or _sys_nerr) were handled with an
assumption that errors start at 0 and continuous. This is, however, not
something POSIX requires, and not true on some platforms.

Notably, on Linux, where sys_nerr is no longer available for newly linked
binaries starting with glibc 2.32, there are gaps in error list, which
used to stop us from properly detecting maximum errno. Further, on
GNU/Hurd errors start at 0x40000001.

With this change, maximum errno detection is moved to the runtime code,
now able to ignore gaps, and also detects the first error if needed.
This fixes observed "Unknown error" messages as seen on Linux with
glibc 2.32 and on GNU/Hurd.

diffstat:

auto/unix | 28 ---------------
src/os/unix/ngx_errno.c | 91 +++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 85 insertions(+), 34 deletions(-)

diffs (172 lines):

diff -r 171682010da4 -r 8cc5b0365ee5 auto/unix
--- a/auto/unix Mon Mar 01 17:31:28 2021 +0300
+++ b/auto/unix Mon Mar 01 20:00:43 2021 +0300
@@ -753,34 +753,6 @@ if [ $ngx_found = no ]; then
fi


-if [ $ngx_found = no ]; then
-
- # Solaris has no sys_nerr
- ngx_feature='maximum errno'
- ngx_feature_name=NGX_SYS_NERR
- ngx_feature_run=value
- ngx_feature_incs='#include <errno.h>
- #include <string.h>
- #include <stdio.h>'
- ngx_feature_path=
- ngx_feature_libs=
- ngx_feature_test='int n;
- char *p;
- for (n = 1; n < 1000; n++) {
- errno = 0;
- p = strerror(n);
- if (errno == EINVAL
- || p == NULL
- || strncmp(p, "Unknown error", 13) == 0)
- {
- break;
- }
- }
- printf("%d", n);'
- . auto/feature
-fi
-
-
ngx_feature="localtime_r()"
ngx_feature_name="NGX_HAVE_LOCALTIME_R"
ngx_feature_run=no
diff -r 171682010da4 -r 8cc5b0365ee5 src/os/unix/ngx_errno.c
--- a/src/os/unix/ngx_errno.c Mon Mar 01 17:31:28 2021 +0300
+++ b/src/os/unix/ngx_errno.c Mon Mar 01 20:00:43 2021 +0300
@@ -27,6 +27,8 @@

static ngx_str_t *ngx_sys_errlist;
static ngx_str_t ngx_unknown_error = ngx_string("Unknown error");
+static ngx_err_t ngx_first_error;
+static ngx_err_t ngx_last_error;


u_char *
@@ -34,8 +36,13 @@ ngx_strerror(ngx_err_t err, u_char *errs
{
ngx_str_t *msg;

- msg = ((ngx_uint_t) err < NGX_SYS_NERR) ? &ngx_sys_errlist[err]:
- &ngx_unknown_error;
+ if (err >= ngx_first_error && err < ngx_last_error) {
+ msg = &ngx_sys_errlist[err - ngx_first_error];
+
+ } else {
+ msg = &ngx_unknown_error;
+ }
+
size = ngx_min(size, msg->len);

return ngx_cpymem(errstr, msg->data, size);
@@ -50,20 +57,92 @@ ngx_strerror_init(void)
size_t len;
ngx_err_t err;

+#if (NGX_SYS_NERR)
+ ngx_first_error = 0;
+ ngx_last_error = NGX_SYS_NERR;
+
+#elif (EPERM > 1000 && EPERM < 0x7fffffff - 1000)
+
+ /*
+ * If number of errors is not known, and EPERM error code has large
+ * but reasonable value, guess possible error codes based on the error
+ * messages returned by strerror(), starting from EPERM. Notably,
+ * this covers GNU/Hurd, where errors start at 0x40000001.
+ */
+
+ for (err = EPERM; err > EPERM - 1000; err--) {
+ ngx_set_errno(0);
+ msg = strerror(err);
+
+ if (errno == EINVAL
+ || msg == NULL
+ || strncmp(msg, "Unknown error", 13) == 0)
+ {
+ continue;
+ }
+
+ ngx_first_error = err;
+ }
+
+ for (err = EPERM; err < EPERM + 1000; err++) {
+ ngx_set_errno(0);
+ msg = strerror(err);
+
+ if (errno == EINVAL
+ || msg == NULL
+ || strncmp(msg, "Unknown error", 13) == 0)
+ {
+ continue;
+ }
+
+ ngx_last_error = err + 1;
+ }
+
+#else
+
+ /*
+ * If number of errors is not known, guess it based on the error
+ * messages returned by strerror().
+ */
+
+ ngx_first_error = 0;
+
+ for (err = 0; err < 1000; err++) {
+ ngx_set_errno(0);
+ msg = strerror(err);
+
+ if (errno == EINVAL
+ || msg == NULL
+ || strncmp(msg, "Unknown error", 13) == 0)
+ {
+ continue;
+ }
+
+ ngx_last_error = err + 1;
+ }
+
+#endif
+
/*
* ngx_strerror() is not ready to work at this stage, therefore,
* malloc() is used and possible errors are logged using strerror().
*/

- len = NGX_SYS_NERR * sizeof(ngx_str_t);
+ len = (ngx_last_error - ngx_first_error) * sizeof(ngx_str_t);

ngx_sys_errlist = malloc(len);
if (ngx_sys_errlist == NULL) {
goto failed;
}

- for (err = 0; err < NGX_SYS_NERR; err++) {
+ for (err = ngx_first_error; err < ngx_last_error; err++) {
msg = strerror(err);
+
+ if (msg == NULL) {
+ ngx_sys_errlist[err - ngx_first_error] = ngx_unknown_error;
+ continue;
+ }
+
len = ngx_strlen(msg);

p = malloc(len);
@@ -72,8 +151,8 @@ ngx_strerror_init(void)
}

ngx_memcpy(p, msg, len);
- ngx_sys_errlist[err].len = len;
- ngx_sys_errlist[err].data = p;
+ ngx_sys_errlist[err - ngx_first_error].len = len;
+ ngx_sys_errlist[err - ngx_first_error].data = p;
}

return NGX_OK;
_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-devel
Subject Author Views Posted

[nginx] Improved maximum errno detection.

Maxim Dounin 242 March 01, 2021 01:44PM



Sorry, you do not have permission to post/reply in this forum.

Online Users

Guests: 311
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready