Tcl Source Code

Check-in [427bc951fb]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix memory leaks and remove unnecessary reference count bounce.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk | main
Files: files | file ages | folders
SHA3-256: 427bc951fbcffe81aeaf6ad765e84bd0fe3cda345e3c270410232457e23e9cad
User & Date: pooryorick 2023-05-16 09:33:12
References
2023-05-17
15:22 New ticket [6022b9f946] Tk when built against Tcl 9.0 broken. artifact: cb3a25bc39 user: jan.nijtmans
Context
2023-05-17
16:12
Merge trunk check-in: 3e44e4bdd3 user: griffin tags: tip-636-tcl9-644
07:30
Remove dead code check-in: a00f23f242 user: jan.nijtmans tags: trunk, main
2023-05-16
09:33
Fix memory leaks and remove unnecessary reference count bounce. check-in: 427bc951fb user: pooryorick tags: trunk, main
06:25
Merge 8.7 check-in: 8e4d8a6053 user: jan.nijtmans tags: trunk, main
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/tclCmdIL.c.

2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
    TCL_UNUSED(void *),
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,		/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Tcl_Obj *listPtr;
    Tcl_Size len, index;
    int result;

    if (objc < 3) {
	Tcl_WrongNumArgs(interp, 1, objv, "list index ?element ...?");
	return TCL_ERROR;
    }

    result = TclListObjLengthM(interp, objv[1], &len);







|







2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
    TCL_UNUSED(void *),
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,		/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Tcl_Obj *listPtr;
    Tcl_Size len, index;
    int copied = 0, result;

    if (objc < 3) {
	Tcl_WrongNumArgs(interp, 1, objv, "list index ?element ...?");
	return TCL_ERROR;
    }

    result = TclListObjLengthM(interp, objv[1], &len);
2498
2499
2500
2501
2502
2503
2504

2505
2506
2507
2508
2509
2510
2511
2512
2513



2514
2515
2516
2517
2518



2519
2520
2521
2522
2523
2524
2525
     * If the list object is unshared we can modify it directly. Otherwise we
     * create a copy to modify: this is "copy on write".
     */

    listPtr = objv[1];
    if (Tcl_IsShared(listPtr)) {
	listPtr = TclDuplicatePureObj(listPtr);

    }

    if ((objc == 4) && (index == len)) {
	/*
	 * Special case: insert one element at the end of the list.
	 */

	result = Tcl_ListObjAppendElement(NULL, listPtr, objv[3]);
	if (result != TCL_OK) {



	    return result;
	}
    } else {
	if (TCL_OK != Tcl_ListObjReplace(interp, listPtr, index, 0,
		(objc-3), &(objv[3]))) {



	    return TCL_ERROR;
	}
    }

    /*
     * Set the interpreter's object result.
     */







>









>
>
>





>
>
>







2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
     * If the list object is unshared we can modify it directly. Otherwise we
     * create a copy to modify: this is "copy on write".
     */

    listPtr = objv[1];
    if (Tcl_IsShared(listPtr)) {
	listPtr = TclDuplicatePureObj(listPtr);
	copied = 1;
    }

    if ((objc == 4) && (index == len)) {
	/*
	 * Special case: insert one element at the end of the list.
	 */

	result = Tcl_ListObjAppendElement(NULL, listPtr, objv[3]);
	if (result != TCL_OK) {
	    if (copied) {
		Tcl_DecrRefCount(listPtr);
	    }
	    return result;
	}
    } else {
	if (TCL_OK != Tcl_ListObjReplace(interp, listPtr, index, 0,
		(objc-3), &(objv[3]))) {
	    if (copied) {
		Tcl_DecrRefCount(listPtr);
	    }
	    return TCL_ERROR;
	}
    }

    /*
     * Set the interpreter's object result.
     */
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
    TCL_UNUSED(void *),
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])
				/* Argument objects. */
{
    Tcl_Size listLen;
    int result;
    Tcl_Obj *elemPtr, *stored;
    Tcl_Obj *listPtr, **elemPtrs;

    if (objc < 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "listvar ?index?");
	return TCL_ERROR;
    }







|







2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
    TCL_UNUSED(void *),
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])
				/* Argument objects. */
{
    Tcl_Size listLen;
    int copied = 0, result;
    Tcl_Obj *elemPtr, *stored;
    Tcl_Obj *listPtr, **elemPtrs;

    if (objc < 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "listvar ?index?");
	return TCL_ERROR;
    }
2688
2689
2690
2691
2692
2693
2694

2695
2696
2697



2698
2699
2700
2701
2702



2703
2704
2705


