Changes On Branch 6b5f0e9b55fae09e
Not logged in

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

Changes In Branch bug-d4e7780ca1 Excluding Merge-Ins

This is equivalent to a diff from f0027409f5 to 6b5f0e9b55

2016-09-07
12:54
Fix [d4e7780ca1681cd095dbd81fe264feff75c988f7|d4e7780ca1]: "global" cmd literal sharing vs. per-inte... check-in: c09edf1bac user: jan.nijtmans tags: core-8-6-branch
2016-09-06
10:44
Fixed bug in pushed transforms with full internal buffers not writing out. check-in: 10c5858b0d user: dkf tags: core-8-6-branch
08:25
Additiona patch/suggestion from Gustaf. This indeed fixes the crash in oo.test. Looks good to me, so... Closed-Leaf check-in: 6b5f0e9b55 user: jan.nijtmans tags: bug-d4e7780ca1
2016-09-05
14:52
some more clean-up check-in: b6613c42d4 user: jan.nijtmans tags: bug-d4e7780ca1
14:12
merge core-8-6-branch check-in: 088a6d7995 user: jan.nijtmans tags: bug-d4e7780ca1
13:56
merge core-8-6-branch check-in: 4ba030874a user: jan.nijtmans tags: trunk
13:55
Allow additional optional "interp" argument for testinterpresolver command. Not used yet in any test... check-in: f0027409f5 user: jan.nijtmans tags: core-8-6-branch
2016-08-30
13:00
Don't ever allow UTF-8 sequences of more than 4 characters to be generated or parsed, even when TCL_... check-in: c0a65532a7 user: jan.nijtmans tags: core-8-6-branch

Changes to generic/tclCompile.c.
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786











1787
1788
1789
1790
1791
1792
1793
1777
1778
1779
1780
1781
1782
1783



1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801







-
-
-
+
+
+
+
+
+
+
+
+
+
+







static void
CompileCmdLiteral(
    Tcl_Interp *interp,
    Tcl_Obj *cmdObj,
    CompileEnv *envPtr)
{
    int numBytes;
    const char *bytes = Tcl_GetStringFromObj(cmdObj, &numBytes);
    int cmdLitIdx = TclRegisterNewCmdLiteral(envPtr, bytes, numBytes);
    Command *cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, cmdObj);
    const char *bytes;
    Command *cmdPtr;
    int cmdLitIdx, extraLiteralFlags = LITERAL_CMD_NAME;

    cmdPtr = (Command *) Tcl_GetCommandFromObj(interp, cmdObj);
    if ((cmdPtr != NULL) && (cmdPtr->flags & CMD_VIA_RESOLVER)) {
	extraLiteralFlags |= LITERAL_UNSHARED;
    }

    bytes = Tcl_GetStringFromObj(cmdObj, &numBytes);
    cmdLitIdx = TclRegisterLiteral(envPtr, (char *)bytes, numBytes, extraLiteralFlags);

    if (cmdPtr) {
	TclSetCmdNameObj(interp, TclFetchLiteral(envPtr, cmdLitIdx), cmdPtr);
    }
    TclEmitPush(cmdLitIdx, envPtr);
}

Changes to generic/tclCompile.h.
1204
1205
1206
1207
1208
1209
1210

1211
1212
1213
1214
1215
1216
1217
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218







+







 */

#define TclFetchAuxData(envPtr, index) \
    (envPtr)->auxDataArrayPtr[(index)].clientData

#define LITERAL_ON_HEAP		0x01
#define LITERAL_CMD_NAME	0x02
#define LITERAL_UNSHARED	0x04

