Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fix a9929f112a: Bugs in the implementation of TIP #577 ('Enhanced index values for Tk') |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk | main |
Files: | files | file ages | folders |
SHA3-256: |
0b05b5c750dff7d4688256a494ba5c4b |
User & Date: | jan.nijtmans 2023-06-28 07:10:49 |
Original Comment: | Fix a9929f112a: Bugs in the implementation of TIP 577 ("Enhanced index values for Tk" ) |
References
2024-08-20
| ||
12:50 | Merge [55602e8331f44cf5], "Bug [bc076f4f0e]. Fix large indexing broken by commit [0b05b5c750df]. Als... check-in: 1083a2733e user: pooryorick tags: unchained, INCOMPATIBLE_LICENSE | |
2023-08-14
| ||
03:42 | Bug [bc076f4f0e]. Fix large indexing broken by commit [0b05b5c750df]. Also preserves Tk bug fix [a99... check-in: 55602e8331 user: apnadkarni tags: trunk, main | |
2023-08-13
| ||
15:47 | • New ticket [13d3c0d764] lset on empty list is allowed when index argument is large. artifact: a337784d33 user: apnadkarni | |
06:22 | Revert [0b05b5c750df] that broke bigdata tests and lseq-1.13 check-in: 6985418bfc user: apnadkarni tags: bug-bc076f4f0e75 | |
Context
2024-06-14
| ||
08:18 | Fix a9929f112a: Bugs in the implementation of TIP #577 ('Enhanced index values for Tk'). check-in: 4420d1f8dc user: pooryorick tags: unchained | |
2023-08-13
| ||
06:22 | Revert [0b05b5c750df] that broke bigdata tests and lseq-1.13 check-in: 6985418bfc user: apnadkarni tags: bug-bc076f4f0e75 | |
2023-06-28
| ||
07:27 | Merge 8.7 check-in: 0663e9a4ab user: jan.nijtmans tags: trunk, main | |
07:10 | Fix a9929f112a: Bugs in the implementation of TIP ... check-in: 0b05b5c750 user: jan.nijtmans tags: trunk, main | |
2023-06-27
| ||
15:31 | Merge 9.0 Closed-Leaf check-in: 2b09ea3b64 user: jan.nijtmans tags: bug-a9929f112a | |
12:57 | Fix [24a8c16dbd]: bigdata.test: invalid command name "testbigdata" on 32-bit check-in: d5db55aa17 user: jan.nijtmans tags: trunk, main | |
Changes
Changes to generic/tclCompCmdsGR.c.
︙ | ︙ | |||
45 46 47 48 49 50 51 | * *---------------------------------------------------------------------- */ int TclGetIndexFromToken( Tcl_Token *tokenPtr, | | | | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | * *---------------------------------------------------------------------- */ int TclGetIndexFromToken( Tcl_Token *tokenPtr, int before, int after, int *indexPtr) { Tcl_Obj *tmpObj; int result = TCL_ERROR; TclNewObj(tmpObj); if (TclWordKnownAtCompileTime(tokenPtr, tmpObj)) { |
︙ | ︙ |
Changes to generic/tclCompile.h.
︙ | ︙ | |||
1134 1135 1136 1137 1138 1139 1140 | int create, CompileEnv *envPtr); MODULE_SCOPE int TclFixupForwardJump(CompileEnv *envPtr, JumpFixup *jumpFixupPtr, int jumpDist, int distThreshold); MODULE_SCOPE void TclFreeCompileEnv(CompileEnv *envPtr); MODULE_SCOPE void TclFreeJumpFixupArray(JumpFixupArray *fixupArrayPtr); MODULE_SCOPE int TclGetIndexFromToken(Tcl_Token *tokenPtr, | | | 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 | int create, CompileEnv *envPtr); MODULE_SCOPE int TclFixupForwardJump(CompileEnv *envPtr, JumpFixup *jumpFixupPtr, int jumpDist, int distThreshold); MODULE_SCOPE void TclFreeCompileEnv(CompileEnv *envPtr); MODULE_SCOPE void TclFreeJumpFixupArray(JumpFixupArray *fixupArrayPtr); MODULE_SCOPE int TclGetIndexFromToken(Tcl_Token *tokenPtr, int before, int after, int *indexPtr); MODULE_SCOPE ByteCode * TclInitByteCode(CompileEnv *envPtr); MODULE_SCOPE ByteCode * TclInitByteCodeObj(Tcl_Obj *objPtr, const Tcl_ObjType *typePtr, CompileEnv *envPtr); MODULE_SCOPE void TclInitCompileEnv(Tcl_Interp *interp, CompileEnv *envPtr, const char *string, size_t numBytes, const CmdFrame *invoker, int word); MODULE_SCOPE void TclInitJumpFixupArray(JumpFixupArray *fixupArrayPtr); |
︙ | ︙ |
Changes to generic/tclListObj.c.
︙ | ︙ | |||
2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 | /* ...the index we're trying to use isn't an index at all. */ result = TCL_ERROR; indexArray++; /* Why bother with this increment? TBD */ break; } indexArray++; if (index < 0 || index > elemCount || (valueObj == NULL && index >= elemCount)) { /* ...the index points outside the sublist. */ if (interp != NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf("index \"%s\" out of range", Tcl_GetString(indexArray[-1]))); | > > > | 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 | /* ...the index we're trying to use isn't an index at all. */ result = TCL_ERROR; indexArray++; /* Why bother with this increment? TBD */ break; } indexArray++; if ((index == TCL_SIZE_MAX) && (elemCount == 0)) { index = 0; } if (index < 0 || index > elemCount || (valueObj == NULL && index >= elemCount)) { /* ...the index points outside the sublist. */ if (interp != NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf("index \"%s\" out of range", Tcl_GetString(indexArray[-1]))); |
︙ | ︙ |
Changes to generic/tclUtil.c.
︙ | ︙ | |||
136 137 138 139 140 141 142 | Tcl_Size TclLengthOne( TCL_UNUSED(Tcl_Obj *)) { return 1; } | | | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | Tcl_Size TclLengthOne( TCL_UNUSED(Tcl_Obj *)) { return 1; } /* * * STRING REPRESENTATION OF LISTS * * * * * The next several routines implement the conversions of strings to and from * Tcl lists. To understand their operation, the rules of parsing and * generating the string representation of lists must be known. Here we * describe them in one place. |
︙ | ︙ | |||
3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 | void *cd; int code = Tcl_GetNumberFromObj(NULL, objPtr, &cd, &numType); if (code == TCL_OK) { if (numType == TCL_NUMBER_INT) { /* objPtr holds an integer in the signed wide range */ *widePtr = *(Tcl_WideInt *)cd; return TCL_OK; } if (numType == TCL_NUMBER_BIG) { /* objPtr holds an integer outside the signed wide range */ /* Truncate to the signed wide range. */ | > > > | | 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 | void *cd; int code = Tcl_GetNumberFromObj(NULL, objPtr, &cd, &numType); if (code == TCL_OK) { if (numType == TCL_NUMBER_INT) { /* objPtr holds an integer in the signed wide range */ *widePtr = *(Tcl_WideInt *)cd; if ((*widePtr < 0)) { *widePtr = (endValue == -1) ? WIDE_MIN : -1; } return TCL_OK; } if (numType == TCL_NUMBER_BIG) { /* objPtr holds an integer outside the signed wide range */ /* Truncate to the signed wide range. */ *widePtr = ((mp_isneg((mp_int *)cd)) ? ((endValue == -1) ? WIDE_MIN : -1) : WIDE_MAX); return TCL_OK; } } /* objPtr does not hold a number, check the end+/- format... */ return GetEndOffsetFromObj(interp, objPtr, endValue, widePtr); } |
︙ | ︙ | |||
3403 3404 3405 3406 3407 3408 3409 | * object. The string value 'objPtr' is expected have the format * integer([+-]integer)? or end([+-]integer)?. * * If the computed index lies within the valid range of Tcl indices * (0..TCL_SIZE_MAX) it is returned. Higher values are returned as * TCL_SIZE_MAX. Negative values are returned as TCL_INDEX_NONE (-1). * | < < < | > | | > | 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 | * object. The string value 'objPtr' is expected have the format * integer([+-]integer)? or end([+-]integer)?. * * If the computed index lies within the valid range of Tcl indices * (0..TCL_SIZE_MAX) it is returned. Higher values are returned as * TCL_SIZE_MAX. Negative values are returned as TCL_INDEX_NONE (-1). * * * Results: * TCL_OK * * The index is stored at the address given by by 'indexPtr'. If * 'objPtr' has the value "end", the value stored is 'endValue'. * * TCL_ERROR * * The value of 'objPtr' does not have one of the expected formats. If * 'interp' is non-NULL, an error message is left in the interpreter's * result object. * * Effect * * The object referenced by 'objPtr' is converted, as needed, to an * integer, wide integer, or end-based-index object. * *---------------------------------------------------------------------- */ int Tcl_GetIntForIndex( Tcl_Interp *interp, /* Interpreter to use for error reporting. If |
︙ | ︙ | |||
3442 3443 3444 3445 3446 3447 3448 | { Tcl_WideInt wide; if (GetWideForIndex(interp, objPtr, endValue, &wide) == TCL_ERROR) { return TCL_ERROR; } if (indexPtr != NULL) { | < | | > > | | 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 | { Tcl_WideInt wide; if (GetWideForIndex(interp, objPtr, endValue, &wide) == TCL_ERROR) { return TCL_ERROR; } if (indexPtr != NULL) { if ((wide < 0) && (endValue >= 0)) { *indexPtr = TCL_INDEX_NONE; } else if (wide > TCL_SIZE_MAX) { *indexPtr = TCL_SIZE_MAX; } else if (wide < -1-TCL_SIZE_MAX) { *indexPtr = -1-TCL_SIZE_MAX; } else { *indexPtr = (Tcl_Size) wide; } } return TCL_OK; } /* *---------------------------------------------------------------------- |
︙ | ︙ | |||
3688 3689 3690 3691 3692 3693 3694 | ir.wideValue = offset; Tcl_StoreInternalRep(objPtr, &endOffsetType.objType, &ir); } offset = irPtr->wideValue; if (offset == WIDE_MAX) { | < < < < < < < < | < > > | | < < | 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 | ir.wideValue = offset; Tcl_StoreInternalRep(objPtr, &endOffsetType.objType, &ir); } offset = irPtr->wideValue; if (offset == WIDE_MAX) { *widePtr = (endValue == -1) ? WIDE_MAX : endValue + 1; } else if (offset == WIDE_MIN) { *widePtr = -1; } else if (endValue == -1) { *widePtr = offset; } else if (offset < 0) { /* Different signs, sum cannot overflow */ *widePtr = (size_t)endValue + offset + 1; } else if (offset < WIDE_MAX) { *widePtr = offset; } else { *widePtr = WIDE_MAX; } return TCL_OK; /* Report a parse error. */ parseError: if (interp != NULL) { |
︙ | ︙ | |||
3732 3733 3734 3735 3736 3737 3738 | return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TclIndexEncode -- | < < < < | | > > | | | | < < < < < | | 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 | return TCL_ERROR; } /* *---------------------------------------------------------------------- * * TclIndexEncode -- * * Parse objPtr to determine if it is an index value. Two cases * are possible. The value objPtr might be parsed as an absolute * index value in the C signed int range. Note that this includes * index values that are integers as presented and it includes index * arithmetic expressions. The absolute index values that can be * directly meaningful as an index into either a list or a string are * those integer values >= TCL_INDEX_START (0) * and < INT_MAX. * The largest string supported in Tcl 8 has bytelength INT_MAX. * This means the largest supported character length is also INT_MAX, * and the index of the last character in a string of length INT_MAX * is INT_MAX-1. * * Any absolute index value parsed outside that range is encoded * using the before and after values passed in by the * caller as the encoding to use for indices that are either * less than or greater than the usable index range. TCL_INDEX_NONE * is available as a good choice for most callers to use for * after. Likewise, the value TCL_INDEX_NONE is good for |
︙ | ︙ | |||
3776 3777 3778 3779 3780 3781 3782 3783 | * index "end" is encoded as -2, down to the index "end-0x7FFFFFFE" * which is encoded as INT_MIN. Since the largest index into a * string possible in Tcl 8 is 0x7FFFFFFE, the interpretation of * "end-0x7FFFFFFE" for that largest string would be 0. Thus, * if the tokens "end-0x7FFFFFFF" or "end+-0x80000000" are parsed, * they can be encoded with the before value. * * Returns: | > > > > | < | < < | > > | > | | < < < < < < < < < < < < < < < < < < < < < < < | > | | | < | | < | < < < < < < < | < | | < | < | < < < < < < < < < < < < < < < < < | < < < < < < < < < | < < < < < < < < < < < < < < | < < | < > | | < | | < < < | < < < < < < < < | | 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 | * index "end" is encoded as -2, down to the index "end-0x7FFFFFFE" * which is encoded as INT_MIN. Since the largest index into a * string possible in Tcl 8 is 0x7FFFFFFE, the interpretation of * "end-0x7FFFFFFE" for that largest string would be 0. Thus, * if the tokens "end-0x7FFFFFFF" or "end+-0x80000000" are parsed, * they can be encoded with the before value. * * These details will require re-examination whenever string and * list length limits are increased, but that will likely also * mean a revised routine capable of returning Tcl_WideInt values. * * Returns: * TCL_OK if parsing succeeded, and TCL_ERROR if it failed. * * Side effects: * When TCL_OK is returned, the encoded index value is written * to *indexPtr. * *---------------------------------------------------------------------- */ int TclIndexEncode( Tcl_Interp *interp, /* For error reporting, may be NULL */ Tcl_Obj *objPtr, /* Index value to parse */ int before, /* Value to return for index before beginning */ int after, /* Value to return for index after end */ int *indexPtr) /* Where to write the encoded answer, not NULL */ { Tcl_WideInt wide; int idx; if (TCL_OK == GetWideForIndex(interp, objPtr, (unsigned)TCL_INDEX_END , &wide)) { const Tcl_ObjInternalRep *irPtr = TclFetchInternalRep(objPtr, &endOffsetType.objType); if (irPtr && irPtr->wideValue >= 0) { /* "int[+-]int" syntax, works the same here as "int" */ irPtr = NULL; } /* * We parsed an end+offset index value. * wide holds the offset value in the range WIDE_MIN...WIDE_MAX. */ if ((irPtr ? ((wide < INT_MIN) && ((Tcl_Size)-wide <= LIST_MAX)) : ((wide > INT_MAX) && ((Tcl_Size)wide <= LIST_MAX))) && (sizeof(int) != sizeof(Tcl_Size))) { if (interp) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "index \"%s\" out of range", TclGetString(objPtr))); Tcl_SetErrorCode(interp, "TCL", "VALUE", "INDEX" "OUTOFRANGE", NULL); } return TCL_ERROR; } else if (wide > (unsigned)(irPtr ? TCL_INDEX_END : INT_MAX)) { /* * All end+postive or end-negative expressions * always indicate "after the end". */ idx = after; } else if (wide <= (irPtr ? INT_MAX : -1)) { /* These indices always indicate "before the beginning" */ idx = before; } else { /* Encoded end-positive (or end+negative) are offset */ idx = (int)wide; } } else { return TCL_ERROR; } *indexPtr = idx; return TCL_OK; } /* *---------------------------------------------------------------------- * * TclIndexDecode -- * |
︙ | ︙ | |||
3948 3949 3950 3951 3952 3953 3954 | TclIndexDecode( int encoded, /* Value to decode */ Tcl_Size endValue) /* Meaning of "end" to use, > TCL_INDEX_END */ { if (encoded > TCL_INDEX_END) { return encoded; } | | < | | 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 | TclIndexDecode( int encoded, /* Value to decode */ Tcl_Size endValue) /* Meaning of "end" to use, > TCL_INDEX_END */ { if (encoded > TCL_INDEX_END) { return encoded; } if ((size_t)endValue >= (size_t)TCL_INDEX_END - encoded) { return endValue + encoded - TCL_INDEX_END; } return TCL_INDEX_NONE; } /* *------------------------------------------------------------------------ * |
︙ | ︙ |
Changes to tests/indexObj.test.
︙ | ︙ | |||
196 197 198 199 200 201 202 | testgetintforindex end 2147483646 } 2147483646 test indexObj-8.9 {Tcl_GetIntForIndex end} testgetintforindex { testgetintforindex end 2147483647 } 2147483647 test indexObj-8.10 {Tcl_GetIntForIndex end-1} testgetintforindex { testgetintforindex end-1 -1 | | | | | > > > > > > | 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | testgetintforindex end 2147483646 } 2147483646 test indexObj-8.9 {Tcl_GetIntForIndex end} testgetintforindex { testgetintforindex end 2147483647 } 2147483647 test indexObj-8.10 {Tcl_GetIntForIndex end-1} testgetintforindex { testgetintforindex end-1 -1 } -2 test indexObj-8.11 {Tcl_GetIntForIndex end-1} testgetintforindex { testgetintforindex end-1 -2 } [expr {[testConstraint has64BitLengths] ? -3 : 2147483647}] test indexObj-8.12 {Tcl_GetIntForIndex end} testgetintforindex { testgetintforindex end -1 } -1 test indexObj-8.13 {Tcl_GetIntForIndex end} testgetintforindex { testgetintforindex end -2 } [expr {[testConstraint has64BitLengths] ? -2 : 2147483647}] test indexObj-8.14 {Tcl_GetIntForIndex end+1} testgetintforindex { testgetintforindex end+1 -1 } [expr {[testConstraint has64BitLengths] ? 9223372036854775807 : 2147483647}] test indexObj-8.15 {Tcl_GetIntForIndex end+1} testgetintforindex { testgetintforindex end+1 -2 } -1 test indexObj-8.16 {Tcl_GetIntForIndex integer} testgetintforindex { testgetintforindex -1 -1 } [expr {[testConstraint has64BitLengths] ? -9223372036854775808 : -2147483648}] test indexObj-8.17 {Tcl_GetIntForIndex integer} testgetintforindex { testgetintforindex -2 -1 } [expr {[testConstraint has64BitLengths] ? -9223372036854775808 : -2147483648}] # cleanup ::tcltest::cleanupTests return # Local Variables: # mode: tcl |
︙ | ︙ |
Changes to tests/lseq.test.
︙ | ︙ | |||
594 595 596 597 598 599 600 | lindex [lseq 0x7fffffff] 0x80000000 } -result {} test lseq-4.12 {bug lseq} -constraints has64BitLengths -body { llength [lseq 0x100000000] } -result {4294967296} | | | 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 | lindex [lseq 0x7fffffff] 0x80000000 } -result {} test lseq-4.12 {bug lseq} -constraints has64BitLengths -body { llength [lseq 0x100000000] } -result {4294967296} test lseq-4.13 {bug lseq} -constraints {has64BitLengths knownBug} -body { set l [lseq 0x7fffffffffffffff] list \ [llength $l] \ [lindex $l end] \ [lindex $l 9223372036854775800] } -cleanup {unset l} -result {9223372036854775807 9223372036854775806 9223372036854775800} |
︙ | ︙ |