summaryrefslogtreecommitdiffstats
path: root/generic/tclEncoding.c
diff options
context:
space:
mode:
authorapnadkarni <apnmbx-wits@yahoo.com>2023-02-25 16:29:09 (GMT)
committerapnadkarni <apnmbx-wits@yahoo.com>2023-02-25 16:29:09 (GMT)
commit2a5b403768444ddf2d6379ffe3644e9d5b230e19 (patch)
treefca9b2cba8f952b8189181e1b9faf571739be695 /generic/tclEncoding.c
parent8390c51fcaeaa278ec7ec40ec5d31ee187c25208 (diff)
downloadtcl-2a5b403768444ddf2d6379ffe3644e9d5b230e19.zip
tcl-2a5b403768444ddf2d6379ffe3644e9d5b230e19.tar.gz
tcl-2a5b403768444ddf2d6379ffe3644e9d5b230e19.tar.bz2
Experimental fix for [fb368527ae] - length truncation
Diffstat (limited to 'generic/tclEncoding.c')
-rw-r--r--generic/tclEncoding.c86
1 files changed, 67 insertions, 19 deletions
diff --git a/generic/tclEncoding.c b/generic/tclEncoding.c
index ce5626f..3a39966 100644
--- a/generic/tclEncoding.c
+++ b/generic/tclEncoding.c
@@ -1160,8 +1160,8 @@ Tcl_ExternalToUtfDStringEx(
char *dst;
Tcl_EncodingState state;
const Encoding *encodingPtr;
- int result, soFar, srcRead, dstWrote, dstChars;
- Tcl_Size dstLen;
+ int result;
+ Tcl_Size dstLen, soFar;
const char *srcStart = src;
Tcl_DStringInit(dstPtr);
@@ -1179,23 +1179,47 @@ Tcl_ExternalToUtfDStringEx(
srcLen = encodingPtr->lengthProc(src);
}
- flags |= TCL_ENCODING_START | TCL_ENCODING_END;
+ flags |= TCL_ENCODING_START;
if (encodingPtr->toUtfProc == UtfToUtfProc) {
flags |= ENCODING_INPUT;
}
while (1) {
- result = encodingPtr->toUtfProc(encodingPtr->clientData, src, srcLen,
- flags, &state, dst, dstLen, &srcRead, &dstWrote, &dstChars);
- soFar = dst + dstWrote - Tcl_DStringValue(dstPtr);
+ int srcChunkLen, srcChunkRead;
+ int dstChunkLen, dstChunkWrote, dstChunkChars;
+
+ if (srcLen > INT_MAX) {
+ srcChunkLen = INT_MAX;
+ } else {
+ srcChunkLen = srcLen;
+ flags |= TCL_ENCODING_END; /* Last chunk */
+ }
+ dstChunkLen = dstLen > INT_MAX ? INT_MAX : dstLen;
+
+ result = encodingPtr->toUtfProc(encodingPtr->clientData, src,
+ srcChunkLen, flags, &state, dst, dstChunkLen,
+ &srcChunkRead, &dstChunkWrote, &dstChunkChars);
+ soFar = dst + dstChunkWrote - Tcl_DStringValue(dstPtr);
- src += srcRead;
- if (result != TCL_CONVERT_NOSPACE) {
+ src += srcChunkRead;
+ srcLen -= srcChunkRead;
+
+ /*
+ * Keep looping in two case -
+ * - our destination buffer did not have enough room
+ * - we had not passed in all the data and error indicated fragment
+ * of a multibyte character
+ * In both cases we have to grow buffer, move the input source pointer
+ * and loop. Otherwise, return the result we got.
+ */
+ if ((result != TCL_CONVERT_NOSPACE) &&
+ !(result == TCL_CONVERT_MULTIBYTE && (flags & TCL_ENCODING_END))) {
Tcl_DStringSetLength(dstPtr, soFar);
return (result == TCL_OK) ? TCL_INDEX_NONE : (Tcl_Size)(src - srcStart);
}
+
flags &= ~TCL_ENCODING_START;
- srcLen -= srcRead;
+
if (Tcl_DStringLength(dstPtr) == 0) {
Tcl_DStringSetLength(dstPtr, dstLen);
}
@@ -1398,9 +1422,9 @@ Tcl_UtfToExternalDStringEx(
char *dst;
Tcl_EncodingState state;
const Encoding *encodingPtr;
- int result, soFar, srcRead, dstWrote, dstChars;
+ int result;
+ Tcl_Size dstLen, soFar;
const char *srcStart = src;
- Tcl_Size dstLen;
Tcl_DStringInit(dstPtr);
dst = Tcl_DStringValue(dstPtr);
@@ -1416,16 +1440,40 @@ Tcl_UtfToExternalDStringEx(
} else if (srcLen == TCL_INDEX_NONE) {
srcLen = strlen(src);
}
- flags |= TCL_ENCODING_START | TCL_ENCODING_END;
+ flags |= TCL_ENCODING_START;
while (1) {
+ int srcChunkLen, srcChunkRead;
+ int dstChunkLen, dstChunkWrote, dstChunkChars;
+
+ if (srcLen > INT_MAX) {
+ srcChunkLen = INT_MAX;
+ } else {
+ srcChunkLen = srcLen;
+ flags |= TCL_ENCODING_END; /* Last chunk */
+ }
+ dstChunkLen = dstLen > INT_MAX ? INT_MAX : dstLen;
+
result = encodingPtr->fromUtfProc(encodingPtr->clientData, src,
- srcLen, flags, &state, dst, dstLen,
- &srcRead, &dstWrote, &dstChars);
- soFar = dst + dstWrote - Tcl_DStringValue(dstPtr);
+ srcChunkLen, flags, &state, dst, dstChunkLen,
+ &srcChunkRead, &dstChunkWrote, &dstChunkChars);
+ soFar = dst + dstChunkWrote - Tcl_DStringValue(dstPtr);
- src += srcRead;
- if (result != TCL_CONVERT_NOSPACE) {
- int i = soFar + encodingPtr->nullSize - 1;
+ /* Move past the part processed in this go around */
+ src += srcChunkRead;
+ srcLen -= srcChunkRead;
+
+ /*
+ * Keep looping in two case -
+ * - our destination buffer did not have enough room
+ * - we had not passed in all the data and error indicated fragment
+ * of a multibyte character
+ * In both cases we have to grow buffer, move the input source pointer
+ * and loop. Otherwise, return the result we got.
+ */
+ if ((result != TCL_CONVERT_NOSPACE) &&
+ !(result == TCL_CONVERT_MULTIBYTE && (flags & TCL_ENCODING_END))) {
+ size_t i = soFar + encodingPtr->nullSize - 1;
+ /* Loop as DStringSetLength only stores one nul byte at a time */
while (i >= soFar) {
Tcl_DStringSetLength(dstPtr, i--);
}
@@ -1433,7 +1481,7 @@ Tcl_UtfToExternalDStringEx(
}
flags &= ~TCL_ENCODING_START;
- srcLen -= srcRead;
+
if (Tcl_DStringLength(dstPtr) == 0) {
Tcl_DStringSetLength(dstPtr, dstLen);
}