summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjan.nijtmans <nijtmans@users.sourceforge.net>2018-10-06 17:12:46 (GMT)
committerjan.nijtmans <nijtmans@users.sourceforge.net>2018-10-06 17:12:46 (GMT)
commitac711bcf45a5b5bd09e3102e5ea08f726237212f (patch)
treeaa1f8b68dd50c5e303d53ca13d43ef7639b4ea95
parentb5f75d3392ae32955aaef38e3d3af58119179a73 (diff)
downloadtcl-ac711bcf45a5b5bd09e3102e5ea08f726237212f.zip
tcl-ac711bcf45a5b5bd09e3102e5ea08f726237212f.tar.gz
tcl-ac711bcf45a5b5bd09e3102e5ea08f726237212f.tar.bz2
protect Tcl_WinUtfToTChar/Tcl_WinTCharToUtf against NULL input values: return empty string in that case.
Add TIP #494-compatible definitions of TCL_IO_FAILURE/TCL_AUTO_LENGTH, and use it in some appropriate places.
-rw-r--r--generic/tcl.h9
-rw-r--r--generic/tclIOCmd.c2
-rw-r--r--generic/tclIOUtil.c8
-rw-r--r--generic/tclZipfs.c6
-rw-r--r--generic/tclZlib.c6
-rw-r--r--win/tclWin32Dll.c8
6 files changed, 26 insertions, 13 deletions
diff --git a/generic/tcl.h b/generic/tcl.h
index 2ced16b..0971066 100644
--- a/generic/tcl.h
+++ b/generic/tcl.h
@@ -224,7 +224,7 @@ extern "C" {
* to be included in a shared library, then it should have the DLLEXPORT
* storage class. If is being declared for use by a module that is going to
* link against the shared library, then it should have the DLLIMPORT storage
- * class. If the symbol is beind declared for a static build or for use from a
+ * class. If the symbol is being declared for a static build or for use from a
* stub library, then the storage class should be empty.
*
* The convention is that a macro called BUILD_xxxx, where xxxx is the name of
@@ -2334,6 +2334,13 @@ typedef int (Tcl_ArgvGenFuncProc)(ClientData clientData, Tcl_Interp *interp,
#define TCL_TCPSERVER_REUSEPORT (1<<1)
/*
+ * Constants for special int-typed values, see TIP #494
+ */
+
+#define TCL_IO_FAILURE (-1)
+#define TCL_AUTO_LENGTH (-1)
+
+/*
*----------------------------------------------------------------------------
* Single public declaration for NRE.
*/
diff --git a/generic/tclIOCmd.c b/generic/tclIOCmd.c
index d38240a..1dd8666 100644
--- a/generic/tclIOCmd.c
+++ b/generic/tclIOCmd.c
@@ -991,7 +991,7 @@ Tcl_ExecObjCmd(
resultPtr = Tcl_NewObj();
if (Tcl_GetChannelHandle(chan, TCL_READABLE, NULL) == TCL_OK) {
- if (Tcl_ReadChars(chan, resultPtr, -1, 0) < 0) {
+ if (Tcl_ReadChars(chan, resultPtr, -1, 0) == TCL_IO_FAILURE) {
/*
* TIP #219.
* Capture error messages put by the driver into the bypass area
diff --git a/generic/tclIOUtil.c b/generic/tclIOUtil.c
index 11cc22d..63d16be 100644
--- a/generic/tclIOUtil.c
+++ b/generic/tclIOUtil.c
@@ -1807,7 +1807,7 @@ Tcl_FSEvalFileEx(
* be handled especially.
*/
- if (Tcl_ReadChars(chan, objPtr, 1, 0) < 0) {
+ if (Tcl_ReadChars(chan, objPtr, 1, 0) == TCL_IO_FAILURE) {
Tcl_Close(interp, chan);
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"couldn't read file \"%s\": %s",
@@ -1822,7 +1822,7 @@ Tcl_FSEvalFileEx(
*/
if (Tcl_ReadChars(chan, objPtr, -1,
- memcmp(string, "\xef\xbb\xbf", 3)) < 0) {
+ memcmp(string, "\xef\xbb\xbf", 3)) == TCL_IO_FAILURE) {
Tcl_Close(interp, chan);
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"couldn't read file \"%s\": %s",
@@ -1942,7 +1942,7 @@ TclNREvalFile(
* be handled especially.
*/
- if (Tcl_ReadChars(chan, objPtr, 1, 0) < 0) {
+ if (Tcl_ReadChars(chan, objPtr, 1, 0) == TCL_IO_FAILURE) {
Tcl_Close(interp, chan);
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"couldn't read file \"%s\": %s",
@@ -1958,7 +1958,7 @@ TclNREvalFile(
*/
if (Tcl_ReadChars(chan, objPtr, -1,
- memcmp(string, "\xef\xbb\xbf", 3)) < 0) {
+ memcmp(string, "\xef\xbb\xbf", 3)) == TCL_IO_FAILURE) {
Tcl_Close(interp, chan);
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"couldn't read file \"%s\": %s",
diff --git a/generic/tclZipfs.c b/generic/tclZipfs.c
index b609779..5342fb1 100644
--- a/generic/tclZipfs.c
+++ b/generic/tclZipfs.c
@@ -4726,9 +4726,6 @@ TclZipfs_AppHook(
#endif /* _WIN32 */
***argvPtr) /* Pointer to argv */
{
-#ifdef _WIN32
- Tcl_DString ds;
-#endif /* _WIN32 */
char *archive;
Tcl_FindExecutable((*argvPtr)[0]);
@@ -4773,6 +4770,9 @@ TclZipfs_AppHook(
}
#ifdef SUPPORT_BUILTIN_ZIP_INSTALL
} else if (*argcPtr > 1) {
+#ifdef _WIN32
+ Tcl_DString ds;
+#endif /* _WIN32 */
/*
* If the first argument is "install", run the supplied installer
* script.
diff --git a/generic/tclZlib.c b/generic/tclZlib.c
index 644ac8b..9bad36d 100644
--- a/generic/tclZlib.c
+++ b/generic/tclZlib.c
@@ -2931,7 +2931,7 @@ ZlibTransformClose(
result = TCL_ERROR;
break;
}
- if (written && Tcl_WriteRaw(cd->parent, cd->outBuffer, written) < 0) {
+ if (written && Tcl_WriteRaw(cd->parent, cd->outBuffer, written) == TCL_IO_FAILURE) {
/* TODO: is this the right way to do errors on close?
* Note: when close is called from FinalizeIOSubsystem then
* interp may be NULL */
@@ -3130,7 +3130,7 @@ ZlibTransformOutput(
break;
}
- if (Tcl_WriteRaw(cd->parent, cd->outBuffer, produced) < 0) {
+ if (Tcl_WriteRaw(cd->parent, cd->outBuffer, produced) == TCL_IO_FAILURE) {
*errorCodePtr = Tcl_GetErrno();
return -1;
}
@@ -3186,7 +3186,7 @@ ZlibTransformFlush(
* Write the bytes we've received to the next layer.
*/
- if (len > 0 && Tcl_WriteRaw(cd->parent, cd->outBuffer, len) < 0) {
+ if (len > 0 && Tcl_WriteRaw(cd->parent, cd->outBuffer, len) == TCL_IO_FAILURE) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"problem flushing channel: %s",
Tcl_PosixError(interp)));
diff --git a/win/tclWin32Dll.c b/win/tclWin32Dll.c
index 1a33514..04d27dd 100644
--- a/win/tclWin32Dll.c
+++ b/win/tclWin32Dll.c
@@ -472,6 +472,9 @@ Tcl_WinUtfToTChar(
* converted string is stored. */
{
Tcl_DStringInit(dsPtr);
+ if (!string) {
+ return (TCHAR *)Tcl_DStringValue(dsPtr);
+ }
return Tcl_UtfToUniCharDString(string, len, dsPtr);
}
@@ -483,12 +486,15 @@ Tcl_WinTCharToUtf(
Tcl_DString *dsPtr) /* Uninitialized or free DString in which the
* converted string is stored. */
{
+ Tcl_DStringInit(dsPtr);
+ if (!string) {
+ return Tcl_DStringValue(dsPtr);
+ }
if (len > 0) {
len /= 2;
} else if (len < 0) {
len = wcslen(string);
}
- Tcl_DStringInit(dsPtr);
return Tcl_UniCharToUtfDString(string, len, dsPtr);
}