Bug 1590976 - Fix errno <-> PRErrorCode mapping in libprldap. r=mkmelin a=jorgk
authorBen Campbell <benc@thunderbird.net>
Thu, 24 Oct 2019 18:37:17 +1300
changeset 36390 ccbcf47c5673534d79f39eeb5058145685f4c839
parent 36389 9be1474307f448e3db3e564e6f3efb0a3b7957ef
child 36391 056d8cc39c8b91c735da616caee4335e5f3d7c4d
push id2523
push usermozilla@jorgk.com
push dateThu, 07 Nov 2019 13:59:32 +0000
treeherdercomm-beta@4c356f38873a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmkmelin, jorgk
bugs1590976
Bug 1590976 - Fix errno <-> PRErrorCode mapping in libprldap. r=mkmelin a=jorgk
ldap/c-sdk/libraries/libprldap/ldappr-error.c
ldap/c-sdk/libraries/libprldap/ldappr-int.h
ldap/c-sdk/libraries/libprldap/ldappr-io.c
ldap/c-sdk/libraries/libprldap/ldappr-public.c
ldap/c-sdk/libraries/libprldap/ldappr-threads.c
--- a/ldap/c-sdk/libraries/libprldap/ldappr-error.c
+++ b/ldap/c-sdk/libraries/libprldap/ldappr-error.c
@@ -31,34 +31,28 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 /*
- * Utilities for manageing the relationship between NSPR errors and
+ * Utilities for managing the relationship between NSPR errors and
  * OS (errno-style) errors.
  *
  * The overall strategy used is to map NSPR errors into OS errors.
+ * Inside libprldap we set NSPR errors. Implicitly, via the various PR_
+ * calls and explicitly via PR_SetError().
+ * We provide prldap_get_errno() which libldap calls to retrieve our error
+ * codes, mapped to the errno values it expects (ENOENT, EAGAIN etc...)
  */
 
 #include "ldappr-int.h"
 
-void prldap_set_system_errno(int oserrno) {
-  PR_SetError(PR_GetError(), oserrno);
-}
-
-int prldap_get_system_errno(void) { return (PR_GetOSError()); }
-
-/*
- * Retrieve the NSPR error number, convert to a system error code, and return
- * the result.
- */
 struct prldap_errormap_entry {
   PRInt32 erm_nspr; /* NSPR error code */
   int erm_system;   /* corresponding system error code */
 };
 
 /* XXX: not sure if this extra mapping for Windows is good or correct */
 #ifdef _WINDOWS
 #  ifndef ENOTSUP