2706
2707
2708
2709
2710
2711
2712
     * Second, remove the element.
     * TclLsetFlat adds a ref count which is handled.
     */

    if (objc == 2) {
	if (Tcl_IsShared(listPtr)) {
	    listPtr = TclDuplicatePureObj(listPtr);

	}
	result = Tcl_ListObjReplace(interp, listPtr, listLen - 1, 1, 0, NULL);
	if (result != TCL_OK) {



	    return result;
	}
	Tcl_IncrRefCount(listPtr);
    } else {
	listPtr = TclLsetFlat(interp, listPtr, objc-2, objv+2, NULL);




	if (listPtr == NULL) {
	    return TCL_ERROR;


	}
    }

    stored = Tcl_ObjSetVar2(interp, objv[1], NULL, listPtr, TCL_LEAVE_ERR_MSG);
    Tcl_DecrRefCount(listPtr);
    if (stored == NULL) {
	return TCL_ERROR;







>



>
>
>




|
>
>
>
|
<

>
>







2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717

2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
     * Second, remove the element.
     * TclLsetFlat adds a ref count which is handled.
     */

    if (objc == 2) {
	if (Tcl_IsShared(listPtr)) {
	    listPtr = TclDuplicatePureObj(listPtr);
	    copied = 1;
	}
	result = Tcl_ListObjReplace(interp, listPtr, listLen - 1, 1, 0, NULL);
	if (result != TCL_OK) {
	    if (copied) {
		Tcl_DecrRefCount(listPtr);
	    }
	    return result;
	}
	Tcl_IncrRefCount(listPtr);
    } else {
	Tcl_Obj *newListPtr = TclLsetFlat(interp, listPtr, objc-2, objv+2, NULL);
	if (newListPtr == NULL) {
	    if (copied) {
		Tcl_DecrRefCount(listPtr);
	    }

	    return TCL_ERROR;
	} else {
	    listPtr = newListPtr;
	}
    }

    stored = Tcl_ObjSetVar2(interp, objv[1], NULL, listPtr, TCL_LEAVE_ERR_MSG);
    Tcl_DecrRefCount(listPtr);
    if (stored == NULL) {
	return TCL_ERROR;
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Tcl_Size i, idxc, prevIdx, first, num;
    Tcl_Size *idxv, listLen;
    Tcl_Obj *listObj;
    int status = TCL_OK;

    /*
     * Parse the arguments.
     */

    if (objc < 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "list ?index ...?");







|







2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    Tcl_Size i, idxc, prevIdx, first, num;
    Tcl_Size *idxv, listLen;
    Tcl_Obj *listObj;
    int copied = 0, status = TCL_OK;

    /*
     * Parse the arguments.
     */

    if (objc < 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "list ?index ...?");
2865
2866
2867
2868
2869
2870
2871

2872
2873
2874
2875
2876
2877
2878

    /*
     * Make our working copy, then do the actual removes piecemeal.
     */

    if (Tcl_IsShared(listObj)) {
	listObj = TclDuplicatePureObj(listObj);

    }
    num = 0;
    first = listLen;
    for (i = 0, prevIdx = -1 ; i < idxc ; i++) {
	Tcl_Size idx = idxv[i];

	/*







>







2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894

    /*
     * Make our working copy, then do the actual removes piecemeal.
     */

    if (Tcl_IsShared(listObj)) {
	listObj = TclDuplicatePureObj(listObj);
	copied = 1;
    }
    num = 0;
    first = listLen;
    for (i = 0, prevIdx = -1 ; i < idxc ; i++) {
	Tcl_Size idx = idxv[i];

	/*
2911
2912
2913
2914
2915
2916
2917



2918
2919
2920
2921
2922
2923
2924
	    num = 1;
	    first = idx;
	}
    }
    if (num != 0) {
	status = Tcl_ListObjReplace(interp, listObj, first, num, 0, NULL);
	if (status != TCL_OK) {



	    goto done;
	}
    }
    Tcl_SetObjResult(interp, listObj);
done:
    Tcl_Free(idxv);
    return status;







>
>
>







2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
	    num = 1;
	    first = idx;
	}
    }
    if (num != 0) {
	status = Tcl_ListObjReplace(interp, listObj, first, num, 0, NULL);
	if (status != TCL_OK) {
	    if (copied) {
		Tcl_DecrRefCount(listObj);
	    }
	    goto done;
	}
    }
    Tcl_SetObjResult(interp, listObj);
done:
    Tcl_Free(idxv);
    return status;
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
	    Tcl_DecrRefCount(listPtr);
	}
	return result;
    }

    /*
     * Tcl_ObjSetVar2 may return a value different from listPtr in the
     * presence of traces etc.. Note that finalValuePtr will always have a
     * reference count of at least 1 corresponding to the reference from the
     * var. If it is same as listPtr, then ref count will be at least 2
     * since we are incr'ing the latter below (safer when calling
     * Tcl_ObjSetVar2 which can release it in some cases). Note that we
     * leave the incrref of listPtr this late because we want to pass it as
     * unshared to Tcl_ListObjReplace above if possible.
     */
    Tcl_IncrRefCount(listPtr);
    finalValuePtr =
	Tcl_ObjSetVar2(interp, objv[1], NULL, listPtr, TCL_LEAVE_ERR_MSG);
    Tcl_DecrRefCount(listPtr); /* safe irrespective of createdNewObj */
    if (finalValuePtr == NULL) {
	return TCL_ERROR;
    }

    Tcl_SetObjResult(interp, finalValuePtr);
    return TCL_OK;
}







|
<
<
<
<
<
<

<


<







5124
5125
5126
5127
5128
5129
5130
5131






5132

5133
5134

5135
5136
5137
5138
5139
5140
5141
	    Tcl_DecrRefCount(listPtr);
	}
	return result;
    }

    /*
     * Tcl_ObjSetVar2 may return a value different from listPtr in the
     * presence of traces etc.






     */

    finalValuePtr =
	Tcl_ObjSetVar2(interp, objv[1], NULL, listPtr, TCL_LEAVE_ERR_MSG);

    if (finalValuePtr == NULL) {
	return TCL_ERROR;
    }

    Tcl_SetObjResult(interp, finalValuePtr);
    return TCL_OK;
}