Subject: Restore API compatibility with public Tcl_*Scan and Tcl_*Convert functions (changes in private functions are OK) Increase LOCAL_SIZE to 64, and remove two Panic's which cannot occur any more as a result of the improvements.

From: "jan.nijtmans" <[email-masked]>
Date: Wed, 9 Jan 2013 12:33:45 +0000

---
 generic/tcl.decls    |  8 ++++----
 generic/tclDecls.h   | 16 ++++++++--------
 generic/tclDictObj.c |  7 ++-----
 generic/tclListObj.c |  4 ++--
 generic/tclUtil.c    | 32 +++++++-------------------------
 5 files changed, 23 insertions(+), 44 deletions(-)

diff --git a/generic/tcl.decls b/generic/tcl.decls
index 1084144..fe1d763 100644
--- a/generic/tcl.decls
+++ b/generic/tcl.decls
@@ -310,11 +310,11 @@ declare 83 {
     char *Tcl_Concat(int argc, const char *const *argv)
 }
 declare 84 {
-    int Tcl_ConvertElement(const char *src, char *dst, char flags)
+    int Tcl_ConvertElement(const char *src, char *dst, int flags)
 }
 declare 85 {
     int Tcl_ConvertCountedElement(const char *src, int length, char *dst,
-	    char flags)
+	    int flags)
 }
 declare 86 {
     int Tcl_CreateAlias(Tcl_Interp *slave, const char *slaveCmd,
@@ -778,10 +778,10 @@ declare 217 {
     void Tcl_ResetResult(Tcl_Interp *interp)
 }
 declare 218 {
-    int Tcl_ScanElement(const char *src, char *flagPtr)
+    int Tcl_ScanElement(const char *src, int *flagPtr)
 }
 declare 219 {
-    int Tcl_ScanCountedElement(const char *src, int length, char *flagPtr)
+    int Tcl_ScanCountedElement(const char *src, int length, int *flagPtr)
 }
 # Removed in Tcl 9
 #declare 220 {
diff --git a/generic/tclDecls.h b/generic/tclDecls.h
index e6c63b3..0770e98 100644
--- a/generic/tclDecls.h
+++ b/generic/tclDecls.h
@@ -257,10 +257,10 @@ TCLAPI int		Tcl_CommandComplete(const char *cmd);
 TCLAPI char *		Tcl_Concat(int argc, const char *const *argv);
 /* 84 */
 TCLAPI int		Tcl_ConvertElement(const char *src, char *dst,
-				char flags);
+				int flags);
 /* 85 */
 TCLAPI int		Tcl_ConvertCountedElement(const char *src,
-				int length, char *dst, char flags);
+				int length, char *dst, int flags);
 /* 86 */
 TCLAPI int		Tcl_CreateAlias(Tcl_Interp *slave,
 				const char *slaveCmd, Tcl_Interp *target,
@@ -625,10 +625,10 @@ TCLAPI void		Tcl_Release(ClientData clientData);
 /* 217 */
 TCLAPI void		Tcl_ResetResult(Tcl_Interp *interp);
 /* 218 */
-TCLAPI int		Tcl_ScanElement(const char *src, char *flagPtr);
+TCLAPI int		Tcl_ScanElement(const char *src, int *flagPtr);
 /* 219 */
 TCLAPI int		Tcl_ScanCountedElement(const char *src, int length,
-				char *flagPtr);
+				int *flagPtr);
 /* Slot 220 is reserved */
 /* 221 */
 TCLAPI int		Tcl_ServiceAll(void);
