Bug 1420407, land NSPR 4.18.1 beta1 (r=me) and remove local NSPR patch that's no longer necessary (r=dragana)
☠☠ backed out by b97b62055f10 ☠ ☠
authorKai Engert <kaie@kuix.de>
Mon, 27 Nov 2017 21:01:35 +0100
changeset 703830 f7f814a5a9577b545036f9be69aeb5293d8feda0
parent 703829 afefcc7ecca06203a0ea46f4f6949ab509911c93
child 703831 4e5b62d139a83ea164cb4ae52e3a5b60de732a1f
push id90984
push userbmo:gl@mozilla.com
push dateMon, 27 Nov 2017 20:54:52 +0000
reviewersme, dragana
bugs1420407
milestone59.0a1
Bug 1420407, land NSPR 4.18.1 beta1 (r=me) and remove local NSPR patch that's no longer necessary (r=dragana) UPGRADE_NSPR_RELEASE
nsprpub/TAG-INFO
nsprpub/config/prdepend.h
nsprpub/configure
nsprpub/configure.in
nsprpub/patches/README.TXT
nsprpub/patches/bug1399100-temporary.patch
nsprpub/pr/include/prinit.h
nsprpub/pr/include/private/pprio.h
nsprpub/pr/include/private/primpl.h
nsprpub/pr/src/io/prio.c
nsprpub/pr/src/io/prsocket.c
nsprpub/pr/src/md/windows/w95sock.c
nsprpub/pr/src/md/windows/w95thred.c
nsprpub/pr/src/nspr.def
nsprpub/pr/src/pthreads/ptio.c
nsprpub/pr/src/pthreads/ptthread.c
nsprpub/pr/tests/vercheck.c
--- a/nsprpub/TAG-INFO
+++ b/nsprpub/TAG-INFO
@@ -1,1 +1,1 @@
-NSPR_4_17_RTM
+NSPR_4_18_BETA1
--- a/nsprpub/config/prdepend.h
+++ b/nsprpub/config/prdepend.h
@@ -5,8 +5,9 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSPR in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
+
--- a/nsprpub/configure
+++ b/nsprpub/configure
@@ -2483,17 +2483,17 @@ case $target_os in *\ *) target_os=`echo
 # The aliases save the names the user supplied, while $host etc.
 # will get canonicalized.
 test -n "$target_alias" &&
   test "$program_prefix$program_suffix$program_transform_name" = \
     NONENONEs,x,x, &&
   program_prefix=${target_alias}-
 
 MOD_MAJOR_VERSION=4
-MOD_MINOR_VERSION=17
+MOD_MINOR_VERSION=18
 MOD_PATCH_VERSION=0
 NSPR_MODNAME=nspr20
 _HAVE_PTHREADS=
 USE_PTHREADS=
 USE_USER_PTHREADS=
 USE_NSPR_THREADS=
 USE_N32=
 USE_X32=
--- a/nsprpub/configure.in
+++ b/nsprpub/configure.in
@@ -10,17 +10,17 @@ AC_CONFIG_SRCDIR([pr/include/nspr.h])
 
 AC_CONFIG_AUX_DIR(${srcdir}/build/autoconf)
 AC_CANONICAL_TARGET
 
 dnl ========================================================
 dnl = Defaults
 dnl ========================================================
 MOD_MAJOR_VERSION=4
-MOD_MINOR_VERSION=17
+MOD_MINOR_VERSION=18
 MOD_PATCH_VERSION=0
 NSPR_MODNAME=nspr20
 _HAVE_PTHREADS=
 USE_PTHREADS=
 USE_USER_PTHREADS=
 USE_NSPR_THREADS=
 USE_N32=
 USE_X32=
deleted file mode 100644
--- a/nsprpub/patches/README.TXT
+++ /dev/null
@@ -1,9 +0,0 @@
-bug1399100-temporary.patch :
-  This is a temporary patch as described in
-    https://bugzilla.mozilla.org/show_bug.cgi?id=1399100
-  It is temporarily necessary because of the changes in
-    https://bugzilla.mozilla.org/show_bug.cgi?id=1384633
-  The patch should be re-applied during the Firefox 57 release cycle,
-  if other changes to NSPR are necessary during the lifetime of Firefox 57.
-  The temporary API will be removed for Firefox 58, as agreed in
-    https://bugzilla.mozilla.org/show_bug.cgi?id=1394808
deleted file mode 100644
--- a/nsprpub/patches/bug1399100-temporary.patch
+++ /dev/null
@@ -1,16 +0,0 @@
-diff --git a/nsprpub/pr/src/nspr.def b/nsprpub/pr/src/nspr.def
---- a/nsprpub/pr/src/nspr.def
-+++ b/nsprpub/pr/src/nspr.def
-@@ -457,8 +457,12 @@ EXPORTS ;-
- ;+} NSPR_4.9.2;
- ;+# Function PR_DuplicateEnvironment had been added in NSPR 4.10.9,
- ;+# but we neglected to add it to nspr.def until NSPR 4.12
- ;+NSPR_4.12 {
- ;+      global:
- 		PR_DuplicateEnvironment;
- 		PR_GetEnvSecure;
- ;+} NSPR_4.10.3;
-+;+NSPR_4.17_fork {
-+;+      global:
-+		PR_EXPERIMENTAL_ONLY_IN_4_17_GetOverlappedIOHandle;
-+;+} NSPR_4.16;
--- a/nsprpub/pr/include/prinit.h
+++ b/nsprpub/pr/include/prinit.h
@@ -26,21 +26,21 @@ PR_BEGIN_EXTERN_C
 /*
 ** NSPR's version is used to determine the likelihood that the version you
 ** used to build your component is anywhere close to being compatible with
 ** what is in the underlying library.
 **
 ** The format of the version string is
 **     "<major version>.<minor version>[.<patch level>] [<Beta>]"
 */
-#define PR_VERSION  "4.17"
+#define PR_VERSION  "4.18 Beta"
 #define PR_VMAJOR   4
-#define PR_VMINOR   17
+#define PR_VMINOR   18
 #define PR_VPATCH   0
-#define PR_BETA     PR_FALSE
+#define PR_BETA     PR_TRUE
 
 /*
 ** PRVersionCheck
 **
 ** The basic signature of the function that is called to provide version
 ** checking. The result will be a boolean that indicates the likelihood
 ** that the underling library will perform as the caller expects.
 **
--- a/nsprpub/pr/include/private/pprio.h
+++ b/nsprpub/pr/include/private/pprio.h
@@ -232,25 +232,11 @@ NSPR_API(void) PR_NTFast_UpdateAcceptCon
 ** DESCRIPTION:
 **    Cancel IO operations on fd.
 */
 NSPR_API(PRStatus) PR_NT_CancelIo(PRFileDesc *fd);
 
 
 #endif /* WIN32 */
 
-/* FUNCTION: PR_EXPERIMENTAL_ONLY_IN_4_17_GetOverlappedIOHandle
-** DESCRIPTION:
-** This function will be available only in nspr version 4.17
-** This functionality is only available on windows. Some windows operation use
-** asynchronous (call overlapped) io. One of them is ConnectEx. NSPR uses
-** ConnectEx for enabling TCP Fast Open.
-** This function returns an OVERLAPPED structure associated with ConnectEx call.
-** If ConnectEx has not been called or the io has already finished, the
-** function will return PR_INVALID_ARGUMENT_ERROR.
-** PRFileDesc continues to be owner of the structure and the structure must not
-** be destroyed.
-*/
-NSPR_API(PRStatus) PR_EXPERIMENTAL_ONLY_IN_4_17_GetOverlappedIOHandle(PRFileDesc *fd, void **ol);
-
 PR_END_EXTERN_C
 
 #endif /* pprio_h___ */
--- a/nsprpub/pr/include/private/primpl.h
+++ b/nsprpub/pr/include/private/primpl.h
@@ -2160,11 +2160,23 @@ typedef struct _ConnectListNode {
 } ConnectListNode;
 
 extern ConnectListNode connectList[64];
 
 extern PRUint32 connectCount;
 
 #endif /* XP_BEOS */
 
+#if defined(_WIN64) && defined(WIN95)
+typedef struct _PRFileDescList {
+  PRFileDesc *fd;
+  struct _PRFileDescList *next;
+} PRFileDescList;
+
+extern PRLock *_fd_waiting_for_overlapped_done_lock;
+extern PRFileDescList *_fd_waiting_for_overlapped_done;
+extern void CheckOverlappedPendingSocketsAreDone();
+#endif
+
+
 PR_END_EXTERN_C
 
 #endif /* primpl_h___ */
--- a/nsprpub/pr/src/io/prio.c
+++ b/nsprpub/pr/src/io/prio.c
@@ -132,21 +132,92 @@ PR_IMPLEMENT(PRFileDesc*) PR_AllocFileDe
 }
 
 PR_IMPLEMENT(void) PR_FreeFileDesc(PRFileDesc *fd)
 {
     PR_ASSERT(fd);
     _PR_Putfd(fd);
 }
 
+#if defined(_WIN64) && defined(WIN95)
+
+PRFileDescList *_fd_waiting_for_overlapped_done = NULL;
+PRLock *_fd_waiting_for_overlapped_done_lock = NULL;
+
+void CheckOverlappedPendingSocketsAreDone()
+{
+  if (!_fd_waiting_for_overlapped_done_lock ||
+      !_fd_waiting_for_overlapped_done) {
+    return;
+  }
+
+  PR_Lock(_fd_waiting_for_overlapped_done_lock);
+
+  PRFileDescList *cur = _fd_waiting_for_overlapped_done;
+  PRFileDescList *previous = NULL;
+  while (cur) {
+    PR_ASSERT(cur->fd->secret->overlappedActive);
+    PRFileDesc *fd = cur->fd;
+    DWORD rvSent;
+    if (GetOverlappedResult((HANDLE)fd->secret->md.osfd, &fd->secret->ol, &rvSent, FALSE) == TRUE) {
+      fd->secret->overlappedActive = PR_FALSE;
+      PR_LOG(_pr_io_lm, PR_LOG_MIN,
+             ("CheckOverlappedPendingSocketsAreDone GetOverlappedResult succeeded\n"));
+    } else {
+      DWORD err = WSAGetLastError();
+      PR_LOG(_pr_io_lm, PR_LOG_MIN,
+             ("CheckOverlappedPendingSocketsAreDone GetOverlappedResult failed %d\n", err));
+      if (err != ERROR_IO_INCOMPLETE) {
+        fd->secret->overlappedActive = PR_FALSE;
+      }
+    }
+
+    if (!fd->secret->overlappedActive) {
+
+      _PR_MD_CLOSE_SOCKET(fd->secret->md.osfd);
+      fd->secret->state = _PR_FILEDESC_CLOSED;
+#ifdef _PR_HAVE_PEEK_BUFFER
+      if (fd->secret->peekBuffer) {
+        PR_ASSERT(fd->secret->peekBufSize > 0);
+        PR_DELETE(fd->secret->peekBuffer);
+        fd->secret->peekBufSize = 0;
+        fd->secret->peekBytes = 0;
+      }
+#endif
+
+      PR_FreeFileDesc(fd);
+
+      if (previous) {
+        previous->next = cur->next;
+      } else {
+        _fd_waiting_for_overlapped_done = cur->next;
+      }
+      PRFileDescList *del = cur;
+      cur = cur->next;
+      PR_Free(del);
+    } else {
+      previous = cur;
+      cur = cur->next;
+    }
+  }
+
+  PR_Unlock(_fd_waiting_for_overlapped_done_lock);
+}
+#endif
+
 /*
 ** Wait for some i/o to finish on one or more more poll descriptors.
 */
 PR_IMPLEMENT(PRInt32) PR_Poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
 {
+#if defined(_WIN64) && defined(WIN95)
+  // For each iteration check if TFO overlapped IOs are down.
+  CheckOverlappedPendingSocketsAreDone();
+#endif
+
 	return(_PR_MD_PR_POLL(pds, npds, timeout));
 }
 
 /*
 ** Set the inheritance attribute of a file descriptor.
 */
 PR_IMPLEMENT(PRStatus) PR_SetFDInheritable(
     PRFileDesc *fd,
--- a/nsprpub/pr/src/io/prsocket.c
+++ b/nsprpub/pr/src/io/prsocket.c
@@ -732,16 +732,66 @@ static PRStatus PR_CALLBACK SocketClose(
 	if (!fd || !fd->secret
 			|| (fd->secret->state != _PR_FILEDESC_OPEN
 			&& fd->secret->state != _PR_FILEDESC_CLOSED)) {
 		PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
 		return PR_FAILURE;
 	}
 
 	if (fd->secret->state == _PR_FILEDESC_OPEN) {
+#if defined(_WIN64) && defined(WIN95)
+    /* TCP Fast Open on Windows must use ConnectEx, which uses overlapped
+     * input/output. Before closing such a socket we must cancelIO.
+     */
+    if (fd->secret->overlappedActive) {
+      PR_ASSERT(fd->secret->nonblocking);
+      if (CancelIo((HANDLE) fd->secret->md.osfd) == TRUE) {
+        PR_LOG(_pr_io_lm, PR_LOG_MIN,
+               ("SocketClose - CancelIo succeeded\n"));
+      } else {
+        DWORD err = WSAGetLastError();
+        PR_LOG(_pr_io_lm, PR_LOG_MIN,
+               ("SocketClose - CancelIo failed err=%x\n", err));
+      }
+
+      DWORD rvSent;
+      if (GetOverlappedResult((HANDLE)fd->secret->md.osfd, &fd->secret->ol, &rvSent, FALSE) == TRUE) {
+        fd->secret->overlappedActive = PR_FALSE;
+        PR_LOG(_pr_io_lm, PR_LOG_MIN,
+               ("SocketClose GetOverlappedResult succeeded\n"));
+      } else {
+        DWORD err = WSAGetLastError();
+        PR_LOG(_pr_io_lm, PR_LOG_MIN,
+               ("SocketClose GetOverlappedResult failed %d\n", err));
+        if (err != ERROR_IO_INCOMPLETE) {
+          _PR_MD_MAP_CONNECT_ERROR(err);
+          fd->secret->overlappedActive = PR_FALSE;
+        }
+      }
+    }
+
+    if (fd->secret->overlappedActive &&
+        _fd_waiting_for_overlapped_done_lock) {
+      // Put osfd into the list to be checked later.
+      PRFileDescList *forWaiting = PR_NEW(PRFileDescList);
+      if (!forWaiting) {
+        PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+        return PR_FAILURE;
+      }
+      forWaiting->fd = fd;
+
+      PR_Lock(_fd_waiting_for_overlapped_done_lock);
+      forWaiting->next = _fd_waiting_for_overlapped_done;
+      _fd_waiting_for_overlapped_done = forWaiting;
+      PR_Unlock(_fd_waiting_for_overlapped_done_lock);
+
+      return PR_SUCCESS;
+    }
+#endif
+
 		if (_PR_MD_CLOSE_SOCKET(fd->secret->md.osfd) < 0) {
 			return PR_FAILURE;
 		}
 		fd->secret->state = _PR_FILEDESC_CLOSED;
 	}
 
 #ifdef _PR_HAVE_PEEK_BUFFER
 	if (fd->secret->peekBuffer) {
@@ -1679,43 +1729,16 @@ PR_FileDesc2NativeHandle(PRFileDesc *fd)
 
 PR_IMPLEMENT(void)
 PR_ChangeFileDescNativeHandle(PRFileDesc *fd, PROsfd handle)
 {
 	if (fd)
 		fd->secret->md.osfd = handle;
 }
 
-/* Expose OVERLAPPED if present. OVERLAPPED is implemented only on WIN95. */
-PR_IMPLEMENT(PRStatus)
-PR_EXPERIMENTAL_ONLY_IN_4_17_GetOverlappedIOHandle(PRFileDesc *fd, void **ol)
-{
-#if defined(_WIN64) && defined(WIN95)
-    *ol = NULL;
-    if (fd) {
-        fd = PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER);
-    }
-    if (!fd) {
-        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
-        return PR_FAILURE;
-    }
-
-    if (!fd->secret->overlappedActive) {
-        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
-        return PR_FAILURE;
-    }
-
-    *ol = &fd->secret->ol;
-    return PR_SUCCESS;
-#else
-    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
-    return PR_FAILURE;
-#endif
-}
-
 /*
 ** Select compatibility
 **
 */
 
 PR_IMPLEMENT(void) PR_FD_ZERO(PR_fd_set *set)
 {
 	memset(set, 0, sizeof(PR_fd_set));
--- a/nsprpub/pr/src/md/windows/w95sock.c
+++ b/nsprpub/pr/src/md/windows/w95sock.c
@@ -377,16 +377,21 @@ static PRStatus PR_CALLBACK _pr_set_conn
     rc = closesocket(sock);
     return PR_SUCCESS;
 }
 
 PRInt32
 _PR_MD_TCPSENDTO(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
                  const PRNetAddr *addr, PRUint32 addrlen, PRIntervalTime timeout)
 {
+    if (!_fd_waiting_for_overlapped_done_lock) {
+        PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
+        return PR_FAILURE;
+    }
+
     if (PR_CallOnce(&_pr_has_connectex_once, _pr_set_connectex) != PR_SUCCESS) {
         PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
         return PR_FAILURE;
     }
 
     if (_pr_win_connectex == NULL) {
         PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
         return PR_FAILURE;
--- a/nsprpub/pr/src/md/windows/w95thred.c
+++ b/nsprpub/pr/src/md/windows/w95thred.c
@@ -30,31 +30,58 @@ int                           _pr_intsOf
 void
 _PR_MD_EARLY_INIT()
 {
 #ifndef _PR_USE_STATIC_TLS
     _pr_currentThreadIndex = TlsAlloc();
     _pr_lastThreadIndex = TlsAlloc();
     _pr_currentCPUIndex = TlsAlloc();
 #endif
+
+#if defined(_WIN64) && defined(WIN95)
+    _fd_waiting_for_overlapped_done_lock = PR_NewLock();
+#endif
 }
 
 void _PR_MD_CLEANUP_BEFORE_EXIT(void)
 {
     _PR_NT_FreeSids();
 
     _PR_MD_CleanupSockets();
 
     WSACleanup();
 
 #ifndef _PR_USE_STATIC_TLS
     TlsFree(_pr_currentThreadIndex);
     TlsFree(_pr_lastThreadIndex);
     TlsFree(_pr_currentCPUIndex);
 #endif
+
+#if defined(_WIN64) && defined(WIN95)
+    // For each iteration check if TFO overlapped IOs are down.
+    if (_fd_waiting_for_overlapped_done_lock) {
+        PRIntervalTime delay = PR_MillisecondsToInterval(1000);
+        PRFileDescList *cur;
+        do {
+            CheckOverlappedPendingSocketsAreDone();
+
+            PR_Lock(_fd_waiting_for_overlapped_done_lock);
+            cur = _fd_waiting_for_overlapped_done;
+            PR_Unlock(_fd_waiting_for_overlapped_done_lock);
+#if define DO_NOT_WAIT_FOR_CONNECT_OVERLAPPED_OPERATIONS
+            cur = NULL;
+#endif
+            if (cur) {
+                PR_Sleep(delay); // wait another 1s.
+            }
+        } while (cur);
+
+        PR_DestroyLock(_fd_waiting_for_overlapped_done_lock);
+    }
+#endif
 }
 
 PRStatus
 _PR_MD_INIT_THREAD(PRThread *thread)
 {
     if (thread->flags & (_PR_PRIMORDIAL | _PR_ATTACHED)) {
         /*
         ** Warning:
--- a/nsprpub/pr/src/nspr.def
+++ b/nsprpub/pr/src/nspr.def
@@ -457,12 +457,8 @@ EXPORTS ;-
 ;+} NSPR_4.9.2;
 ;+# Function PR_DuplicateEnvironment had been added in NSPR 4.10.9,
 ;+# but we neglected to add it to nspr.def until NSPR 4.12
 ;+NSPR_4.12 {
 ;+      global:
 		PR_DuplicateEnvironment;
 		PR_GetEnvSecure;
 ;+} NSPR_4.10.3;
-;+NSPR_4.17_fork {
-;+      global:
-		PR_EXPERIMENTAL_ONLY_IN_4_17_GetOverlappedIOHandle;
-;+} NSPR_4.16;
--- a/nsprpub/pr/src/pthreads/ptio.c
+++ b/nsprpub/pr/src/pthreads/ptio.c
@@ -4739,24 +4739,16 @@ PR_IMPLEMENT(PRInt32) PR_FileDesc2Native
     PRInt32 osfd = -1;
     bottom = (NULL == bottom) ?
         NULL : PR_GetIdentitiesLayer(bottom, PR_NSPR_IO_LAYER);
     if (NULL == bottom) PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
     else osfd = bottom->secret->md.osfd;
     return osfd;
 }  /* PR_FileDesc2NativeHandle */
 
-/* Expose OVERLAPPED if present. OVERLAPPED is implemented only on WIN95. */
-PR_IMPLEMENT(PRStatus)
-PR_EXPERIMENTAL_ONLY_IN_4_17_GetOverlappedIOHandle(PRFileDesc *fd, void **ol)
-{
-    PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
-    return PR_FAILURE;
-}
-
 PR_IMPLEMENT(void) PR_ChangeFileDescNativeHandle(PRFileDesc *fd,
     PRInt32 handle)
 {
     if (fd) fd->secret->md.osfd = handle;
 }  /*  PR_ChangeFileDescNativeHandle*/
 
 PR_IMPLEMENT(PRStatus) PR_LockFile(PRFileDesc *fd)
 {
--- a/nsprpub/pr/src/pthreads/ptthread.c
+++ b/nsprpub/pr/src/pthreads/ptthread.c
@@ -1059,16 +1059,21 @@ void PR_HPUX10xInit(shl_t handle, int lo
 }
 #endif
 #elif defined(AIX)
 /* Need to use the -binitfini::_PR_Fini linker option. */
 #endif
 
 void _PR_Fini(void)
 {
+    /* We disable the cleanup code on Mac OSX, see bug 1399746.
+     * The .dylib containing NSPR can get unloaded, and _PR_Fini called,
+     * and other code calling NSPR functions can get executed afterwards.
+    */
+#ifndef DARWIN
     void *thred;
     int rv;
 
     if (!_pr_initialized) {
         /* Either NSPR was never successfully initialized or 
          * PR_Cleanup has been called already. */
         if (pt_book.keyCreated)
         {
@@ -1090,16 +1095,17 @@ void _PR_Fini(void)
         rv = pthread_setspecific(pt_book.key, NULL);
         PR_ASSERT(0 == rv);
     }
     rv = pthread_key_delete(pt_book.key);
     PR_ASSERT(0 == rv);
     pt_book.keyCreated = PR_FALSE;
     /* TODO: free other resources used by NSPR */
     /* _pr_initialized = PR_FALSE; */
+#endif
 }  /* _PR_Fini */
 
 PR_IMPLEMENT(PRStatus) PR_Cleanup(void)
 {
     PRThread *me = PR_GetCurrentThread();
     int rv;
     PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("PR_Cleanup: shutting down NSPR"));
     PR_ASSERT(me->state & PT_THREAD_PRIMORD);
--- a/nsprpub/pr/tests/vercheck.c
+++ b/nsprpub/pr/tests/vercheck.c
@@ -35,34 +35,34 @@ static char *compatible_version[] = {
     "4.7.6",
     "4.8", "4.8.1", "4.8.2", "4.8.3", "4.8.4", "4.8.5",
     "4.8.6", "4.8.7", "4.8.8", "4.8.9",
     "4.9", "4.9.1", "4.9.2", "4.9.3", "4.9.4", "4.9.5",
     "4.9.6",
     "4.10", "4.10.1", "4.10.2", "4.10.3", "4.10.4",
     "4.10.5", "4.10.6", "4.10.7", "4.10.8", "4.10.9",
     "4.10.10", "4.11", "4.12", "4.13", "4.14", "4.15",
-    "4.16",
+    "4.16", "4.17",
     PR_VERSION
 };
 
 /*
  * This release is not backward compatible with the old
  * NSPR 2.1 and 3.x releases.
  *
  * Any release is incompatible with future releases and
  * patches.
  */
 static char *incompatible_version[] = {
     "2.1 19980529",
     "3.0", "3.0.1",
     "3.1", "3.1.1", "3.1.2", "3.1.3",
     "3.5", "3.5.1",
-    "4.17.1",
-    "4.18", "4.18.1",
+    "4.18.1",
+    "4.19", "4.19.1",
     "10.0", "11.1", "12.14.20"
 };
 
 int main(int argc, char **argv)
 {
     int idx;
     int num_compatible = sizeof(compatible_version) / sizeof(char *);
     int num_incompatible = sizeof(incompatible_version) / sizeof(char *);