From f3f1cc024f9a94edd14dd77e7f3b59dcebcd04ce Mon Sep 17 00:00:00 2001
From: "larryh%netscape.com" <larryh%netscape.com>
Date: Thu, 22 Jun 2000 19:46:28 +0000
Subject: [PATCH] BugZilla: 39942. PR_SetError() calls free()

---
 nsprpub/pr/include/private/primpl.h |   3 +-
 nsprpub/pr/src/misc/prerror.c       |  24 ++--
 nsprpub/pr/tests/Makefile           |   1 +
 nsprpub/pr/tests/errset.c           | 183 ++++++++++++++++++++++++++++
 4 files changed, 201 insertions(+), 10 deletions(-)
 create mode 100644 nsprpub/pr/tests/errset.c

diff --git a/nsprpub/pr/include/private/primpl.h b/nsprpub/pr/include/private/primpl.h
index dc95e4d8e60ee..754d02946f6c4 100644
--- a/nsprpub/pr/include/private/primpl.h
+++ b/nsprpub/pr/include/private/primpl.h
@@ -1524,9 +1524,10 @@ struct PRThread {
     */
     PRUint32 tpdLength;             /* thread's current vector length */
     void **privateData;             /* private data vector or NULL */
-    PRInt32 errorStringSize;        /* byte length of current error string | zero */
     PRErrorCode errorCode;          /* current NSPR error code | zero */
     PRInt32 osErrorCode;            /* mapping of errorCode | zero */
+    PRIntn  errorStringLength;      /* textLength from last call to PR_SetErrorText() */
+    PRInt32 errorStringSize;        /* malloc()'d size of buffer | zero */
     char *errorString;              /* current error string | NULL */
 
 #if defined(_PR_PTHREADS)
diff --git a/nsprpub/pr/src/misc/prerror.c b/nsprpub/pr/src/misc/prerror.c
index 73404cd172ef7..9840565c6403b 100644
--- a/nsprpub/pr/src/misc/prerror.c
+++ b/nsprpub/pr/src/misc/prerror.c
@@ -54,8 +54,7 @@ PR_IMPLEMENT(void) PR_SetError(PRErrorCode code, PRInt32 osErr)
     PRThread *thread = PR_GetCurrentThread();
     thread->errorCode = code;
     thread->osErrorCode = osErr;
-    thread->errorStringSize = 0;
-    PR_DELETE(thread->errorString);
+    thread->errorStringLength = 0;
 }
 
 PR_IMPLEMENT(void) PR_SetErrorText(PRIntn textLength, const char *text)
@@ -66,33 +65,40 @@ PR_IMPLEMENT(void) PR_SetErrorText(PRIntn textLength, const char *text)
     {
 	    if (NULL != thread->errorString)
 	        PR_DELETE(thread->errorString);
+            thread->errorStringSize = 0;
     }
     else
     {
-	    PRIntn size = textLength + 1;  /* actual length to allocate */
-        if (thread->errorStringSize < textLength)  /* do we have room? */
+	    PRIntn size = textLength + 31;  /* actual length to allocate. Plus a little extra */
+        if (thread->errorStringSize < textLength+1)  /* do we have room? */
         {
 	        if (NULL != thread->errorString)
 	            PR_DELETE(thread->errorString);
 		    thread->errorString = (char*)PR_MALLOC(size);
+            if ( NULL == thread->errorString ) {
+                thread->errorStringSize = 0;
+                thread->errorStringLength = 0;
+                return;
+            }
+            thread->errorStringSize = size;
 	    }
-        memcpy(thread->errorString, text, size);
+        thread->errorStringLength = textLength;
+        memcpy(thread->errorString, text, textLength+1 );
     }
-    thread->errorStringSize = textLength;
 }
 
 PR_IMPLEMENT(PRInt32) PR_GetErrorTextLength(void)
 {
     PRThread *thread = PR_GetCurrentThread();
-    return thread->errorStringSize;
+    return thread->errorStringLength;
 }  /* PR_GetErrorTextLength */
 
 PR_IMPLEMENT(PRInt32) PR_GetErrorText(char *text)
 {
     PRThread *thread = PR_GetCurrentThread();
     if (0 != thread->errorStringSize)
-        memcpy(text, thread->errorString, thread->errorStringSize + 1);
-    return thread->errorStringSize;
+        memcpy(text, thread->errorString, thread->errorStringLength+1);
+    return thread->errorStringLength;
 }  /* PR_GetErrorText */
 
 