@@ -225,19 +219,20 @@ struct prldap_errormap_entry {
 #if defined(__hpux) || defined(_AIX) || defined(OSF1) || defined(DARWIN) || \
     defined(BEOS) || defined(FREEBSD) || defined(BSDI) || defined(VMS) ||   \
     defined(OPENBSD) || defined(NETBSD)
 #  define EDEADLOCK -1
 #endif
 
 /* XXX: need to verify that the -1 entries are correct (no mapping) */
 static struct prldap_errormap_entry prldap_errormap[] = {
+    {0, 0},
     {PR_OUT_OF_MEMORY_ERROR, ENOMEM},
     {PR_BAD_DESCRIPTOR_ERROR, EBADF},
-    {PR_WOULD_BLOCK_ERROR, EAGAIN},
+    {PR_WOULD_BLOCK_ERROR, EAGAIN}, /* Important for ldap async mode. */
     {PR_ACCESS_FAULT_ERROR, EFAULT},
     {PR_INVALID_METHOD_ERROR, EINVAL}, /* XXX: correct mapping ? */
     {PR_ILLEGAL_ACCESS_ERROR, EACCES}, /* XXX: correct mapping ? */
     {PR_UNKNOWN_ERROR, -1},
     {PR_PENDING_INTERRUPT_ERROR, -1},
     {PR_NOT_IMPLEMENTED_ERROR, ENOTSUP},
     {PR_IO_ERROR, EIO},
     {PR_IO_TIMEOUT_ERROR, ETIMEDOUT}, /* XXX: correct mapping ? */
@@ -302,24 +297,46 @@ static struct prldap_errormap_entry prld
     {PR_INVALID_STATE_ERROR, -1},
     {PR_NETWORK_DOWN_ERROR, ENETDOWN},
     {PR_SOCKET_SHUTDOWN_ERROR, ESHUTDOWN},
     {PR_CONNECT_ABORTED_ERROR, ECONNABORTED},
     {PR_HOST_UNREACHABLE_ERROR, EHOSTUNREACH},
     {PR_MAX_ERROR, -1},
 };
 
-int prldap_prerr2errno(void) {
-  int oserr, i;
-  PRInt32 nsprerr;
+/**
+ *  Set an appropriate NSPR error code for a given os errno.
+ *
+ *  @param oserrno - the system errno value
+ */
+void prldap_set_errno(int oserrno) {
+  /* NOTE: it's the code returned by PR_GetError() which we'll consider the
+   * 'canonical' error state. Other functions (eg in NSS) will set errors with
+   * no system code, ie PR_SetError(prerrcode, 0).
+   * We set the system error here because it'd seem rude not to, but it
+   * shouldn't be relied upon to check for error states.
+   */
+  PRErrorCode nsprerr = PR_UNKNOWN_ERROR;
+  for (int i = 0; prldap_errormap[i].erm_nspr != PR_MAX_ERROR; ++i) {
+    if (prldap_errormap[i].erm_system == oserrno) {
+      nsprerr = prldap_errormap[i].erm_nspr;
+      break;
+    }
+  }
+  PR_SetError(nsprerr, oserrno);
+}
 
-  nsprerr = PR_GetError();
-
-  oserr = -1; /* unknown */
-  for (i = 0; prldap_errormap[i].erm_nspr != PR_MAX_ERROR; ++i) {
+/**
+ *  Get the NSPR error code, converted to an appropriate os errno.
+ *
+ *  @returns an os errno value to approximate the current NSPR error code.
+ */
+int prldap_get_errno(void) {
+  PRErrorCode nsprerr = PR_GetError();
+  int oserr = -1; /* unknown */
+  for (int i = 0; prldap_errormap[i].erm_nspr != PR_MAX_ERROR; ++i) {
     if (prldap_errormap[i].erm_nspr == nsprerr) {
       oserr = prldap_errormap[i].erm_system;
       break;
     }
   }
-
-  return (oserr);
+  return oserr;
 }
--- a/ldap/c-sdk/libraries/libprldap/ldappr-int.h
+++ b/ldap/c-sdk/libraries/libprldap/ldappr-int.h
@@ -126,11 +126,10 @@ void prldap_thread_dispose_handle(LDAP *
 /*
  * From ldapprdns.c:
  */
 int prldap_install_dns_functions(LDAP *ld);
 
 /*
  * From ldapprerror.c:
  */
-void prldap_set_system_errno(int e);
-int prldap_get_system_errno(void);
-int prldap_prerr2errno(void);
+void prldap_set_errno(int e);
+int prldap_get_errno(void);
--- a/ldap/c-sdk/libraries/libprldap/ldappr-io.c
+++ b/ldap/c-sdk/libraries/libprldap/ldappr-io.c
@@ -233,27 +233,27 @@ static struct prldap_eventmap_entry prld
 static int LDAP_CALLBACK
 prldap_poll(LDAP_X_PollFD fds[], int nfds, int timeout,
             struct lextiof_session_private *sessionarg) {
   PRLDAPIOSessionArg *prsessp = sessionarg;
   PRPollDesc *pds;
   int i, j, rc;
 
   if (NULL == prsessp) {
-    prldap_set_system_errno(EINVAL);
+    // Make sure prldap_get_errno() returns an error.
+    PR_SetError(PR_INVALID_ARGUMENT_ERROR, EINVAL);
     return (-1);
   }
 
   /* allocate or resize NSPR poll descriptor array */
   if (prsessp->prsess_pollds_count < nfds) {
     pds = prldap_safe_realloc(
         prsessp->prsess_pollds,
         (nfds + PRLDAP_POLL_ARRAY_GROWTH) * sizeof(PRPollDesc));
     if (NULL == pds) {
-      prldap_set_system_errno(prldap_prerr2errno());
       return (-1);
     }
     prsessp->prsess_pollds = pds;
     prsessp->prsess_pollds_count = nfds + PRLDAP_POLL_ARRAY_GROWTH;
   } else {
     pds = prsessp->prsess_pollds;
   }
 
@@ -312,17 +312,16 @@ static int prldap_try_one_address(struct
    * Set nonblocking option if requested:
    */
   if (0 != (options & LDAP_X_EXTIOF_OPT_NONBLOCKING)) {
     PRSocketOptionData optdata;
 
     optdata.option = PR_SockOpt_Nonblocking;
     optdata.value.non_blocking = PR_TRUE;
     if (PR_SetSocketOption(prsockp->prsock_prfd, &optdata) != PR_SUCCESS) {
-      prldap_set_system_errno(prldap_prerr2errno());
       PR_Close(prsockp->prsock_prfd);
       return (-1);
     }
   }
 
 #ifdef PRLDAP_DEBUG
   {
     char buf[256], *p, *fmtstr;
@@ -374,22 +373,22 @@ static int LDAP_CALLBACK prldap_connect(
   int rc, parse_err, port;
   char *host;
   struct ldap_x_hostlist_status *status;
   struct lextiof_socket_private *prsockp;
   PRNetAddr addr;
   PRAddrInfo *infop = NULL;
 
   if (0 != (options & LDAP_X_EXTIOF_OPT_SECURE)) {
-    prldap_set_system_errno(EINVAL);
+    // Make sure prldap_get_errno() returns an error.
+    PR_SetError(PR_INVALID_ARGUMENT_ERROR, EINVAL);
     return (-1);
   }
 
   if (NULL == (prsockp = prldap_socket_arg_alloc(sessionarg))) {
-    prldap_set_system_errno(prldap_prerr2errno());
     return (-1);
   }
 
   rc = -1; /* pessimistic */
   for (parse_err =
            ldap_x_hostlist_first(hostlist, defport, &host, &port, &status);
        rc < 0 && LDAP_SUCCESS == parse_err && NULL != host;
        parse_err = ldap_x_hostlist_next(&host, &port, status)) {
@@ -422,33 +421,31 @@ static int LDAP_CALLBACK prldap_connect(
   }
 
   if (host) {
     ldap_memfree(host);
   }
   ldap_x_hostlist_statusfree(status);
 
   if (rc < 0) {
-    prldap_set_system_errno(prldap_prerr2errno());
     prldap_socket_arg_free(&prsockp);
   } else {
     *socketargp = prsockp;
   }
 
   return (rc);
 }
 
 static int LDAP_CALLBACK
 prldap_close(int s, struct lextiof_socket_private *socketarg) {
   int rc;
 
   rc = 0;
   if (PR_Close(PRLDAP_GET_PRFD(socketarg)) != PR_SUCCESS) {
     rc = -1;
-    prldap_set_system_errno(prldap_prerr2errno());
   }
   prldap_socket_arg_free(&socketarg);
 
   return (rc);
 }
 
 /*
  * LDAP session handle creation callback.
--- a/ldap/c-sdk/libraries/libprldap/ldappr-public.c
+++ b/ldap/c-sdk/libraries/libprldap/ldappr-public.c
@@ -55,17 +55,18 @@
  *
  * prldap_init() returns an LDAP session handle (or NULL if an error occurs).
  */
 LDAP *LDAP_CALL prldap_init(const char *defhost, int defport, int shared) {
   LDAP *ld;
 
   if ((ld = ldap_init(defhost, defport)) != NULL) {
     if (prldap_install_routines(ld, shared) != LDAP_SUCCESS) {
-      prldap_set_system_errno(EINVAL); /* XXXmcs: just a guess! */
+      // Make sure prldap_get_errno() returns an error.
+      PR_SetError(PR_UNKNOWN_ERROR, EINVAL);
       ldap_unbind(ld);
       ld = NULL;
     }
   }
 
   return (ld);
 }
 
--- a/ldap/c-sdk/libraries/libprldap/ldappr-threads.c
+++ b/ldap/c-sdk/libraries/libprldap/ldappr-threads.c
@@ -154,18 +154,18 @@ int prldap_install_thread_functions(LDAP
 
   if (PR_CallOnce(&prldap_callonce_init_tpd, prldap_init_tpd) != PR_SUCCESS) {
     ldap_set_lderrno(ld, LDAP_LOCAL_ERROR, NULL, NULL);
     return (-1);
   }
 
   /* set thread function pointers */
   memset(&tfns, '\0', sizeof(struct ldap_thread_fns));
-  tfns.ltf_get_errno = prldap_get_system_errno;
-  tfns.ltf_set_errno = prldap_set_system_errno;
+  tfns.ltf_get_errno = prldap_get_errno;
+  tfns.ltf_set_errno = prldap_set_errno;
   if (shared) {
     tfns.ltf_mutex_alloc = prldap_mutex_alloc;
     tfns.ltf_mutex_free = prldap_mutex_free;
     tfns.ltf_mutex_lock = prldap_mutex_lock;
     tfns.ltf_mutex_unlock = prldap_mutex_unlock;
     tfns.ltf_get_lderrno = prldap_get_ld_error;
     tfns.ltf_set_lderrno = prldap_set_ld_error;
     if (ld != NULL) {