Ticket UUID: | adb198c256df8c4192838cc3c1112fb2821314e9 | |||
Title: | Potential Tcl_Obj leak in tclPathObj.c | |||
Type: | Bug | Version: | current | |
Submitter: | chw | Created on: | 2017-07-02 05:03:00 | |
Subsystem: | 36. Pathname Management | Assigned To: | nobody | |
Priority: | 5 Medium | Severity: | Critical | |
Status: | Closed | Last Modified: | 2017-07-06 16:35:32 | |
Resolution: | Fixed | Closed By: | dgp | |
Closed on: | 2017-07-06 16:35:32 | |||
Description: |
I think there are two potential Tcl_Obj leaks in the current version of tclPathObj.c in the TclJoinPath function, as shown in the following patch. The first in a newly introduced code path which releases a Tcl_Obj although it gets used later, the second regarding the path name separator returned as an optional new Tcl_Obj from a VFS implementation which never gets released. Index: generic/tclPathObj.c ================================================================== --- generic/tclPathObj.c +++ generic/tclPathObj.c @@ -916,22 +916,27 @@ * cannot have backslashes either. */ if ((tclPlatform != TCL_PLATFORM_WINDOWS) || (strchr(Tcl_GetString(elt), '\\') == NULL)) { - if (res != NULL) { - TclDecrRefCount(res); - } - if (PATHFLAGS(elt)) { + if (res != NULL) { + TclDecrRefCount(res); + } return TclNewFSPathObj(elt, str, len); } if (TCL_PATH_ABSOLUTE != Tcl_FSGetPathType(elt)) { + if (res != NULL) { + TclDecrRefCount(res); + } return TclNewFSPathObj(elt, str, len); } (void) Tcl_FSGetNormalizedPath(NULL, elt); if (elt == PATHOBJ(elt)->normPathPtr) { + if (res != NULL) { + TclDecrRefCount(res); + } return TclNewFSPathObj(elt, str, len); } } } @@ -1085,10 +1090,11 @@ if (fsPtr->filesystemSeparatorProc != NULL) { Tcl_Obj *sep = fsPtr->filesystemSeparatorProc(res); if (sep != NULL) { separator = TclGetString(sep)[0]; + Tcl_DecrRefCount(sep); } /* Safety check in case the VFS driver caused sharing */ if (Tcl_IsShared(res)) { TclDecrRefCount(res); res = Tcl_DuplicateObj(res); ================================================================== | |||
User Comments: |
dgp added on 2017-07-06 16:35:32:
Revised the fix on the 8.6 branch; will merge fwd. dgp added on 2017-07-06 15:28:37: Having said that, it's worth noting that the codebases of the 8.5 and 8.6 filesystem implementations have diverged, and I lack much confidence that a patch developed for one can lightly be applied to the other. I'd be happier leaving 8.5 untouched, and if that leaves unfixed bugs, then the fix for them is to start using 8.6. dgp added on 2017-07-06 15:25:36: I think that would be a further improvement. Will look into it. The code is messy, fragile, and abandoned by the originator, so it improves only in tiny, tentative incremental changes, usually motivated by actual bugs and crashes, not just aesthetic concerns. Someone who really got up a head of steam to make it much much better would be better off rewriting the thing from the ground up, IMO. That said, the memleak in the separator handling from a VFS looks legit and properly fixed. sebres added on 2017-07-06 14:56:39: > That means we can only execute this block on the first iteration of the for loop Hmm, strange... The question is "Why this belong then to the cycle, and not above it?" I fixed it just by the way like "minimalistic" surgery, so don't observed the cycle conditions. dgp added on 2017-07-06 14:14:56: This large conditional block https://core.tcl.tk/tcl/artifact/6c6428a1c565405c?ln=877-960 is conditioned on (i == 0) among others. That means we can only execute this block on the first iteration of the for loop, and at that point, nothing has had the chance to make res contain anything other than NULL. Much code directing what to do when (res != NULL) is actually useless. Some asserts would be better, I think. dgp added on 2017-07-06 14:08:26: Still looking, but it appears this is tidying up some code that cannot actually ever be reached. I think we'd be better eliminating it. dgp added on 2017-07-06 12:35:09: Any test cases? sebres added on 2017-07-03 09:25:46: Fixed for 8.6 and 8.5. Thanks. |