/*
 * Form of TclRegisterLiteral with flags == 0. In that case, it is safe to
 * cast away constness, and it is cleanest to do that here, all in one place.
 *
 * int TclRegisterNewLiteral(CompileEnv *envPtr, const char *bytes,
 *			     int length);
Changes to generic/tclEnsemble.c.
3302
3303
3304
3305
3306
3307
3308
3309

3310
3311
3312
3313
3314
3315
3316
3302
3303
3304
3305
3306
3307
3308

3309
3310
3311
3312
3313
3314
3315
3316







-
+







    Tcl_Obj *replacements,
    Command *cmdPtr,
    CompileEnv *envPtr)		/* Holds resulting instructions. */
{
    Tcl_Token *tokPtr;
    Tcl_Obj *objPtr, **words;
    char *bytes;
    int length, i, numWords, cmdLit;
    int length, i, numWords, cmdLit, extraLiteralFlags = LITERAL_CMD_NAME;
    DefineLineInformation;

    /*
     * Push the words of the command. Take care; the command words may be
     * scripts that have backslashes in them, and [info frame 0] can see the
     * difference. Hence the call to TclContinuationsEnterDerived...
     */
3345
3346
3347
3348
3349
3350
3351



3352

3353
3354
3355
3356
3357
3358
3359
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354

3355
3356
3357
3358
3359
3360
3361
3362







+
+
+
-
+







     * Push the name of the command we're actually dispatching to as part of
     * the implementation.
     */

    objPtr = Tcl_NewObj();
    Tcl_GetCommandFullName(interp, (Tcl_Command) cmdPtr, objPtr);
    bytes = Tcl_GetStringFromObj(objPtr, &length);
    if ((cmdPtr != NULL) && (cmdPtr->flags & CMD_VIA_RESOLVER)) {
	extraLiteralFlags |= LITERAL_UNSHARED;
    }
    cmdLit = TclRegisterNewCmdLiteral(envPtr, bytes, length);
    cmdLit = TclRegisterLiteral(envPtr, (char *)bytes, length, extraLiteralFlags);
    TclSetCmdNameObj(interp, TclFetchLiteral(envPtr, cmdLit), cmdPtr);
    TclEmitPush(cmdLit, envPtr);
    TclDecrRefCount(objPtr);

    /*
     * Do the replacing dispatch.
     */
Changes to generic/tclInt.h.
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683




1684


1685
1686
1687
1688
1689
1690
1691
1673
1674
1675
1676
1677
1678
1679




1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693







-
-
-
-
+
+
+
+

+
+







 * TCL_TRACE_RENAME -		A rename trace is in progress. Further
 *				recursive renames will not be traced.
 * TCL_TRACE_DELETE -		A delete trace is in progress. Further
 *				recursive deletes will not be traced.
 * (these last two flags are defined in tcl.h)
 */

#define CMD_IS_DELETED		    0x1
#define CMD_TRACE_ACTIVE	    0x2
#define CMD_HAS_EXEC_TRACES	    0x4
#define CMD_COMPILES_EXPANDED	    0x8
#define CMD_IS_DELETED		    0x01
#define CMD_TRACE_ACTIVE	    0x02
#define CMD_HAS_EXEC_TRACES	    0x04
#define CMD_COMPILES_EXPANDED	    0x08
#define CMD_REDEF_IN_PROGRESS	    0x10
#define CMD_VIA_RESOLVER	    0x20


/*
 *----------------------------------------------------------------
 * Data structures related to name resolution procedures.
 *----------------------------------------------------------------
 */

Changes to generic/tclLiteral.c.
237
238
239
240
241
242
243










244
245
246
247
248
249
250
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260







+
+
+
+
+
+
+
+
+
+







    Tcl_IncrRefCount(objPtr);
    if (flags & LITERAL_ON_HEAP) {
	objPtr->bytes = bytes;
	objPtr->length = length;
    } else {
	TclInitStringRep(objPtr, bytes, length);
    }

    if (flags & LITERAL_UNSHARED) {
	/*
	 * Make clear, that no global value is returned
	 */
	if (globalPtrPtr != NULL) {
	    *globalPtrPtr = NULL;
	}
	return objPtr;
    }

#ifdef TCL_COMPILE_DEBUG
    if (LookupLiteralEntry((Tcl_Interp *) iPtr, objPtr) != NULL) {
	Tcl_Panic("%s: literal \"%.*s\" found globally but shouldn't be",
		"TclRegisterLiteral", (length>60? 60 : length), bytes);
    }
#endif
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1159
1160
1161
1162
1163
1164
1165







1166
1167
1168
1169
1170
1171
1172







-
-
-
-
-
-
-







	    count++;
	    if (localPtr->refCount != -1) {
		bytes = Tcl_GetStringFromObj(localPtr->objPtr, &length);
		Tcl_Panic("%s: local literal \"%.*s\" had bad refCount %d",
			"TclVerifyLocalLiteralTable",
			(length>60? 60 : length), bytes, localPtr->refCount);
	    }
	    if (LookupLiteralEntry((Tcl_Interp *) envPtr->iPtr,
		    localPtr->objPtr) == NULL) {
		bytes = Tcl_GetStringFromObj(localPtr->objPtr, &length);
		Tcl_Panic("%s: local literal \"%.*s\" is not global",
			"TclVerifyLocalLiteralTable",
			(length>60? 60 : length), bytes);
	    }
	    if (localPtr->objPtr->bytes == NULL) {
		Tcl_Panic("%s: literal has NULL string rep",
			"TclVerifyLocalLiteralTable");
	    }
	}
    }
    if (count != localTablePtr->numEntries) {
Changes to generic/tclNamesp.c.
2562
2563
2564
2565
2566
2567
2568

2569

2570
2571
2572
2573
2574
2575
2576
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578







+

+







		result = resPtr->cmdResProc(interp, name,
			(Tcl_Namespace *) cxtNsPtr, flags, &cmd);
	    }
	    resPtr = resPtr->nextPtr;
	}

	if (result == TCL_OK) {
	    ((Command *)cmd)->flags |= CMD_VIA_RESOLVER;
	    return cmd;

	} else if (result != TCL_CONTINUE) {
	    return NULL;
	}
    }

    /*
     * Find the namespace(s) that contain the command.
2654
2655
2656
2657
2658
2659
2660

2661
2662
2663
2664
2665
2666
2667
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670







+







		    cmdPtr = Tcl_GetHashValue(entryPtr);
		}
	    }
	}
    }

    if (cmdPtr != NULL) {
	cmdPtr->flags  &= ~CMD_VIA_RESOLVER;
	return (Tcl_Command) cmdPtr;
    }

    if (flags & TCL_LEAVE_ERR_MSG) {
	Tcl_SetObjResult(interp, Tcl_ObjPrintf(
                "unknown command \"%s\"", name));
	Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "COMMAND", name, NULL);
Changes to generic/tclObj.c.
4215
4216
4217
4218
4219
4220
4221


4222


4223
4224
4225
4226
4227
4228
4229
4215
4216
4217
4218
4219
4220
4221
4222
4223

4224
4225
4226
4227
4228
4229
4230
4231
4232







+
+
-
+
+







{
    Interp *iPtr = (Interp *) interp;
    register ResolvedCmdName *resPtr;
    register Namespace *currNsPtr;
    const char *name;

    if (objPtr->typePtr == &tclCmdNameType) {
	resPtr = objPtr->internalRep.twoPtrValue.ptr1;
	if (resPtr != NULL && resPtr->cmdPtr == cmdPtr) {
	return;
	    return;
	}
    }

    cmdPtr->refCount++;
    resPtr = ckalloc(sizeof(ResolvedCmdName));
    resPtr->cmdPtr = cmdPtr;
    resPtr->cmdEpoch = cmdPtr->cmdEpoch;
    resPtr->refCount = 1;
Changes to generic/tclTest.c.
7295
7296
7297
7298
7299
7300
7301


7302
7303








7304

7305
7306
7307























7308
7309
7310
7311
7312
7313
7314
7315
7316
7317







































7318
7319
7320
7321
7322
7323
7324
7325
7295
7296
7297
7298
7299
7300
7301
7302
7303


7304
7305
7306
7307
7308
7309
7310
7311
7312
7313



7314
7315
7316
7317
7318
7319
7320
7321
7322
7323
7324
7325
7326
7327
7328
7329
7330
7331
7332
7333
7334
7335
7336
7337
7338








7339
7340
7341
7342
7343
7344
7345
7346
7347
7348
7349
7350
7351
7352
7353
7354
7355
7356
7357
7358
7359
7360
7361
7362
7363
7364
7365
7366
7367
7368
7369
7370
7371
7372
7373
7374
7375
7376
7377

7378
7379
7380
7381
7382
7383
7384







+
+
-
-
+
+
+
+
+
+
+
+

+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+


-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-







    int flags,
    Tcl_Command *rPtr)
{
    Interp *iPtr = (Interp *) interp;
    CallFrame *varFramePtr = iPtr->varFramePtr;
    Proc *procPtr = (varFramePtr->isProcCallFrame & FRAME_IS_PROC) ?
            varFramePtr->procPtr : NULL;
    Namespace *callerNsPtr = varFramePtr->nsPtr;
    Tcl_Command resolvedCmdPtr = NULL;
    Namespace *ns2NsPtr = (Namespace *)
            Tcl_FindNamespace(interp, "::ns2", NULL, 0);

    /*
     * Just do something special on a cmd literal "z" in two cases:
     *  A)  when the caller is a proc "x", and the proc is either in "::" or in "::ns2".
     *  B) the caller's namespace is "ctx1" or "ctx2"
     */
    if ( (name[0] == 'z') && (name[1] == '\0') ) {
        Namespace *ns2NsPtr = (Namespace *) Tcl_FindNamespace(interp, "::ns2", NULL, 0);

        if (procPtr != NULL
    if (procPtr && (procPtr->cmdPtr->nsPtr == iPtr->globalNsPtr
            || (ns2NsPtr && procPtr->cmdPtr->nsPtr == ns2NsPtr))) {
        const char *callingCmdName =
            && ((procPtr->cmdPtr->nsPtr == iPtr->globalNsPtr)
                || (ns2NsPtr != NULL && procPtr->cmdPtr->nsPtr == ns2NsPtr)
                )
            ) {
            /*
             * Case A)
             *
             *    - The context, in which this resolver becomes active, is
             *      determined by the name of the caller proc, which has to be
             *      named "x".
             *
             *    - To determine the name of the caller proc, the proc is taken
             *      from the topmost stack frame.
             *
             *    - Note that the context is NOT provided during byte-code
             *      compilation (e.g. in TclProcCompileProc)
             *
             *   When these conditions hold, this function resolves the
             *   passed-in cmd literal into a cmd "y", which is taken from the
             *   the global namespace (for simplicity).
             */

            const char *callingCmdName =
                Tcl_GetCommandName(interp, (Tcl_Command) procPtr->cmdPtr);

        if ((callingCmdName[0] == 'x') && (callingCmdName[1] == '\0')
                && (name[0] == 'z') && (name[1] == '\0')) {
            Tcl_Command sourceCmdPtr = Tcl_FindCommand(interp, "y", NULL,
                    TCL_GLOBAL_ONLY);

            if (sourceCmdPtr != NULL) {
                *rPtr = sourceCmdPtr;
                return TCL_OK;
            if ( callingCmdName[0] == 'x' && callingCmdName[1] == '\0' ) {
                resolvedCmdPtr = Tcl_FindCommand(interp, "y", NULL, TCL_GLOBAL_ONLY);
            }
        } else if (callerNsPtr != NULL) {
            /*
             * Case B)
             *
             *    - The context, in which this resolver becomes active, is
             *      determined by the name of the parent namespace, which has
             *      to be named "ctx1" or "ctx2".
             *
             *    - To determine the name of the parent namesace, it is taken
             *      from the 2nd highest stack frame.
             *
             *    - Note that the context can be provided during byte-code
             *      compilation (e.g. in TclProcCompileProc)
             *
             *   When these conditions hold, this function resolves the
             *   passed-in cmd literal into a cmd "y" or "Y" depending on the
             *   context. The resolved procs are taken from the the global
             *   namespace (for simplicity).
             */

            CallFrame *parentFramePtr = varFramePtr->callerPtr;
            char *context = parentFramePtr != NULL ? parentFramePtr->nsPtr->name : "(NULL)";

            if (strcmp(context, "ctx1") == 0 && (name[0] == 'z') && (name[1] == '\0')) {
                resolvedCmdPtr = Tcl_FindCommand(interp, "y", NULL, TCL_GLOBAL_ONLY);
                /* fprintf(stderr, "... y ==> %p\n", resolvedCmdPtr);*/

            } else if (strcmp(context, "ctx2") == 0 && (name[0] == 'z') && (name[1] == '\0')) {
                resolvedCmdPtr = Tcl_FindCommand(interp, "Y", NULL, TCL_GLOBAL_ONLY);
                /*fprintf(stderr, "... Y ==> %p\n", resolvedCmdPtr);*/
            }
        }

        if (resolvedCmdPtr != NULL) {
            *rPtr = resolvedCmdPtr;
            return TCL_OK;
            }
        }
    }
    return TCL_CONTINUE;
}

static int
InterpVarResolver(
Changes to tests/resolver.test.
192
193
194
195
196
197
198



















































































































199
200
201
202
203
204
205
192
193
194
195
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
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







    x
    # When the proc is freed, the resolver-specific resolver var info is
    # freed. This did not happen before fix #3383616.
    rename ::x ""
} -cleanup {
    testinterpresolver down
} -result {}


#
# The test resolver-3.1* test bad interactions of resolvers on the "global"
# (per interp) literal pools. A resolver might resolve a cmd literal depending
# on a context differently, whereas the cmd literal sharing assumed that the
# namespace containing the literal solely determines the resolved cmd (and is
# resolver-agnostic).
#
# In order to make the test cases for the per-interpreter cmd literal pool
# reproducable and to minimize interactions between test cases, we use a slave
# interpreter per test-case.
#
#
# Testing resolver in namespace-based context "ctx1"
#
test resolver-3.1a {
    interp command resolver,
    resolve literal "z" in proc "x1" in context "ctx1"
} -setup {

    interp create i0
    testinterpresolver up i0
    i0 eval {
	proc y {} { return yy }
	namespace eval ::ns {
	    proc x1 {} { z }
	}
    }
} -constraints testinterpresolver -body {

    set r [i0 eval {namespace eval ::ctx1 {
	::ns::x1
    }}]

    return $r
} -cleanup {
    testinterpresolver down i0
    interp delete i0
} -result {yy}

#
# Testing resolver in namespace-based context "ctx2"
#
test resolver-3.1b {
    interp command resolver,
    resolve literal "z" in proc "x2" in context "ctx2"
} -setup {

    interp create i0
    testinterpresolver up i0
    i0 eval {
	proc Y {} { return YY }
	namespace eval ::ns {
	    proc x2 {} { z }
	}
    }
} -constraints testinterpresolver -body {

    set r [i0 eval {namespace eval ::ctx2 {
	::ns::x2
    }}]

    return $r
} -cleanup {
    testinterpresolver down i0
    interp delete i0
} -result {YY}

#
# Testing resolver in namespace-based context "ctx1" and "ctx2" in the same
# interpreter.
#

test resolver-3.1c {
    interp command resolver,
    resolve literal "z" in proc "x1" in context "ctx1",
    resolve literal "z" in proc "x2" in context "ctx2"

    Test, whether the shared cmd literal created by the first byte-code
    compilation interacts with the second one.
} -setup {

    interp create i0
    testinterpresolver up i0

    i0 eval {
	proc y {} { return yy }
	proc Y {} { return YY }
	namespace eval ::ns {
	    proc x1 {} { z }
	    proc x2 {} { z }
	}
    }

} -constraints testinterpresolver -body {

    set r1 [i0 eval {namespace eval ::ctx1 {
	::ns::x1
    }}]

    set r2 [i0 eval {namespace eval ::ctx2 {
	::ns::x2
    }}]

    set r3 [i0 eval {namespace eval ::ctx1 {
	::ns::x1
    }}]

    return [list $r1 $r2 $r3]
} -cleanup {
    testinterpresolver down i0
    interp delete i0
} -result {yy YY yy}


cleanupTests
return

# Local Variables:
# mode: tcl
# fill-column: 78