From 07279ebb64ef3359cd341e8ef7f8f99ea36dedd1 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Sun, 29 Oct 2023 21:45:31 +0000 Subject: Fix [0219fb7511]: tclIO.c: avoid -Wstrict-prototypes warning. Some code cleanup --- generic/tclIO.c | 120 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 62 insertions(+), 58 deletions(-) diff --git a/generic/tclIO.c b/generic/tclIO.c index 7e83e89..0f79f1e 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -103,7 +103,7 @@ typedef struct CopyState { Tcl_Interp *interp; /* Interp that started the copy. */ Tcl_Obj *cmdPtr; /* Command to be invoked at completion. */ int bufSize; /* Size of appended buffer. */ - char buffer[1]; /* Copy buffer, this must be the last + char buffer[TCLFLEXARRAY]; /* Copy buffer, this must be the last * field. */ } CopyState; @@ -557,7 +557,6 @@ TclInitIOSubsystem(void) *------------------------------------------------------------------------- */ - /* ARGSUSED */ void TclFinalizeIOSubsystem(void) { @@ -1444,7 +1443,7 @@ Tcl_GetChannel( if (hPtr == NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "can not find channel named \"%s\"", chanName)); - Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CHANNEL", chanName, NULL); + Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "CHANNEL", chanName, (void *)NULL); return NULL; } @@ -1457,7 +1456,7 @@ Tcl_GetChannel( chanPtr = (Channel *)Tcl_GetHashValue(hPtr); chanPtr = chanPtr->state->bottomChanPtr; if (modePtr != NULL) { - *modePtr = chanPtr->state->flags & (TCL_READABLE|TCL_WRITABLE); + *modePtr = GotFlag(chanPtr->state, TCL_READABLE|TCL_WRITABLE); } return (Tcl_Channel) chanPtr; @@ -1553,7 +1552,7 @@ TclGetChannelFromObj( *channelPtr = (Tcl_Channel) statePtr->bottomChanPtr; if (modePtr != NULL) { - *modePtr = statePtr->flags & (TCL_READABLE|TCL_WRITABLE); + *modePtr = GotFlag(statePtr, TCL_READABLE|TCL_WRITABLE); } return TCL_OK; @@ -1847,7 +1846,7 @@ Tcl_StackChannel( * --+---+---+---+----+ */ - if ((mask & (statePtr->flags & (TCL_READABLE | TCL_WRITABLE))) == 0) { + if ((mask & GotFlag(statePtr, TCL_READABLE|TCL_WRITABLE)) == 0) { if (interp) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "reading and writing both disallowed for channel \"%s\"", @@ -2345,7 +2344,7 @@ Tcl_GetChannelMode( ChannelState *statePtr = ((Channel *) chan)->state; /* State of actual channel. */ - return (statePtr->flags & (TCL_READABLE | TCL_WRITABLE)); + return GotFlag(statePtr, TCL_READABLE|TCL_WRITABLE); } /* @@ -2529,7 +2528,7 @@ RecycleBuffer( * This is to honor dynamic changes of the buffe rsize made by the user. */ - if ((bufPtr->bufLength - BUFFER_PADDING) != statePtr->bufSize) { + if ((bufPtr->bufLength) != statePtr->bufSize + BUFFER_PADDING) { ReleaseChannelBuffer(bufPtr); return; } @@ -2850,8 +2849,8 @@ FlushChannel( * queued. */ - DiscardOutputQueued(statePtr); ReleaseChannelBuffer(bufPtr); + DiscardOutputQueued(statePtr); break; } else { /* @@ -3360,7 +3359,6 @@ Tcl_SpliceChannel( *---------------------------------------------------------------------- */ - /* ARGSUSED */ int Tcl_Close( Tcl_Interp *interp, /* Interpreter for errors. */ @@ -3554,7 +3552,6 @@ Tcl_Close( *---------------------------------------------------------------------- */ - /* ARGSUSED */ int Tcl_CloseEx( Tcl_Interp *interp, /* Interpreter for errors. */ @@ -3609,7 +3606,7 @@ Tcl_CloseEx( * opened for that direction). */ - if (!(statePtr->flags & (TCL_READABLE | TCL_WRITABLE) & flags)) { + if (!(GotFlag(statePtr, TCL_READABLE|TCL_WRITABLE) & flags)) { const char *msg; if (flags & TCL_CLOSE_READ) { @@ -3628,7 +3625,7 @@ Tcl_CloseEx( * That won't do. */ - if (statePtr->flags & CHANNEL_INCLOSE) { + if (GotFlag(statePtr, CHANNEL_INCLOSE)) { if (interp) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "illegal recursive call to close through close-handler" @@ -4065,7 +4062,8 @@ Tcl_WriteRaw( Channel *chanPtr = ((Channel *) chan); ChannelState *statePtr = chanPtr->state; /* State info for channel */ - int errorCode, written; + int errorCode; + int written; if (CheckChannelErrors(statePtr, TCL_WRITABLE | CHANNEL_RAW_MODE) != 0) { return -1; @@ -4282,13 +4280,14 @@ static int Write( Channel *chanPtr, /* The channel to buffer output for. */ const char *src, /* UTF-8 string to write. */ - int srcLen, /* Length of UTF-8 string in bytes. */ + int srcLen, /* Length of UTF-8 string in bytes. */ Tcl_Encoding encoding) { ChannelState *statePtr = chanPtr->state; /* State info for channel */ char *nextNewLine = NULL; - int endEncoding, saved = 0, total = 0, flushed = 0, needNlFlush = 0; + int endEncoding, needNlFlush = 0; + int saved = 0, total = 0, flushed = 0; char safe[BUFFER_PADDING]; int encodingError = 0; @@ -4301,7 +4300,6 @@ Write( */ endEncoding = ((statePtr->outputEncodingFlags & TCL_ENCODING_END) != 0); - if (GotFlag(statePtr, CHANNEL_LINEBUFFERED) || (statePtr->outputTranslation != TCL_TRANSLATE_LF)) { nextNewLine = (char *)memchr(src, '\n', srcLen); @@ -4310,7 +4308,8 @@ Write( while (srcLen + saved + endEncoding > 0 && !encodingError) { ChannelBuffer *bufPtr; char *dst; - int result, srcRead, dstLen, dstWrote, srcLimit = srcLen; + int result, srcRead, dstLen, dstWrote; + int srcLimit = srcLen; if (nextNewLine) { srcLimit = nextNewLine - src; @@ -4527,7 +4526,8 @@ Tcl_GetsObj( ChannelState *statePtr = chanPtr->state; /* State info for channel */ ChannelBuffer *bufPtr; - int inEofChar, skip, copiedTotal, oldLength, oldFlags, oldRemoved; + int inEofChar, skip, copiedTotal, oldFlags, oldRemoved; + int oldLength; Tcl_Encoding encoding; char *dst, *dstEnd, *eol, *eof; Tcl_EncodingState oldState; @@ -5208,7 +5208,7 @@ FreeBinaryEncoding( } static Tcl_Encoding -GetBinaryEncoding() +GetBinaryEncoding(void) { ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); @@ -5352,6 +5352,7 @@ FilterInputBytes( *gsPtr->dstPtr = dst; } gsPtr->state = statePtr->inputEncodingState; + result = Tcl_ExternalToUtf(NULL, gsPtr->encoding, raw, rawLen, statePtr->inputEncodingFlags | TCL_ENCODING_NO_TERMINATE, &statePtr->inputEncodingState, dst, spaceLeft, &gsPtr->rawRead, @@ -5752,7 +5753,7 @@ int Tcl_ReadChars( Tcl_Channel chan, /* The channel to read. */ Tcl_Obj *objPtr, /* Input data is stored in this object. */ - int toRead, /* Maximum number of characters to store, or + int toRead, /* Maximum number of characters to store, or * -1 to read all available data (up to EOF or * when channel blocks). */ int appendFlag) /* If non-zero, data read from the channel @@ -5808,7 +5809,7 @@ static int DoReadChars( Channel *chanPtr, /* The channel to read. */ Tcl_Obj *objPtr, /* Input data is stored in this object. */ - int toRead, /* Maximum number of characters to store, or + int toRead, /* Maximum number of characters to store, or * -1 to read all available data (up to EOF or * when channel blocks). */ int appendFlag) /* If non-zero, data read from the channel @@ -5819,7 +5820,8 @@ DoReadChars( ChannelState *statePtr = chanPtr->state; /* State info for channel */ ChannelBuffer *bufPtr; - int copied, copiedNow, result; + int copied; + int result; Tcl_Encoding encoding = statePtr->encoding; int binaryMode; #define UTF_EXPANSION_FACTOR 1024 @@ -5859,7 +5861,7 @@ DoReadChars( assert(statePtr->inputEncodingFlags & TCL_ENCODING_END); assert(!GotFlag(statePtr, CHANNEL_BLOCKED|INPUT_SAW_CR)); - /* TODO: We don't need this call? */ + /* TODO: UpdateInterest not needed here? */ UpdateInterest(chanPtr); return 0; } @@ -5873,7 +5875,7 @@ DoReadChars( } ResetFlag(statePtr, CHANNEL_BLOCKED|CHANNEL_EOF); statePtr->inputEncodingFlags &= ~TCL_ENCODING_END; - /* TODO: We don't need this call? */ + /* TODO: UpdateInterest not needed here? */ UpdateInterest(chanPtr); return 0; } @@ -5895,7 +5897,7 @@ DoReadChars( ResetFlag(statePtr, CHANNEL_BLOCKED|CHANNEL_EOF); statePtr->inputEncodingFlags &= ~TCL_ENCODING_END; for (copied = 0; (unsigned) toRead > 0; ) { - copiedNow = -1; + int copiedNow = -1; if (statePtr->inQueueHead != NULL) { if (binaryMode) { copiedNow = ReadBytes(statePtr, objPtr, toRead); @@ -5904,7 +5906,7 @@ DoReadChars( } /* - * If the current buffer is empty recycle it. + * Recycle current buffer if empty. */ bufPtr = statePtr->inQueueHead; @@ -5956,7 +5958,7 @@ DoReadChars( } /* - * Regenerate the top channel, in case it was changed due to + * Regenerate chanPtr in case it was changed due to * self-modifying reflected transforms. */ @@ -6300,7 +6302,7 @@ ReadChars( return 1; } - } else if (statePtr->flags & CHANNEL_EOF) { + } else if (GotFlag(statePtr, CHANNEL_EOF)) { /* * The bare \r is the only char and we will never read a * subsequent char to make the determination. @@ -6403,7 +6405,7 @@ ReadChars( * precautions. */ - if (nextPtr->nextRemoved - srcLen < 0) { + if (nextPtr->nextRemoved < srcLen) { Tcl_Panic("Buffer Underflow, BUFFER_PADDING not enough"); } @@ -6566,7 +6568,7 @@ TranslateInputEOL( char *dst = dstStart; int lesser; - if ((statePtr->flags & INPUT_SAW_CR) && srcLen) { + if (GotFlag(statePtr, INPUT_SAW_CR) && srcLen) { if (*src == '\n') { src++; srcLen--; } ResetFlag(statePtr, INPUT_SAW_CR); } @@ -6900,7 +6902,7 @@ GetInput( */ if ((bufPtr != NULL) - && (bufPtr->bufLength - BUFFER_PADDING != statePtr->bufSize)) { + && (bufPtr->bufLength != statePtr->bufSize + BUFFER_PADDING)) { ReleaseChannelBuffer(bufPtr); bufPtr = NULL; } @@ -7370,7 +7372,7 @@ CheckChannelErrors( * Fail if the channel is not opened for desired operation. */ - if ((statePtr->flags & direction) == 0) { + if (GotFlag(statePtr, direction) == 0) { Tcl_SetErrno(EACCES); return -1; } @@ -7480,7 +7482,7 @@ Tcl_InputBuffered( } /* - * Don't forget the bytes in the topmost pushback area. + * Remember the bytes in the topmost pushback area. */ for (bufPtr = statePtr->topChanPtr->inQueueHead; bufPtr != NULL; @@ -8690,7 +8692,7 @@ Tcl_CreateChannelHandler( /* * The remainder of the initialization below is done regardless of whether - * or not this is a new record or a modification of an old one. + * this is a new record or a modification of an old one. */ chPtr->mask = mask; @@ -9004,7 +9006,6 @@ TclChannelEventScriptInvoker( *---------------------------------------------------------------------- */ - /* ARGSUSED */ int Tcl_FileEventObjCmd( ClientData dummy, /* Not used. */ @@ -9040,7 +9041,7 @@ Tcl_FileEventObjCmd( } chanPtr = (Channel *) chan; statePtr = chanPtr->state; - if ((statePtr->flags & mask) == 0) { + if (GotFlag(statePtr, mask) == 0) { Tcl_SetObjResult(interp, Tcl_ObjPrintf("channel is not %s", (mask == TCL_READABLE) ? "readable" : "writable")); return TCL_ERROR; @@ -9225,7 +9226,7 @@ TclCopyChannel( * completed. */ - csPtr = (CopyState *)ckalloc(sizeof(CopyState) + !moveBytes * inStatePtr->bufSize); + csPtr = (CopyState *)ckalloc(offsetof(CopyState, buffer) + 1U + !moveBytes * inStatePtr->bufSize); csPtr->bufSize = !moveBytes * inStatePtr->bufSize; csPtr->readPtr = inPtr; csPtr->writePtr = outPtr; @@ -9415,13 +9416,13 @@ MBWrite( if (bufPtr) { /* Split the overflowing buffer in two */ int extra = (int) (inBytes - csPtr->toRead); - /* Note that going with int for extra assumes that inBytes is not too - * much over toRead to require a wide itself. If that gets violated - * then the calculations involving extra must be made wide too. - * - * Noted with Win32/MSVC debug build treating the warning (possible of - * data in __int64 to int conversion) as error. - */ + /* Note that going with int for extra assumes that inBytes is not too + * much over toRead to require a wide itself. If that gets violated + * then the calculations involving extra must be made wide too. + * + * Noted with Win32/MSVC debug build treating the warning (possible of + * data in __int64 to int conversion) as error. + */ bufPtr = AllocChannelBuffer(extra); @@ -9519,8 +9520,10 @@ CopyData( Tcl_Obj *cmdPtr, *errObj = NULL, *bufObj = NULL, *msg = NULL; Tcl_Channel inChan, outChan; ChannelState *inStatePtr, *outStatePtr; - int result = TCL_OK, size, sizeb; + int result = TCL_OK; + int sizeb; Tcl_WideInt total; + int size; const char *buffer; int inBinary, outBinary, sameEncoding; /* Encoding control */ @@ -9603,12 +9606,12 @@ CopyData( if (interp) { TclNewObj(errObj); Tcl_AppendStringsToObj(errObj, "error reading \"", - Tcl_GetChannelName(inChan), "\": ", NULL); + Tcl_GetChannelName(inChan), "\": ", (void *)NULL); if (msg != NULL) { Tcl_AppendObjToObj(errObj, msg); } else { Tcl_AppendStringsToObj(errObj, Tcl_PosixError(interp), - NULL); + (void *)NULL); } } if (msg != NULL) { @@ -9684,12 +9687,12 @@ CopyData( if (interp) { TclNewObj(errObj); Tcl_AppendStringsToObj(errObj, "error writing \"", - Tcl_GetChannelName(outChan), "\": ", NULL); + Tcl_GetChannelName(outChan), "\": ", (void *)NULL); if (msg != NULL) { Tcl_AppendObjToObj(errObj, msg); } else { Tcl_AppendStringsToObj(errObj, Tcl_PosixError(interp), - NULL); + (void *)NULL); } } if (msg != NULL) { @@ -9985,7 +9988,7 @@ DoRead( * There's no more buffered data... */ - if (statePtr->flags & CHANNEL_EOF) { + if (GotFlag(statePtr, CHANNEL_EOF)) { /* * ...and there never will be. */ @@ -9993,7 +9996,7 @@ DoRead( *p++ = '\r'; bytesToRead--; bufPtr->nextRemoved++; - } else if (statePtr->flags & CHANNEL_BLOCKED) { + } else if (GotFlag(statePtr, CHANNEL_BLOCKED)) { /* * ...and we cannot get more now. */ @@ -10126,20 +10129,20 @@ StopCopy( */ nonBlocking = csPtr->readFlags & CHANNEL_NONBLOCKING; - if (nonBlocking != (inStatePtr->flags & CHANNEL_NONBLOCKING)) { + if (nonBlocking != GotFlag(inStatePtr, CHANNEL_NONBLOCKING)) { SetBlockMode(NULL, csPtr->readPtr, nonBlocking ? TCL_MODE_NONBLOCKING : TCL_MODE_BLOCKING); } if (csPtr->readPtr != csPtr->writePtr) { nonBlocking = csPtr->writeFlags & CHANNEL_NONBLOCKING; - if (nonBlocking != (outStatePtr->flags & CHANNEL_NONBLOCKING)) { + if (nonBlocking != GotFlag(outStatePtr, CHANNEL_NONBLOCKING)) { SetBlockMode(NULL, csPtr->writePtr, nonBlocking ? TCL_MODE_NONBLOCKING : TCL_MODE_BLOCKING); } } ResetFlag(outStatePtr, CHANNEL_LINEBUFFERED | CHANNEL_UNBUFFERED); - outStatePtr->flags |= - csPtr->writeFlags & (CHANNEL_LINEBUFFERED | CHANNEL_UNBUFFERED); + SetFlag(outStatePtr, + csPtr->writeFlags & (CHANNEL_LINEBUFFERED | CHANNEL_UNBUFFERED)); if (csPtr->cmdPtr) { Tcl_DeleteChannelHandler(inChan, CopyEventProc, csPtr); @@ -11011,7 +11014,8 @@ static Tcl_Obj * FixLevelCode( Tcl_Obj *msg) { - int explicitResult, numOptions, lc, lcn; + int explicitResult, numOptions, lcn; + int lc; Tcl_Obj **lv, **lvn; int res, i, j, val, lignore, cignore; int newlevel = -1, newcode = -1; @@ -11304,8 +11308,8 @@ DumpFlags( char *str, int flags) { - char buf[20]; int i = 0; + char buf[24]; #define ChanFlag(chr, bit) (buf[i++] = ((flags & (bit)) ? (chr) : '_')) -- cgit v0.12 From 05adca525608343e116de898ff6f3b0cd3300429 Mon Sep 17 00:00:00 2001 From: oehhar Date: Fri, 3 Nov 2023 11:25:01 +0000 Subject: Ticket [21b0629c] introduced additional exec quoting for Windows, but did not document it. Here is a proposed documentation. --- doc/exec.n | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/doc/exec.n b/doc/exec.n index d7fd96b..dc1c8c5 100644 --- a/doc/exec.n +++ b/doc/exec.n @@ -234,6 +234,37 @@ processor (\fBcmd.exe /c\fR), because this causes truncation of command-line (also the argument chain) on the first newline character. But it works properly with an executable (using CommandLineToArgv, etc). .PP +\fBVulnerable arguments\fR +.RS +If invoking batch files or other specific programs, the Windows environment +does execute programs mentioned in the arguments or replace environment +variables, which may breake any already existing quoting (for example, if the +environment variable contains a special character like a \fB"\fR). +Examples are: +.CS +% exec my-echo.cmd {test&whoami} + test + mylogin +% exec my-echo.cmd "ENV X:%X%" + ENV X: CONTENT OF X +.CE +This might be seen as a vulnerability. In consequence, the following formatting +is automatically performed on any argument item: +.IP \(bu 3 +Avoid subprogram execution: +Any non-paired special +characters (\fB&\fR, \fB|\fR, \fB^\fR, \fB<\fR, \fB>\fR, \fB!\fR, \fB(\fR, +\fB)\fR, \fB(\fR, \fB%\fR) are automatically enclosed in quotes (\fB"\fR). +.IP \(bu 3 +Avoid environment variable replacement: +Any appearence of environment variable reference (\fB%\fR) is individually quoted +by \fB"\fR. +.PP +This quoting was introduced in TCL 8.6.10 breaking present scripts which rely on +the replacement functionality to avoid. A solution with command parameters is +envisaged for TCL 8.6.14. +.RE +.PP The Tk console text widget does not provide real standard IO capabilities. Under Tk, when redirecting from standard input, all applications will see an immediate end-of-file; information redirected to standard output or standard -- cgit v0.12 From 2ffcfc525bbdf699b316eadff19d2f55139b608a Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 3 Nov 2023 13:23:08 +0000 Subject: test constraint housekeeping --- tests/winFCmd.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/winFCmd.test b/tests/winFCmd.test index 3d0a9e0..fe50043 100644 --- a/tests/winFCmd.test +++ b/tests/winFCmd.test @@ -50,7 +50,7 @@ proc contents {file} { proc cleanupRecurse {args} { # Assumes no loops via links! # Need to change permissions BEFORE deletion - testchmod 0o777 {*}$args + catch {testchmod 0o777 {*}$args} foreach victim $args { if {[file isdirectory $victim]} { cleanupRecurse {*}[glob -nocomplain -directory $victim td* tf* Test*] @@ -500,7 +500,7 @@ test winFCmd-2.11 {TclpCopyFile: CopyFile succeeds} -setup { } -result {tf1 tf1} test winFCmd-2.12 {TclpCopyFile: CopyFile succeeds} -setup { cleanup -} -constraints {win testfile} -body { +} -constraints {win testfile testchmod} -body { createfile tf1 tf1 file attribute tf1 -readonly 1 testfile cp tf1 tf2 -- cgit v0.12 From 352f3ff588c3d6ca7b832fd69a88416d9ea0c0f9 Mon Sep 17 00:00:00 2001 From: oehhar Date: Mon, 6 Nov 2023 16:36:58 +0000 Subject: Exec documentation: refine Windows quoting section (thanks, Sergey !) --- doc/exec.n | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/doc/exec.n b/doc/exec.n index dc1c8c5..4024ffe 100644 --- a/doc/exec.n +++ b/doc/exec.n @@ -234,12 +234,17 @@ processor (\fBcmd.exe /c\fR), because this causes truncation of command-line (also the argument chain) on the first newline character. But it works properly with an executable (using CommandLineToArgv, etc). .PP -\fBVulnerable arguments\fR +\fBArgument quoting\fR .RS +Each argument of the \fBexec\fR command is mapped to an argument of the called +program by an adaptive quoting by adding quote characters (\fB"\fR) around the +arguments. +.PP If invoking batch files or other specific programs, the Windows environment does execute programs mentioned in the arguments or replace environment -variables, which may breake any already existing quoting (for example, if the -environment variable contains a special character like a \fB"\fR). +variables, which may have side effects (vulnerabilities) or break any already +existing quoting (for example, if the environment variable contains a special +character like a \fB"\fR). Examples are: .CS % exec my-echo.cmd {test&whoami} @@ -248,21 +253,24 @@ Examples are: % exec my-echo.cmd "ENV X:%X%" ENV X: CONTENT OF X .CE -This might be seen as a vulnerability. In consequence, the following formatting -is automatically performed on any argument item: +In consequence, the following formatting is automatically performed on any +argument item: .IP \(bu 3 Avoid subprogram execution: -Any non-paired special -characters (\fB&\fR, \fB|\fR, \fB^\fR, \fB<\fR, \fB>\fR, \fB!\fR, \fB(\fR, -\fB)\fR, \fB(\fR, \fB%\fR) are automatically enclosed in quotes (\fB"\fR). +Any special character argument containing a special character (\fB&\fR, \fB|\fR, +\fB^\fR, \fB<\fR, \fB>\fR, \fB!\fR, \fB(\fR, \fB)\fR, \fB(\fR, \fB%\fR) +is automatically enclosed in quotes (\fB"\fR). Any data quote is escaped by +appropriate sequences like a double-quote. .IP \(bu 3 Avoid environment variable replacement: Any appearence of environment variable reference (\fB%\fR) is individually quoted by \fB"\fR. .PP -This quoting was introduced in TCL 8.6.10 breaking present scripts which rely on -the replacement functionality to avoid. A solution with command parameters is -envisaged for TCL 8.6.14. +TCL 8.6.10 refined this quoting by adding quoting for data quotes and individual +quoting of "\fB%\fR". +This may break present scripts which rely on the replacement functionality of +environment variables. +A solution with command parameters is envisaged for a future release of TCL. .RE .PP The Tk console text widget does not provide real standard IO capabilities. -- cgit v0.12 From cea34b6d9878e7861e983182282b2905b4a2175f Mon Sep 17 00:00:00 2001 From: oehhar Date: Mon, 6 Nov 2023 16:45:18 +0000 Subject: Remove the quoting example by ". It is more complicated than that, so be quiet. --- doc/exec.n | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/exec.n b/doc/exec.n index 4024ffe..f4a1702 100644 --- a/doc/exec.n +++ b/doc/exec.n @@ -260,7 +260,7 @@ Avoid subprogram execution: Any special character argument containing a special character (\fB&\fR, \fB|\fR, \fB^\fR, \fB<\fR, \fB>\fR, \fB!\fR, \fB(\fR, \fB)\fR, \fB(\fR, \fB%\fR) is automatically enclosed in quotes (\fB"\fR). Any data quote is escaped by -appropriate sequences like a double-quote. +appropriate sequences. .IP \(bu 3 Avoid environment variable replacement: Any appearence of environment variable reference (\fB%\fR) is individually quoted -- cgit v0.12 From 4626fe265c1403e3568ae8c3d77bb87a88cc4b25 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 9 Nov 2023 21:54:57 +0000 Subject: (partial) fix [54a305cb88]: warning: variable set but not used [-Wunused-but-set-variable] --- generic/tclFileName.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/generic/tclFileName.c b/generic/tclFileName.c index b3294fd..d6dac9c 100644 --- a/generic/tclFileName.c +++ b/generic/tclFileName.c @@ -2138,7 +2138,7 @@ DoGlob( Tcl_GlobTypeData *types) /* List object containing list of acceptable * types. May be NULL. */ { - int baseLength, quoted, count; + int baseLength, quoted; int result = TCL_OK; char *name, *p, *openBrace, *closeBrace, *firstSpecialChar; Tcl_Obj *joinedPtr; @@ -2148,7 +2148,6 @@ DoGlob( * past the last initial separator. */ - count = 0; name = pattern; for (; *pattern != '\0'; pattern++) { if (*pattern == '\\') { @@ -2168,7 +2167,6 @@ DoGlob( } else if (strchr(separators, *pattern) == NULL) { break; } - count++; } /* -- cgit v0.12 From a4ac20392acd864a5b3d95221edf1bafc6737b23 Mon Sep 17 00:00:00 2001 From: oehhar Date: Fri, 10 Nov 2023 10:54:39 +0000 Subject: Exec wordsmithing. Thanks, Sergey! --- doc/exec.n | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/exec.n b/doc/exec.n index f4a1702..a0008ad 100644 --- a/doc/exec.n +++ b/doc/exec.n @@ -236,15 +236,15 @@ But it works properly with an executable (using CommandLineToArgv, etc). .PP \fBArgument quoting\fR .RS -Each argument of the \fBexec\fR command is mapped to an argument of the called -program by an adaptive quoting by adding quote characters (\fB"\fR) around the -arguments. -.PP -If invoking batch files or other specific programs, the Windows environment -does execute programs mentioned in the arguments or replace environment -variables, which may have side effects (vulnerabilities) or break any already -existing quoting (for example, if the environment variable contains a special -character like a \fB"\fR). +The arguments of the \fBexec\fR command are mapped to the arguments of the called +program. Additional quote characters (\fB"\fR) are automatically added around +arguments if expected. Special characters are escaped by inserting backslash +characters. +.PP +The MS-Windows environment does execute programs mentioned in the arguments and +called batch files (conspec) replace environment variables, which may have side +effects (vulnerabilities) or break any already existing quoting (for example, +if the environment variable contains a special character like a \fB"\fR). Examples are: .CS % exec my-echo.cmd {test&whoami} @@ -253,14 +253,14 @@ Examples are: % exec my-echo.cmd "ENV X:%X%" ENV X: CONTENT OF X .CE -In consequence, the following formatting is automatically performed on any +The following formatting is automatically performed on any argument item: .IP \(bu 3 Avoid subprogram execution: Any special character argument containing a special character (\fB&\fR, \fB|\fR, \fB^\fR, \fB<\fR, \fB>\fR, \fB!\fR, \fB(\fR, \fB)\fR, \fB(\fR, \fB%\fR) is automatically enclosed in quotes (\fB"\fR). Any data quote is escaped by -appropriate sequences. +insertion of backslash characters. .IP \(bu 3 Avoid environment variable replacement: Any appearence of environment variable reference (\fB%\fR) is individually quoted -- cgit v0.12 From aaf72b94fa284aeb2580f8c5c4cac49e5166cb82 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 10 Nov 2023 13:55:54 +0000 Subject: Fix typo's in tclGetDate.y --- generic/tclGetDate.y | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/generic/tclGetDate.y b/generic/tclGetDate.y index 412f03f..ac9bf1c 100644 --- a/generic/tclGetDate.y +++ b/generic/tclGetDate.y @@ -641,7 +641,7 @@ static const TABLE TimezoneTable[] = { { "ist", tZONE, -HOUR(11/2) }, /* Indian Standard */ { "zp6", tZONE, -HOUR( 6) }, /* USSR Zone 5 */ #if 0 - /* For completeness. NST is also Newfoundland Stanard, nad SST is + /* For completeness. NST is also Newfoundland Standard, and SST is * also Swedish Summer. */ { "nst", tZONE, -HOUR(13/2) }, /* North Sumatra */ { "sst", tZONE, -HOUR( 7) }, /* South Sumatra, USSR Zone 6 */ @@ -1099,7 +1099,7 @@ TclClockOldscanObjCmd( } Tcl_ListObjAppendElement(interp, result, resultElement); - TcNewObj(resultElement); + TclNewObj(resultElement); if (yyHaveDay && !yyHaveDate) { Tcl_ListObjAppendElement(interp, resultElement, Tcl_NewIntObj((int) yyDayOrdinal)); -- cgit v0.12 From 67b84b71c66b45cb139546c2a7e3aec964a5d4c6 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 10 Nov 2023 14:22:06 +0000 Subject: Fix [54a305cb88] (second part) by hand-editing tclDate.c. --- generic/tclDate.c | 6 ------ unix/Makefile.in | 2 ++ 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/generic/tclDate.c b/generic/tclDate.c index ebe499d..fa27475 100644 --- a/generic/tclDate.c +++ b/generic/tclDate.c @@ -64,7 +64,6 @@ #define yylex TclDatelex #define yyerror TclDateerror #define yydebug TclDatedebug -#define yynerrs TclDatenerrs /* Copy the first part of user declarations. */ @@ -1295,9 +1294,6 @@ static YYLTYPE yyloc_default ; YYLTYPE yylloc = yyloc_default; - /* Number of syntax errors so far. */ - int yynerrs; - int yystate; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; @@ -1361,7 +1357,6 @@ YYLTYPE yylloc = yyloc_default; yystate = 0; yyerrstatus = 0; - yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ yylsp[0] = yylloc; goto yysetstate; @@ -2099,7 +2094,6 @@ yyerrlab: /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { - ++yynerrs; #if ! YYERROR_VERBOSE yyerror (&yylloc, info, YY_("syntax error")); #else diff --git a/unix/Makefile.in b/unix/Makefile.in index 39965cf..9267ef7 100644 --- a/unix/Makefile.in +++ b/unix/Makefile.in @@ -1919,6 +1919,8 @@ dist-packages: configure-packages # the name of the .y file so that make doesn't try to automatically regenerate # the .c file. +# +# Remark: see [54a305cb88]. tclDate.c is manually edited, removing the unused "yynerrs" variable gendate: bison --output-file=$(GENERIC_DIR)/tclDate.c \ --no-lines \ -- cgit v0.12 From b286637e28ec3f7a0cb2808088840ac7c2a0e613 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 17 Nov 2023 15:35:13 +0000 Subject: Cherry-pick [90e09ca320]: silence compiler warning --- generic/tclInterp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tclInterp.c b/generic/tclInterp.c index 42d8ec3..f33aeed 100644 --- a/generic/tclInterp.c +++ b/generic/tclInterp.c @@ -3504,7 +3504,7 @@ static void WrapFree( void *ptr) { - Tcl_Free(ptr); + ckfree(ptr); } void -- cgit v0.12 From df18d9393c3f1336334fa37742e09461296575e7 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 17 Nov 2023 22:43:58 +0000 Subject: [f8c52a8c53]: CI: Add 32-bit Linux job --- .github/workflows/linux-build.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml index 65ca764..f881b47 100644 --- a/.github/workflows/linux-build.yml +++ b/.github/workflows/linux-build.yml @@ -23,6 +23,8 @@ jobs: - "CFLAGS=-ftrapv" - "CFLAGS=-DTCL_UTF_MAX=4" - "CFLAGS=-DTCL_UTF_MAX=6" + # Duplicated below + - "CFLAGS=-m32 CPPFLAGS=-m32 LDFLAGS=-m32 --disable-64bit" defaults: run: shell: bash @@ -30,6 +32,11 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + - name: Install 32-bit dependencies if needed + # Duplicated from above + if: ${{ matrix.cfgopt == 'CFLAGS=-m32 CPPFLAGS=-m32 LDFLAGS=-m32 --disable-64bit' }} + run: | + sudo apt install gcc-multilib libc6-dev-i386 - name: Prepare run: | touch tclStubInit.c tclOOStubInit.c -- cgit v0.12 From 092703d99668fb06f01c3515abfb0fa27f9e42df Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 20 Nov 2023 20:45:14 +0000 Subject: Fix [32b88975f7]: clock format returns spurious errors --- generic/tclClock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index 38c4ec0..7d54edd 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -913,7 +913,7 @@ ConvertLocalToUTCUsingC( Tcl_MutexLock(&clockMutex); errno = 0; fields->seconds = (Tcl_WideInt) mktime(&timeVal); - localErrno = errno; + localErrno = (fields->seconds == -1) ? errno : 0; Tcl_MutexUnlock(&clockMutex); /* -- cgit v0.12 From e92f56554cd9888d3a41bdecfd11773828688d4b Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 20 Nov 2023 21:09:58 +0000 Subject: Missing "static" keywords in various places. --- generic/tclTestObj.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/generic/tclTestObj.c b/generic/tclTestObj.c index 3003487..914c6f0 100644 --- a/generic/tclTestObj.c +++ b/generic/tclTestObj.c @@ -151,7 +151,7 @@ TestbignumobjCmd( int objc, /* Argument count */ Tcl_Obj *const objv[]) /* Argument vector */ { - const char *const subcmds[] = { + static const char *const subcmds[] = { "set", "get", "mult10", "div10", "iseven", "radixsize", NULL }; enum options { @@ -876,7 +876,7 @@ TestlistobjCmd( Tcl_Obj *const objv[]) /* Argument objects */ { /* Subcommands supported by this command */ - const char* subcommands[] = { + static const char *const subcommands[] = { "set", "get", "replace" -- cgit v0.12 From 752a2a1cf22d2b378c0911cc36942bab516d5cd4 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Thu, 23 Nov 2023 15:07:09 +0000 Subject: Fix [e653408972]: autoconf warning --- unix/configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unix/configure.in b/unix/configure.in index 3e80626..39eba16 100644 --- a/unix/configure.in +++ b/unix/configure.in @@ -199,7 +199,7 @@ SC_TCL_64BIT_FLAGS # Tcl_UniChar strings to memcmp on big-endian systems. #-------------------------------------------------------------------- -AC_C_BIGENDIAN +AC_C_BIGENDIAN(,,,[#]) #-------------------------------------------------------------------- # Supply substitutes for missing POSIX library procedures, or -- cgit v0.12 From a130f70eb1c958b938a9d63a055fc64141903155 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Mon, 27 Nov 2023 12:01:09 +0000 Subject: (cherry-pick) Corrected synopsis of namespace manual page where the subcommand was wrongly declared optional --- doc/namespace.n | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/namespace.n b/doc/namespace.n index f7775b4..120c0a3 100644 --- a/doc/namespace.n +++ b/doc/namespace.n @@ -14,7 +14,7 @@ .SH NAME namespace \- create and manipulate contexts for commands and variables .SH SYNOPSIS -\fBnamespace \fR?\fIsubcommand\fR? ?\fIarg ...\fR? +\fBnamespace \fR\fIsubcommand\fR ?\fIarg ...\fR? .BE .SH DESCRIPTION .PP -- cgit v0.12