Compare commits

...
4 changed files with 95 additions and 17 deletions
+1 -1
View File
@@ -2474,7 +2474,7 @@ typedef struct List {
: Tcl_GetIntFromObj((interp), (objPtr), (intPtr)))
#define TclGetIntForIndexM(interp, objPtr, endValue, idxPtr) \
(((objPtr)->typePtr == &tclIntType \
&& (objPtr)->internalRep.longValue >= INT_MIN \
&& (objPtr)->internalRep.longValue >= -1 \
&& (objPtr)->internalRep.longValue <= INT_MAX) \
? ((*(idxPtr) = (objPtr)->internalRep.longValue), TCL_OK) \
: TclGetIntForIndex((interp), (objPtr), (endValue), (idxPtr)))
+71 -13
View File
@@ -13,6 +13,7 @@
*/
#include "tclInt.h"
#include "tclTomMath.h"
#include "tclParse.h"
#include "tclStringTrim.h"
#include <math.h>
@@ -3563,11 +3564,13 @@ TclFormatInt(
* Tcl object referenced by "objPtr" has the value "end", the value
* stored is "endValue". If "objPtr"s values is not of one of the
* expected formats, TCL_ERROR is returned and, if "interp" is non-NULL,
* an error message is left in the interpreter's result object.
* an error message is left in the interpreter's result object. If the
* index is valid but < INT_MIN (normally -2147483648), then the index
* value will be set to INT_MIN. The same happens for values > INT_MAX.
*
* Side effects:
* The object referenced by "objPtr" might be converted to an integer,
* wide integer, or end-based-index object.
* wide integer, bignum or end-based-index object.
*
*----------------------------------------------------------------------
*/
@@ -3587,9 +3590,41 @@ TclGetIntForIndex(
size_t length;
char *opPtr;
const char *bytes;
Tcl_WideInt value;
if (TclGetIntFromObj(NULL, objPtr, indexPtr) == TCL_OK) {
if (TclGetWideIntFromObj(NULL, objPtr, &value) == TCL_OK) {
if (objPtr->typePtr == &tclIntType) {
if ((objPtr)->internalRep.longValue < -1) {
value = -1;
} else if ((objPtr)->internalRep.longValue > INT_MAX) {
value = INT_MAX;
}
}
#ifndef TCL_WIDE_INT_IS_LONG
if (objPtr->typePtr == &tclWideIntType) {
if ((objPtr)->internalRep.wideValue < -1) {
value = -1;
} else if ((objPtr)->internalRep.wideValue > INT_MAX) {
value = INT_MAX;
}
}
#endif
*indexPtr = (int) value;
return TCL_OK;
} else {
mp_int big;
if (Tcl_GetBignumFromObj(NULL, objPtr, &big) == TCL_OK) {
if (objPtr->typePtr == &tclBignumType) {
Tcl_GetBignumFromObj(NULL, objPtr, &big);
if (mp_isneg(&big)) {
*indexPtr = -1;
} else {
*indexPtr = INT_MAX;
}
}
return TCL_OK;
}
}
if (SetEndOffsetFromAny(NULL, objPtr) == TCL_OK) {
@@ -3598,7 +3633,11 @@ TclGetIntForIndex(
* be converted to one, use it.
*/
*indexPtr = endValue + objPtr->internalRep.longValue;
if (objPtr->internalRep.wideValue > (INT_MAX-(Tcl_WideInt)endValue)) {
*indexPtr = INT_MAX;
} else {
*indexPtr = endValue + objPtr->internalRep.wideValue;
}
return TCL_OK;
}
@@ -3690,9 +3729,11 @@ UpdateStringOfEndOffset(
register int len = 3;
memcpy(buffer, "end", 4);
if (objPtr->internalRep.longValue != 0) {
buffer[len++] = '-';
len += TclFormatInt(buffer+len, -(objPtr->internalRep.longValue));
if (objPtr->internalRep.wideValue != 0) {
if (objPtr->internalRep.wideValue > 0) {
buffer[len++] = '+';
}
len += sprintf(buffer+len, "%" TCL_LL_MODIFIER "d", objPtr->internalRep.wideValue);
}
objPtr->bytes = ckalloc((unsigned) len+1);
memcpy(objPtr->bytes, buffer, (unsigned) len+1);
@@ -3722,7 +3763,7 @@ SetEndOffsetFromAny(
Tcl_Interp *interp, /* Tcl interpreter or NULL */
Tcl_Obj *objPtr) /* Pointer to the object to parse */
{
int offset; /* Offset in the "end-offset" expression */
Tcl_WideInt offset; /* Offset in the "end-offset" expression */
register const char *bytes; /* String rep of the object */
int length; /* Length of the object's string rep */
@@ -3758,17 +3799,34 @@ SetEndOffsetFromAny(
} else if ((length > 4) && ((bytes[3] == '-') || (bytes[3] == '+'))) {
/*
* This is our limited string expression evaluator. Pass everything
* after "end-" to Tcl_GetInt, then reverse for offset.
* after "end-" to TclParseNumber, then reverse for offset.
*/
if (TclIsSpaceProc(bytes[4])) {
goto badIndexFormat;
}
if (Tcl_GetInt(interp, bytes+4, &offset) != TCL_OK) {
return TCL_ERROR;
if (TclParseNumber(NULL, objPtr, "number", (char *) (bytes) + 4, -1,
NULL, TCL_PARSE_INTEGER_ONLY | TCL_PARSE_NO_WHITESPACE) != TCL_OK) {
TclFreeIntRep(objPtr);
goto badIndexFormat;
}
if (objPtr->typePtr == &tclIntType
#ifndef TCL_WIDE_INT_IS_LONG
|| objPtr->typePtr == &tclWideIntType
#endif
) {
TclGetWideIntFromObj(interp, objPtr, &offset);
} else if (objPtr->typePtr == &tclBignumType) {
mp_int big;
Tcl_GetBignumFromObj(interp, objPtr, &big);
TclFreeIntRep(objPtr);
offset = mp_isneg(&big) ? -LLONG_MAX : LLONG_MAX;
} else {
TclFreeIntRep(objPtr);
goto badIndexFormat;
}
if (bytes[3] == '-') {
offset = -offset;
offset = (offset == LLONG_MIN) ? LLONG_MAX : -offset;
}
} else {
/*
@@ -3790,7 +3848,7 @@ SetEndOffsetFromAny(
*/
TclFreeIntRep(objPtr);
objPtr->internalRep.longValue = offset;
objPtr->internalRep.wideValue = offset;
objPtr->typePtr = &tclEndOffsetType;
return TCL_OK;
+20
View File
@@ -90,6 +90,26 @@ test lrange-3.1 {Bug 3588366: end-offsets before start} {
lrange $l 0 end-5
}} {1 2 3 4 5}
} {}
test lrange-3.2 {Bug aaa02c55b9: lrange with huge index, weird results} {
apply {l {
lrange $l 2147483649 end
}} {1 2 3 4 5}
} {}
test lrange-3.3 {Bug aaa02c55b9: lrange with huge index, weird results} {
apply {l {
lrange $l -21474836492147483649 end
}} {1 2 3 4 5}
} {1 2 3 4 5}
test lrange-3.4 {Bug aaa02c55b9: lrange with huge index, weird results} {
apply {l {
lrange $l -1 -2147483649
}} {1 2 3 4 5}
} {}
test lrange-3.5 {Bug aaa02c55b9: lrange with huge index, weird results} {
apply {l {
lrange $l -1 21474836492147483649
}} {1 2 3 4 5}
} {1 2 3 4 5}
# cleanup
::tcltest::cleanupTests
+3 -3
View File
@@ -568,7 +568,7 @@ test obj-31.3 {regenerate string rep of "end--1"} testobj {
teststringobj set 1 end--0x1
testobj convert 1 end-offset
testobj invalidateStringRep 1
} end--1
} end+1
test obj-31.4 {regenerate string rep of "end-bigInteger"} testobj {
testobj freeallvars
teststringobj set 1 end-0x7fffffff
@@ -580,13 +580,13 @@ test obj-31.5 {regenerate string rep of "end--bigInteger"} testobj {
teststringobj set 1 end--0x7fffffff
testobj convert 1 end-offset
testobj invalidateStringRep 1
} end--2147483647
} end+2147483647
test obj-31.6 {regenerate string rep of "end--bigInteger"} {testobj longIs32bit} {
testobj freeallvars
teststringobj set 1 end--0x80000000
testobj convert 1 end-offset
testobj invalidateStringRep 1
} end--2147483648
} end+2147483648
test obj-32.1 {freeing very large object trees} {
set x {}