@@ -1877,8 +1877,8 @@ typedef struct TclStubs {
     int (*tcl_Close) (Tcl_Interp *interp, Tcl_Channel chan); /* 81 */
     int (*tcl_CommandComplete) (const char *cmd); /* 82 */
     char * (*tcl_Concat) (int argc, const char *const *argv); /* 83 */
-    int (*tcl_ConvertElement) (const char *src, char *dst, char flags); /* 84 */
-    int (*tcl_ConvertCountedElement) (const char *src, int length, char *dst, char flags); /* 85 */
+    int (*tcl_ConvertElement) (const char *src, char *dst, int flags); /* 84 */
+    int (*tcl_ConvertCountedElement) (const char *src, int length, char *dst, int flags); /* 85 */
     int (*tcl_CreateAlias) (Tcl_Interp *slave, const char *slaveCmd, Tcl_Interp *target, const char *targetCmd, int argc, const char *const *argv); /* 86 */
     int (*tcl_CreateAliasObj) (Tcl_Interp *slave, const char *slaveCmd, Tcl_Interp *target, const char *targetCmd, int objc, Tcl_Obj *const objv[]); /* 87 */
     Tcl_Channel (*tcl_CreateChannel) (const Tcl_ChannelType *typePtr, const char *chanName, ClientData instanceData, int mask); /* 88 */
@@ -2019,8 +2019,8 @@ typedef struct TclStubs {
     void (*tcl_RegExpRange) (Tcl_RegExp regexp, int index, const char **startPtr, const char **endPtr); /* 215 */
     void (*tcl_Release) (ClientData clientData); /* 216 */
     void (*tcl_ResetResult) (Tcl_Interp *interp); /* 217 */
-    int (*tcl_ScanElement) (const char *src, char *flagPtr); /* 218 */
-    int (*tcl_ScanCountedElement) (const char *src, int length, char *flagPtr); /* 219 */
+    int (*tcl_ScanElement) (const char *src, int *flagPtr); /* 218 */
+    int (*tcl_ScanCountedElement) (const char *src, int length, int *flagPtr); /* 219 */
     void (*reserved220)(void);
     int (*tcl_ServiceAll) (void); /* 221 */
     int (*tcl_ServiceEvent) (int flags); /* 222 */
diff --git a/generic/tclDictObj.c b/generic/tclDictObj.c
index 25124a1..2bc5f81 100644
--- a/generic/tclDictObj.c
+++ b/generic/tclDictObj.c
@@ -487,7 +487,7 @@ static void
 UpdateStringOfDict(
     Tcl_Obj *dictPtr)
 {
-#define LOCAL_SIZE 20
+#define LOCAL_SIZE 64
     char localFlags[LOCAL_SIZE], *flagPtr = NULL;
     Dict *dict = dictPtr->internalRep.otherValuePtr;
     ChainEntry *cPtr;
@@ -495,7 +495,6 @@ UpdateStringOfDict(
     int i, length, bytesNeeded = 0;
     const char *elem;
     char *dst;
-    const int maxFlags = UINT_MAX / sizeof(int);
 
     /*
      * This field is the most useful one in the whole hash structure, and it
@@ -517,10 +516,8 @@ UpdateStringOfDict(
 
     if (numElems <= LOCAL_SIZE) {
 	flagPtr = localFlags;
-    } else if (numElems > maxFlags) {
-	Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX);
     } else {
-	flagPtr = ckalloc(numElems * sizeof(char));
+	flagPtr = ckalloc(numElems);
     }
     for (i=0,cPtr=dict->entryChainHead; i<numElems; i+=2,cPtr=cPtr->nextPtr) {
 	/*
diff --git a/generic/tclListObj.c b/generic/tclListObj.c
index 63db812..6cbb10f 100644
--- a/generic/tclListObj.c
+++ b/generic/tclListObj.c
@@ -1923,7 +1923,7 @@ static void
 UpdateStringOfList(
     Tcl_Obj *listPtr)		/* List object with string rep to update. */
 {
-#   define LOCAL_SIZE 20
+#   define LOCAL_SIZE 64
     char localFlags[LOCAL_SIZE], *flagPtr = NULL;
     List *listRepPtr = ListRepPtr(listPtr);
     int numElems = listRepPtr->elemCount;
@@ -1961,7 +1961,7 @@ UpdateStringOfList(
 	 * We know numElems <= LIST_MAX, so this is safe.
 	 */
 
-	flagPtr = ckalloc(numElems * sizeof(char));
+	flagPtr = ckalloc(numElems);
     }
     elemPtrs = &listRepPtr->elements;
     for (i = 0; i < numElems; i++) {
diff --git a/generic/tclUtil.c b/generic/tclUtil.c
index c8cb75c..c6dd464 100644
--- a/generic/tclUtil.c
+++ b/generic/tclUtil.c
@@ -872,7 +872,7 @@ Tcl_SplitList(
 int
 Tcl_ScanElement(
     const char *src,	/* String to convert to list element. */
-    char *flagPtr)	/* Where to store information to guide
+    int *flagPtr)	/* Where to store information to guide
 			 * Tcl_ConvertCountedElement. */
 {
     return Tcl_ScanCountedElement(src, -1, flagPtr);
@@ -905,7 +905,7 @@ int
 Tcl_ScanCountedElement(
     const char *src,		/* String to convert to Tcl list element. */
     int length,			/* Number of bytes in src, or -1. */
-    char *flagPtr)		/* Where to store information to guide
+    int *flagPtr)		/* Where to store information to guide
 				 * Tcl_ConvertElement. */
 {
     char flags = CONVERT_ANY;
@@ -1236,7 +1236,7 @@ int
 Tcl_ConvertElement(
     const char *src,	/* Source information for list element. */
     char *dst,		/* Place to put list-ified element. */
-    char flags)		/* Flags produced by Tcl_ScanElement. */
+    int flags)		/* Flags produced by Tcl_ScanElement. */
 {
     return Tcl_ConvertCountedElement(src, -1, dst, flags);
 }
@@ -1267,7 +1267,7 @@ Tcl_ConvertCountedElement(
     register const char *src,	/* Source information for list element. */
     int length,			/* Number of bytes in src, or -1. */
     char *dst,			/* Place to put list-ified element. */
-    char flags)			/* Flags produced by Tcl_ScanElement. */
+    int flags)			/* Flags produced by Tcl_ScanElement. */
 {
     int numBytes = TclConvertElement(src, length, dst, flags);
     dst[numBytes] = '\0';
@@ -1481,11 +1481,10 @@ Tcl_Merge(
     int argc,			/* How many strings to merge. */
     const char *const *argv)	/* Array of string values. */
 {
-#define LOCAL_SIZE 20
+#define LOCAL_SIZE 64
     char localFlags[LOCAL_SIZE];
     int i, bytesNeeded = 0;
     char *result, *dst, *flagPtr = NULL;
-    const int maxFlags = UINT_MAX / sizeof(int);
 
     /*
      * Handle empty list case first, so logic of the general case can be
@@ -1504,33 +1503,16 @@ Tcl_Merge(
 
     if (argc <= LOCAL_SIZE) {
 	flagPtr = localFlags;
-    } else if (argc > maxFlags) {
-	/*
-	 * We cannot allocate a large enough flag array to format this list in
-	 * one pass.  We could imagine converting this routine to a multi-pass
-	 * implementation, but for sizeof(int) == 4, the limit is a max of
-	 * 2^30 list elements and since each element is at least one byte
-	 * formatted, and requires one byte space between it and the next one,
-	 * that a minimum space requirement of 2^31 bytes, which is already
-	 * INT_MAX. If we tried to format a list of > maxFlags elements, we're
-	 * just going to overflow the size limits on the formatted string
-	 * anyway, so just issue that same panic early.
-	 */
-
-	Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX);
     } else {
-	flagPtr = ckalloc(argc * sizeof(char));
+	flagPtr = ckalloc(argc);
     }
     for (i = 0; i < argc; i++) {
 	flagPtr[i] = ( i ? TCL_DONT_QUOTE_HASH : 0 );
 	bytesNeeded += TclScanElement(argv[i], -1, &flagPtr[i]);
-	if (bytesNeeded < 0) {
+	if ((bytesNeeded < 0) || (bytesNeeded > INT_MAX - argc + 1)) {
 	    Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX);
 	}
     }
-    if (bytesNeeded > INT_MAX - argc + 1) {
-	Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX);
-    }
     bytesNeeded += argc;
 
     /*
-- 
cgit v0.12