Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Limits on list length were too strict. Revised panics to errors where possible. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
2d215ce10301664f777957ec9bea4693 |
User & Date: | dgp 2011-04-21 17:32:20 |
Context
2011-04-21
| ||
18:50 | Use macro to set List intreps check-in: 0353d21711 user: dgp tags: trunk | |
17:32 | Limits on list length were too strict. Revised panics to errors where possible. check-in: 2d215ce103 user: dgp tags: trunk | |
16:53 | Limits on list length were too strict. Revised panics to errors where possible. check-in: 9080c06a95 user: dgp tags: core-8-5-branch | |
13:47 | Make sure SetFooFromAny routines react reasonably when passed a NULL interp. check-in: 36b0307ba2 user: dgp tags: trunk | |
Changes
Changes to ChangeLog.
1 2 3 4 5 6 7 8 | 2011-04-21 Don Porter <[email protected]> * generic/tclCompile.c: Make sure SetFooFromAny routines react * generic/tclIO.c: reasonably when passed a NULL interp. * generic/tclIndexObj.c: * generic/tclListObj.c: * generic/tclNamesp.c: * generic/tclObj.c: | > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 | 2011-04-21 Don Porter <[email protected]> * generic/tclCmdIL.c: Limits on list length were too strict. * generic/tclInt.h: Revised panics to errors where possible. * generic/tclListObj.c: * tests/lrepeat.test: * generic/tclCompile.c: Make sure SetFooFromAny routines react * generic/tclIO.c: reasonably when passed a NULL interp. * generic/tclIndexObj.c: * generic/tclListObj.c: * generic/tclNamesp.c: * generic/tclObj.c: |
︙ | ︙ |
Changes to generic/tclCmdIL.c.
︙ | ︙ | |||
2575 2576 2577 2578 2579 2580 2581 | /* * Skip forward to the interesting arguments now we've finished parsing. */ objc -= 2; objv += 2; | < | < < < < < | | > | < < < < | 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 | /* * Skip forward to the interesting arguments now we've finished parsing. */ objc -= 2; objv += 2; /* Final sanity check. Do not exceed limits on max list length. */ if (elementCount && objc > LIST_MAX/elementCount) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "max length of a Tcl list (%d elements) exceeded", LIST_MAX)); Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL); return TCL_ERROR; } totalElems = objc * elementCount; /* * Get an empty list object that is allocated large enough to hold each * init value elementCount times. */ listPtr = Tcl_NewListObj(totalElems, NULL); |
︙ | ︙ |
Changes to generic/tclInt.h.
︙ | ︙ | |||
2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 | * derived from the list representation. May * be ignored if there is no string rep at * all.*/ Tcl_Obj *elements; /* First list element; the struct is grown to * accomodate all elements. */ } List; /* * Macro used to get the elements of a list object. */ #define ListRepPtr(listPtr) \ ((List *) (listPtr)->internalRep.twoPtrValue.ptr1) | > > > | 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 | * derived from the list representation. May * be ignored if there is no string rep at * all.*/ Tcl_Obj *elements; /* First list element; the struct is grown to * accomodate all elements. */ } List; #define LIST_MAX \ (1 + (int)(((size_t)UINT_MAX - sizeof(List))/sizeof(Tcl_Obj *))) /* * Macro used to get the elements of a list object. */ #define ListRepPtr(listPtr) \ ((List *) (listPtr)->internalRep.twoPtrValue.ptr1) |
︙ | ︙ |
Changes to generic/tclListObj.c.
︙ | ︙ | |||
13 14 15 16 17 18 19 | #include "tclInt.h" /* * Prototypes for functions defined later in this file: */ | > > | | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #include "tclInt.h" /* * Prototypes for functions defined later in this file: */ static List * AttemptNewList(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static List * NewListIntRep(int objc, Tcl_Obj *const objv[], int p); static void DupListInternalRep(Tcl_Obj *srcPtr, Tcl_Obj *copyPtr); static void FreeListInternalRep(Tcl_Obj *listPtr); static int SetListFromAny(Tcl_Interp *interp, Tcl_Obj *objPtr); static void UpdateStringOfList(Tcl_Obj *listPtr); /* * The structure below defines the list Tcl object type by means of functions |
︙ | ︙ | |||
45 46 47 48 49 50 51 | }; /* *---------------------------------------------------------------------- * * NewListIntRep -- * | | | | | | | | | | > | | > > > > > > > > | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | }; /* *---------------------------------------------------------------------- * * NewListIntRep -- * * Creates a list internal rep with space for objc elements. objc * must be > 0. If objv!=NULL, initializes with the first objc values * in that array. If objv==NULL, initalize list internal rep to have * 0 elements, with space to add objc more. Flag value "p" indicates * how to behave on failure. * * Results: * A new List struct with refCount 0 is returned. If some failure * prevents this then if p=0, NULL is returned and otherwise the * routine panics. * * Side effects: * The ref counts of the elements in objv are incremented since the * resulting list now refers to them. * *---------------------------------------------------------------------- */ static List * NewListIntRep( int objc, Tcl_Obj *const objv[], int p) { List *listRepPtr; if (objc <= 0) { Tcl_Panic("NewListIntRep: expects postive element count"); } /* * First check to see if we'd overflow and try to allocate an object * larger than our memory allocator allows. Note that this is actually a * fairly small value when you're on a serious 64-bit machine, but that * requires API changes to fix. See [Bug 219196] for a discussion. */ if ((size_t)objc > LIST_MAX) { if (p) { Tcl_Panic("max length of a Tcl list (%d elements) exceeded", LIST_MAX); } return NULL; } listRepPtr = attemptckalloc(sizeof(List) + ((objc-1) * sizeof(Tcl_Obj*))); if (listRepPtr == NULL) { if (p) { Tcl_Panic("list creation failed: unable to alloc %u bytes", sizeof(List) + ((objc-1) * sizeof(Tcl_Obj *))); } return NULL; } listRepPtr->canonicalFlag = 0; listRepPtr->refCount = 0; listRepPtr->maxElemCount = objc; |
︙ | ︙ | |||
109 110 111 112 113 114 115 116 117 118 119 120 121 122 | Tcl_IncrRefCount(elemPtrs[i]); } } else { listRepPtr->elemCount = 0; } return listRepPtr; } /* *---------------------------------------------------------------------- * * Tcl_NewListObj -- * * This function is normally called when not debugging: i.e., when | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | Tcl_IncrRefCount(elemPtrs[i]); } } else { listRepPtr->elemCount = 0; } return listRepPtr; } /* *---------------------------------------------------------------------- * * AttemptNewList -- * * Creates a list internal rep with space for objc elements. objc * must be > 0. If objv!=NULL, initializes with the first objc values * in that array. If objv==NULL, initalize list internal rep to have * 0 elements, with space to add objc more. * * Results: * A new List struct with refCount 0 is returned. If some failure * prevents this then NULL is returned, and an error message is left * in the interp result, unless interp is NULL. * * Side effects: * The ref counts of the elements in objv are incremented since the * resulting list now refers to them. * *---------------------------------------------------------------------- */ static List * AttemptNewList( Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { List *listRepPtr = NewListIntRep(objc, objv, 0); if (interp != NULL && listRepPtr == NULL) { if (objc > LIST_MAX) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "max length of a Tcl list (%d elements) exceeded", LIST_MAX)); } else { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "list creation failed: unable to alloc %u bytes", sizeof(List) + ((objc-1) * sizeof(Tcl_Obj *)))); } Tcl_SetErrorCode(interp, "TCL", "MEMORY", NULL); } return listRepPtr; } /* *---------------------------------------------------------------------- * * Tcl_NewListObj -- * * This function is normally called when not debugging: i.e., when |
︙ | ︙ | |||
167 168 169 170 171 172 173 | return listPtr; } /* * Create the internal rep. */ | | < < < | 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | return listPtr; } /* * Create the internal rep. */ listRepPtr = NewListIntRep(objc, objv, 1); /* * Now create the object. */ Tcl_InvalidateStringRep(listPtr); listPtr->internalRep.twoPtrValue.ptr1 = listRepPtr; |
︙ | ︙ | |||
239 240 241 242 243 244 245 | return listPtr; } /* * Create the internal rep. */ | | < < < | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 | return listPtr; } /* * Create the internal rep. */ listRepPtr = NewListIntRep(objc, objv, 1); /* * Now create the object. */ Tcl_InvalidateStringRep(listPtr); listPtr->internalRep.twoPtrValue.ptr1 = listRepPtr; |
︙ | ︙ | |||
321 322 323 324 325 326 327 | /* * Set the object's type to "list" and initialize the internal rep. * However, if there are no elements to put in the list, just give the * object an empty string rep and a NULL type. */ if (objc > 0) { | | < < < | 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 | /* * Set the object's type to "list" and initialize the internal rep. * However, if there are no elements to put in the list, just give the * object an empty string rep and a NULL type. */ if (objc > 0) { listRepPtr = NewListIntRep(objc, objv, 1); objPtr->internalRep.twoPtrValue.ptr1 = listRepPtr; objPtr->internalRep.twoPtrValue.ptr2 = NULL; objPtr->typePtr = &tclListType; listRepPtr->refCount++; } else { objPtr->bytes = tclEmptyStringRep; objPtr->length = 0; |
︙ | ︙ | |||
582 583 584 585 586 587 588 | newSize = 0; } if (listRepPtr->refCount > 1) { List *oldListRepPtr = listRepPtr; Tcl_Obj **oldElems; | | | | | 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 | newSize = 0; } if (listRepPtr->refCount > 1) { List *oldListRepPtr = listRepPtr; Tcl_Obj **oldElems; listRepPtr = AttemptNewList(interp, newMax, NULL); if (listRepPtr == NULL) { return TCL_ERROR; } oldElems = &oldListRepPtr->elements; elemPtrs = &listRepPtr->elements; for (i=0; i<numElems; i++) { elemPtrs[i] = oldElems[i]; Tcl_IncrRefCount(elemPtrs[i]); } |
︙ | ︙ | |||
878 879 880 881 882 883 884 | if (numRequired > listRepPtr->maxElemCount){ newMax = 2 * numRequired; } else { newMax = listRepPtr->maxElemCount; } | | | | | 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 | if (numRequired > listRepPtr->maxElemCount){ newMax = 2 * numRequired; } else { newMax = listRepPtr->maxElemCount; } listRepPtr = AttemptNewList(interp, newMax, NULL); if (listRepPtr == NULL) { return TCL_ERROR; } listPtr->internalRep.twoPtrValue.ptr1 = listRepPtr; listRepPtr->refCount++; elemPtrs = &listRepPtr->elements; |
︙ | ︙ | |||
1546 1547 1548 1549 1550 1551 1552 | */ if (listRepPtr->refCount > 1) { List *oldListRepPtr = listRepPtr; Tcl_Obj **oldElemPtrs = elemPtrs; int i; | | | | 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 | */ if (listRepPtr->refCount > 1) { List *oldListRepPtr = listRepPtr; Tcl_Obj **oldElemPtrs = elemPtrs; int i; listRepPtr = AttemptNewList(interp, listRepPtr->maxElemCount, NULL); if (listRepPtr == NULL) { return TCL_ERROR; } listRepPtr->canonicalFlag = oldListRepPtr->canonicalFlag; elemPtrs = &listRepPtr->elements; for (i=0; i < elemCount; i++) { elemPtrs[i] = oldElemPtrs[i]; Tcl_IncrRefCount(elemPtrs[i]); } |
︙ | ︙ | |||
1712 1713 1714 1715 1716 1717 1718 | * the reverse back to a dictionary) are both order-preserving. Also * note that since we know we've got a valid dictionary (by * representation) we also know that fetching the size of the * dictionary or iterating over it will not fail. */ Tcl_DictObjSize(NULL, objPtr, &size); | | < < < < < < | 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 | * the reverse back to a dictionary) are both order-preserving. Also * note that since we know we've got a valid dictionary (by * representation) we also know that fetching the size of the * dictionary or iterating over it will not fail. */ Tcl_DictObjSize(NULL, objPtr, &size); listRepPtr = AttemptNewList(interp, size > 0 ? 2*size : 1, NULL); if (!listRepPtr) { return TCL_ERROR; } listRepPtr->elemCount = 2 * size; /* * Populate the list representation. */ |
︙ | ︙ | |||
1775 1776 1777 1778 1779 1780 1781 | /* * Allocate a new List structure with enough room for "estCount" elements. * Each element is a pointer to a Tcl_Obj with the appropriate string rep. * The initial "estCount" elements are set using the corresponding "argv" * strings. */ | | | < < < < < | 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 | /* * Allocate a new List structure with enough room for "estCount" elements. * Each element is a pointer to a Tcl_Obj with the appropriate string rep. * The initial "estCount" elements are set using the corresponding "argv" * strings. */ listRepPtr = AttemptNewList(interp, estCount, NULL); if (listRepPtr == NULL) { return TCL_ERROR; } elemPtrs = &listRepPtr->elements; for (p=string, lenRemain=length, i=0; lenRemain > 0; p=nextElem, lenRemain=limit-nextElem, i++) { |
︙ | ︙ |
Changes to tests/lrepeat.test.
︙ | ︙ | |||
59 60 61 62 63 64 65 | -body { lrepeat 0 a b c } -result {} } test lrepeat-1.8 {Do not build enormous lists - Bug 2130992} -body { lrepeat 0x10000000 a b c d e f g h | | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | -body { lrepeat 0 a b c } -result {} } test lrepeat-1.8 {Do not build enormous lists - Bug 2130992} -body { lrepeat 0x10000000 a b c d e f g h } -returnCodes error -match glob -result * ## Okay test lrepeat-2.1 {normal cases} { lrepeat 10 a } {a a a a a a a a a a} test lrepeat-2.2 {normal cases} { lrepeat 3 [lrepeat 3 0] |
︙ | ︙ |