diff --git a/nsprpub/pr/tests/Makefile b/nsprpub/pr/tests/Makefile
index eedf9a465f061..825c36a4e3931 100644
--- a/nsprpub/pr/tests/Makefile
+++ b/nsprpub/pr/tests/Makefile
@@ -74,6 +74,7 @@ CSRCS =             \
 	dlltest.c		\
 	dtoa.c			\
 	errcodes.c		\
+	errset.c		\
 	exit.c  		\
 	fdcach.c		\
 	fileio.c		\
diff --git a/nsprpub/pr/tests/errset.c b/nsprpub/pr/tests/errset.c
new file mode 100644
index 0000000000000..51c7b565a1f6c
--- /dev/null
+++ b/nsprpub/pr/tests/errset.c
@@ -0,0 +1,183 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ * 
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ * 
+ * The Original Code is the Netscape security libraries.
+ * 
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation.  Portions created by Netscape are 
+ * Copyright (C) 1998-2000 Netscape Communications Corporation.  All
+ * Rights Reserved.
+ * 
+ * Contributor(s):
+ * 
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable 
+ * instead of those above.  If you wish to allow use of your 
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL.  If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ */
+
+/***********************************************************************
+**
+** Name: errset.c
+**
+** Description: errset.c exercises the functions in prerror.c.
+** This code is a unit test of the prerror.c capability.
+**
+** Note: There's some fluff in here. The guts of the test
+** were plagerized from another test. So, sue me.
+**
+**
+*/
+#include "prerror.h"
+#include "plgetopt.h"
+#include "prlog.h"
+
+#include <stdio.h>
+#include <string.h>
+
+static int _debug_on = 0;
+
+struct errinfo {
+	PRErrorCode errcode;
+	char 		*errname;
+};
+
+struct errinfo errcodes[] = {
+{PR_OUT_OF_MEMORY_ERROR,			"PR_OUT_OF_MEMORY_ERROR"},
+{PR_UNKNOWN_ERROR, "An intentionally long error message text intended to force a delete of the current errorString buffer and get another one."},
+{PR_BAD_DESCRIPTOR_ERROR,			"PR_BAD_DESCRIPTOR_ERROR"},
+{PR_WOULD_BLOCK_ERROR,				"PR_WOULD_BLOCK_ERROR"},
+{PR_ACCESS_FAULT_ERROR,				"PR_ACCESS_FAULT_ERROR"},
+{PR_INVALID_METHOD_ERROR,			"PR_INVALID_METHOD_ERROR"},
+{PR_ILLEGAL_ACCESS_ERROR,			"PR_ILLEGAL_ACCESS_ERROR"},
+{PR_UNKNOWN_ERROR,					"PR_UNKNOWN_ERROR"},
+{PR_PENDING_INTERRUPT_ERROR,		"PR_PENDING_INTERRUPT_ERROR"},
+{PR_NOT_IMPLEMENTED_ERROR,			"PR_NOT_IMPLEMENTED_ERROR"},
+{PR_IO_ERROR,						"PR_IO_ERROR"},
+{PR_IO_TIMEOUT_ERROR,				"PR_IO_TIMEOUT_ERROR"},
+{PR_IO_PENDING_ERROR,				"PR_IO_PENDING_ERROR"},
+{PR_DIRECTORY_OPEN_ERROR,			"PR_DIRECTORY_OPEN_ERROR"},
+{PR_INVALID_ARGUMENT_ERROR,			"PR_INVALID_ARGUMENT_ERROR"},
+{PR_ADDRESS_NOT_AVAILABLE_ERROR,	"PR_ADDRESS_NOT_AVAILABLE_ERROR"},
+{PR_ADDRESS_NOT_SUPPORTED_ERROR,	"PR_ADDRESS_NOT_SUPPORTED_ERROR"},
+{PR_IS_CONNECTED_ERROR,				"PR_IS_CONNECTED_ERROR"},
+{PR_BAD_ADDRESS_ERROR,				"PR_BAD_ADDRESS_ERROR"},
+{PR_ADDRESS_IN_USE_ERROR,			"PR_ADDRESS_IN_USE_ERROR"},
+{PR_CONNECT_REFUSED_ERROR,			"PR_CONNECT_REFUSED_ERROR"},
+{PR_NETWORK_UNREACHABLE_ERROR,		"PR_NETWORK_UNREACHABLE_ERROR"},
+{PR_CONNECT_TIMEOUT_ERROR,			"PR_CONNECT_TIMEOUT_ERROR"},
+{PR_NOT_CONNECTED_ERROR,			"PR_NOT_CONNECTED_ERROR"},
+{PR_LOAD_LIBRARY_ERROR,				"PR_LOAD_LIBRARY_ERROR"},
+{PR_UNLOAD_LIBRARY_ERROR,			"PR_UNLOAD_LIBRARY_ERROR"},
+{PR_FIND_SYMBOL_ERROR,				"PR_FIND_SYMBOL_ERROR"},
+{PR_INSUFFICIENT_RESOURCES_ERROR,	"PR_INSUFFICIENT_RESOURCES_ERROR"},
+{PR_DIRECTORY_LOOKUP_ERROR,			"PR_DIRECTORY_LOOKUP_ERROR"},
+{PR_TPD_RANGE_ERROR,				"PR_TPD_RANGE_ERROR"},
+{PR_PROC_DESC_TABLE_FULL_ERROR,		"PR_PROC_DESC_TABLE_FULL_ERROR"},
+{PR_SYS_DESC_TABLE_FULL_ERROR,		"PR_SYS_DESC_TABLE_FULL_ERROR"},
+{PR_NOT_SOCKET_ERROR,				"PR_NOT_SOCKET_ERROR"},
+{PR_NOT_TCP_SOCKET_ERROR,			"PR_NOT_TCP_SOCKET_ERROR"},
+{PR_SOCKET_ADDRESS_IS_BOUND_ERROR,	"PR_SOCKET_ADDRESS_IS_BOUND_ERROR"},
+{PR_NO_ACCESS_RIGHTS_ERROR,			"PR_NO_ACCESS_RIGHTS_ERROR"},
+{PR_OPERATION_NOT_SUPPORTED_ERROR,	"PR_OPERATION_NOT_SUPPORTED_ERROR"},
+{PR_PROTOCOL_NOT_SUPPORTED_ERROR,	"PR_PROTOCOL_NOT_SUPPORTED_ERROR"},
+{PR_REMOTE_FILE_ERROR,				"PR_REMOTE_FILE_ERROR"},
+{PR_BUFFER_OVERFLOW_ERROR,			"PR_BUFFER_OVERFLOW_ERROR"},
+{PR_CONNECT_RESET_ERROR,			"PR_CONNECT_RESET_ERROR"},
+{PR_RANGE_ERROR,					"PR_RANGE_ERROR"},
+{PR_DEADLOCK_ERROR,					"PR_DEADLOCK_ERROR"},
+{PR_FILE_IS_LOCKED_ERROR,			"PR_FILE_IS_LOCKED_ERROR"},
+{PR_FILE_TOO_BIG_ERROR,				"PR_FILE_TOO_BIG_ERROR"},
+{PR_NO_DEVICE_SPACE_ERROR,			"PR_NO_DEVICE_SPACE_ERROR"},
+{PR_PIPE_ERROR,						"PR_PIPE_ERROR"},
+{PR_NO_SEEK_DEVICE_ERROR,			"PR_NO_SEEK_DEVICE_ERROR"},
+{PR_IS_DIRECTORY_ERROR,				"PR_IS_DIRECTORY_ERROR"},
+{PR_LOOP_ERROR,						"PR_LOOP_ERROR"},
+{PR_NAME_TOO_LONG_ERROR,			"PR_NAME_TOO_LONG_ERROR"},
+{PR_FILE_NOT_FOUND_ERROR,			"PR_FILE_NOT_FOUND_ERROR"},
+{PR_NOT_DIRECTORY_ERROR,			"PR_NOT_DIRECTORY_ERROR"},
+{PR_READ_ONLY_FILESYSTEM_ERROR,		"PR_READ_ONLY_FILESYSTEM_ERROR"},
+{PR_DIRECTORY_NOT_EMPTY_ERROR,		"PR_DIRECTORY_NOT_EMPTY_ERROR"},
+{PR_FILESYSTEM_MOUNTED_ERROR,		"PR_FILESYSTEM_MOUNTED_ERROR"},
+{PR_NOT_SAME_DEVICE_ERROR,			"PR_NOT_SAME_DEVICE_ERROR"},
+{PR_DIRECTORY_CORRUPTED_ERROR,		"PR_DIRECTORY_CORRUPTED_ERROR"},
+{PR_FILE_EXISTS_ERROR,				"PR_FILE_EXISTS_ERROR"},
+{PR_MAX_DIRECTORY_ENTRIES_ERROR,	"PR_MAX_DIRECTORY_ENTRIES_ERROR"},
+{PR_INVALID_DEVICE_STATE_ERROR,		"PR_INVALID_DEVICE_STATE_ERROR"},
+{PR_DEVICE_IS_LOCKED_ERROR,			"PR_DEVICE_IS_LOCKED_ERROR"},
+{PR_NO_MORE_FILES_ERROR,			"PR_NO_MORE_FILES_ERROR"},
+{PR_END_OF_FILE_ERROR,				"PR_END_OF_FILE_ERROR"},
+{PR_FILE_SEEK_ERROR,				"PR_FILE_SEEK_ERROR"},
+{PR_FILE_IS_BUSY_ERROR,				"PR_FILE_IS_BUSY_ERROR"},
+{PR_IN_PROGRESS_ERROR,				"PR_IN_PROGRESS_ERROR"},
+{PR_ALREADY_INITIATED_ERROR,		"PR_ALREADY_INITIATED_ERROR"},
+{PR_GROUP_EMPTY_ERROR,				"PR_GROUP_EMPTY_ERROR"},
+{PR_INVALID_STATE_ERROR,			"PR_INVALID_STATE_ERROR"},
+{PR_NETWORK_DOWN_ERROR,				"PR_NETWORK_DOWN_ERROR"},
+{PR_SOCKET_SHUTDOWN_ERROR,			"PR_SOCKET_SHUTDOWN_ERROR"},
+{PR_CONNECT_ABORTED_ERROR,			"PR_CONNECT_ABORTED_ERROR"},
+{PR_HOST_UNREACHABLE_ERROR,			"PR_HOST_UNREACHABLE_ERROR"}
+};
+
+int
+main(int argc, char **argv)
+{
+
+	int count, errnum;
+
+    /*
+     * -d           debug mode
+     */
+
+    PLOptStatus os;
+    PLOptState *opt = PL_CreateOptState(argc, argv, "d");
+    while (PL_OPT_EOL != (os = PL_GetNextOpt(opt)))
+    {
+        if (PL_OPT_BAD == os) continue;
+        switch (opt->option)
+        {
+        case 'd':  /* debug mode */
+            _debug_on = 1;
+            break;
+        default:
+            break;
+        }
+    }
+    PL_DestroyOptState(opt);
+
+	count = sizeof(errcodes)/sizeof(errcodes[0]);
+	printf("\nNumber of error codes = %d\n\n",count);
+	for (errnum = 0; errnum < count; errnum++) {
+        PRInt32 len1, len2, err;
+        char    msg[256];
+
+        PR_SetError( errnum, -5 );
+        err = PR_GetError();
+        PR_ASSERT( err == errnum );
+        err = PR_GetOSError();
+        PR_ASSERT( err == -5 );
+        PR_SetErrorText( strlen(errcodes[errnum].errname), errcodes[errnum].errname );
+        len1 = PR_GetErrorTextLength();
+        len2 = PR_GetErrorText( msg );
+        PR_ASSERT( len1 == len2 );
+        printf("%5.5d -- %s\n", errnum, msg );
+    }
+
+	return 0;
+}
-- 
GitLab