From d9534890046440144f5b06de2e748c8993b461bc Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Fri, 13 Oct 2023 13:27:40 +0000 Subject: [PATCH] Proposed fix for [abd489a1c]: TclStringCmp() calls functions through pointer to incorrect type. Modified, swapping the wrapping-order --- generic/tclCmdMZ.c | 15 ++++++------ generic/tclIndexObj.c | 4 +-- generic/tclInt.h | 15 +++++++----- generic/tclOOCall.c | 2 +- generic/tclUtf.c | 57 +++++++++++++++++++++++++++++++++++++++++++ unix/tclUnixChan.c | 14 +++++------ 6 files changed, 83 insertions(+), 24 deletions(-) diff --git a/generic/tclCmdMZ.c b/generic/tclCmdMZ.c index d769da821ea..9636528ef2d 100644 --- a/generic/tclCmdMZ.c +++ b/generic/tclCmdMZ.c @@ -1240,7 +1240,7 @@ StringFirstCmd( */ if ((*p == *needleStr) && (TclUniCharNcmp(needleStr, p, - (unsigned long) needleLen) == 0)) { + needleLen) == 0)) { match = p - haystackStr; break; } @@ -1953,7 +1953,7 @@ StringMapCmd( } end = ustring1 + length1; - strCmpFn = (nocase ? Tcl_UniCharNcasecmp : Tcl_UniCharNcmp); + strCmpFn = nocase ? Tcl_UniCharNcasecmp : Tcl_UniCharNcmp; /* * Force result to be Unicode @@ -2740,7 +2740,7 @@ TclStringCmp( if (nocase) { s1 = (char *) Tcl_GetUnicodeFromObj(value1Ptr, &s1len); s2 = (char *) Tcl_GetUnicodeFromObj(value2Ptr, &s2len); - memCmpFn = (memCmpFn_t)Tcl_UniCharNcasecmp; + memCmpFn = TclUniCharNcasecmp; } else { s1len = Tcl_GetCharLength(value1Ptr); s2len = Tcl_GetCharLength(value2Ptr); @@ -2771,7 +2771,7 @@ TclStringCmp( reqlength *= sizeof(Tcl_UniChar); } } else { - memCmpFn = (memCmpFn_t) Tcl_UniCharNcmp; + memCmpFn = TclUniCharNcmp; } } } @@ -2822,17 +2822,16 @@ TclStringCmp( /* * As a catch-all we will work with UTF-8. We cannot use memcmp() * as that is unsafe with any string containing NUL (\xC0\x80 in - * Tcl's utf rep). We can use the more efficient TclpUtfNcmp2 if + * Tcl's utf rep). We can use the more efficient TclUtfNcmp if * we are case-sensitive and no specific length was requested. */ if ((reqlength < 0) && !nocase) { - memCmpFn = (memCmpFn_t) TclpUtfNcmp2; + memCmpFn = TclUtfNcmp2; } else { s1len = Tcl_NumUtfChars(s1, s1len); s2len = Tcl_NumUtfChars(s2, s2len); - memCmpFn = (memCmpFn_t) - (nocase ? Tcl_UtfNcasecmp : Tcl_UtfNcmp); + memCmpFn = nocase ? TclUtfNcasecmp : TclUtfNcmp; } } } diff --git a/generic/tclIndexObj.c b/generic/tclIndexObj.c index 89b19fd04f7..c024b60c771 100644 --- a/generic/tclIndexObj.c +++ b/generic/tclIndexObj.c @@ -692,7 +692,7 @@ PrefixAllObjCmd( */ if (length <= elemLength) { - if (TclpUtfNcmp2(elemString, string, length) == 0) { + if (TclUtfNcmp2(elemString, string, length) == 0) { Tcl_ListObjAppendElement(interp, resultPtr, tableObjv[t]); } } @@ -752,7 +752,7 @@ PrefixLongestObjCmd( */ if ((length > elemLength) || - TclpUtfNcmp2(elemString, string, length) != 0) { + TclUtfNcmp2(elemString, string, length) != 0) { continue; } diff --git a/generic/tclInt.h b/generic/tclInt.h index 103827fe8f3..18edac48d1a 100644 --- a/generic/tclInt.h +++ b/generic/tclInt.h @@ -3143,9 +3143,14 @@ MODULE_SCOPE void * TclStackRealloc(Tcl_Interp *interp, void *ptr, int numBytes); typedef int (*memCmpFn_t)(const void*, const void*, size_t); -MODULE_SCOPE int TclStringCmp (Tcl_Obj *value1Ptr, Tcl_Obj *value2Ptr, +MODULE_SCOPE int TclStringCmp(Tcl_Obj *value1Ptr, Tcl_Obj *value2Ptr, int checkEq, int nocase, int reqlength); -MODULE_SCOPE int TclStringCmpOpts (Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], +MODULE_SCOPE int TclUniCharNcasecmp(const void*, const void*, size_t); +MODULE_SCOPE int TclUtfNcasecmp(const void*, const void*, size_t); +MODULE_SCOPE int TclUtfNcmp(const void*, const void*, size_t); +MODULE_SCOPE int TclUniCharNcmp(const void*, const void*, size_t); +MODULE_SCOPE int TclUtfNcmp2(const void*, const void*, size_t); +MODULE_SCOPE int TclStringCmpOpts(Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], int *nocase, int *reqlength); MODULE_SCOPE int TclStringMatch(const char *str, int strLen, const char *pattern, int ptnLen, int flags); @@ -4052,15 +4057,13 @@ MODULE_SCOPE void TclDbInitNewObj(Tcl_Obj *objPtr, const char *file, * lexically correct on little-endian systems. The ANSI C "prototype" for * this macro is: * - * MODULE_SCOPE int TclUniCharNcmp(const Tcl_UniChar *cs, - * const Tcl_UniChar *ct, unsigned long n); + * MODULE_SCOPE int TclUniCharNcmp(const void *cs, + * const void *ct, size_t n); *---------------------------------------------------------------- */ #if defined(WORDS_BIGENDIAN) && (TCL_UTF_MAX != 4) # define TclUniCharNcmp(cs,ct,n) memcmp((cs),(ct),(n)*sizeof(Tcl_UniChar)) -#else /* !WORDS_BIGENDIAN */ -# define TclUniCharNcmp Tcl_UniCharNcmp #endif /* WORDS_BIGENDIAN */ /* diff --git a/generic/tclOOCall.c b/generic/tclOOCall.c index 7ebde5ebe83..aefd9214e47 100644 --- a/generic/tclOOCall.c +++ b/generic/tclOOCall.c @@ -585,7 +585,7 @@ CmpStr( const char **strPtr1 = (const char **) ptr1; const char **strPtr2 = (const char **) ptr2; - return TclpUtfNcmp2(*strPtr1, *strPtr2, strlen(*strPtr1) + 1); + return TclUtfNcmp2(*strPtr1, *strPtr2, strlen(*strPtr1) + 1); } /* diff --git a/generic/tclUtf.c b/generic/tclUtf.c index 9f32fcf4237..196c5fb8ce0 100644 --- a/generic/tclUtf.c +++ b/generic/tclUtf.c @@ -1231,6 +1231,17 @@ TclpUtfNcmp2( const char *ct, /* UTF string cs is compared to. */ unsigned long numBytes) /* Number of *bytes* to compare. */ { + return TclUtfNcmp2(cs, ct, numBytes); +} + +int +TclUtfNcmp2( + const void *csPtr, /* UTF string to compare to ct. */ + const void *ctPtr, /* UTF string cs is compared to. */ + size_t numBytes) /* Number of *bytes* to compare. */ +{ + const char *cs = (const char *)csPtr; + const char *ct = (const char *)ctPtr; /* * We can't simply call 'memcmp(cs, ct, numBytes);' because we need to * check for Tcl's \xC0\x80 non-utf-8 null encoding. Otherwise utf-8 lexes @@ -1278,6 +1289,17 @@ Tcl_UtfNcmp( const char *ct, /* UTF string cs is compared to. */ unsigned long numChars) /* Number of UTF chars to compare. */ { + return TclUtfNcmp(cs, ct, numChars); +} + +int +TclUtfNcmp( + const void *csPtr, /* UTF string to compare to ct. */ + const void *ctPtr, /* UTF string cs is compared to. */ + size_t numChars) /* Number of UTF chars to compare. */ +{ + const char *cs = (const char *)csPtr; + const char *ct = (const char *)ctPtr; Tcl_UniChar ch1 = 0, ch2 = 0; /* @@ -1336,6 +1358,17 @@ Tcl_UtfNcasecmp( const char *ct, /* UTF string cs is compared to. */ unsigned long numChars) /* Number of UTF chars to compare. */ { + return TclUtfNcasecmp(cs, ct, numChars); +} + +int +TclUtfNcasecmp( + const void *csPtr, /* UTF string to compare to ct. */ + const void *ctPtr, /* UTF string cs is compared to. */ + size_t numChars) /* Number of UTF chars to compare. */ +{ + const char *cs = (const char *)csPtr; + const char *ct = (const char *)ctPtr; Tcl_UniChar ch1 = 0, ch2 = 0; while (numChars-- > 0) { @@ -1588,12 +1621,24 @@ Tcl_UniCharLen( *---------------------------------------------------------------------- */ +#undef TclUniCharNcmp int Tcl_UniCharNcmp( const Tcl_UniChar *ucs, /* Unicode string to compare to uct. */ const Tcl_UniChar *uct, /* Unicode string ucs is compared to. */ unsigned long numChars) /* Number of unichars to compare. */ { + return TclUniCharNcmp(ucs, uct, numChars); +} + +int +TclUniCharNcmp( + const void *ucsPtr, /* Unicode string to compare to uct. */ + const void *uctPtr, /* Unicode string ucs is compared to. */ + size_t numChars) /* Number of unichars to compare. */ +{ + const Tcl_UniChar *ucs = (const Tcl_UniChar *)ucsPtr; + const Tcl_UniChar *uct = (const Tcl_UniChar *)uctPtr; #if defined(WORDS_BIGENDIAN) && (TCL_UTF_MAX != 4) /* * We are definitely on a big-endian machine; memcmp() is safe @@ -1647,6 +1692,18 @@ Tcl_UniCharNcasecmp( const Tcl_UniChar *uct, /* Unicode string ucs is compared to. */ unsigned long numChars) /* Number of Unichars to compare. */ { + return TclUniCharNcasecmp(ucs, uct, numChars); +} + +int +TclUniCharNcasecmp( + const void *ucsPtr, /* Unicode string to compare to uct. */ + const void *uctPtr, /* Unicode string ucs is compared to. */ + size_t numChars) /* Number of Unichars to compare. */ +{ + const Tcl_UniChar *ucs = (const Tcl_UniChar *)ucsPtr; + const Tcl_UniChar *uct = (const Tcl_UniChar *)uctPtr; + for ( ; numChars != 0; numChars--, ucs++, uct++) { if (*ucs != *uct) { Tcl_UniChar lcs = Tcl_UniCharToLower(*ucs); diff --git a/unix/tclUnixChan.c b/unix/tclUnixChan.c index 5742e9a52a8..bd461919bbe 100644 --- a/unix/tclUnixChan.c +++ b/unix/tclUnixChan.c @@ -646,20 +646,20 @@ TtySetOptionProc( #ifdef CRTSCTS CLEAR_BITS(iostate.c_cflag, CRTSCTS); #endif /* CRTSCTS */ - if (Tcl_UtfNcasecmp(value, "NONE", vlen) == 0) { + if (TclUtfNcasecmp(value, "NONE", vlen) == 0) { /* * Leave all handshake options disabled. */ - } else if (Tcl_UtfNcasecmp(value, "XONXOFF", vlen) == 0) { + } else if (TclUtfNcasecmp(value, "XONXOFF", vlen) == 0) { SET_BITS(iostate.c_iflag, IXON | IXOFF | IXANY); - } else if (Tcl_UtfNcasecmp(value, "RTSCTS", vlen) == 0) { + } else if (TclUtfNcasecmp(value, "RTSCTS", vlen) == 0) { #ifdef CRTSCTS SET_BITS(iostate.c_cflag, CRTSCTS); #else /* !CRTSTS */ UNSUPPORTED_OPTION("-handshake RTSCTS"); return TCL_ERROR; #endif /* CRTSCTS */ - } else if (Tcl_UtfNcasecmp(value, "DTRDSR", vlen) == 0) { + } else if (TclUtfNcasecmp(value, "DTRDSR", vlen) == 0) { UNSUPPORTED_OPTION("-handshake DTRDSR"); return TCL_ERROR; } else { @@ -759,19 +759,19 @@ TtySetOptionProc( ckfree(argv); return TCL_ERROR; } - if (Tcl_UtfNcasecmp(argv[i], "DTR", strlen(argv[i])) == 0) { + if (TclUtfNcasecmp(argv[i], "DTR", strlen(argv[i])) == 0) { if (flag) { SET_BITS(control, TIOCM_DTR); } else { CLEAR_BITS(control, TIOCM_DTR); } - } else if (Tcl_UtfNcasecmp(argv[i], "RTS", strlen(argv[i])) == 0) { + } else if (TclUtfNcasecmp(argv[i], "RTS", strlen(argv[i])) == 0) { if (flag) { SET_BITS(control, TIOCM_RTS); } else { CLEAR_BITS(control, TIOCM_RTS); } - } else if (Tcl_UtfNcasecmp(argv[i], "BREAK", strlen(argv[i])) == 0) { + } else if (TclUtfNcasecmp(argv[i], "BREAK", strlen(argv[i])) == 0) { #if defined(TIOCSBRK) && defined(TIOCCBRK) if (flag) { ioctl(fsPtr->fd, TIOCSBRK, NULL);