diff options
author | dgp <dgp@users.sourceforge.net> | 2019-03-08 14:46:26 (GMT) |
---|---|---|
committer | dgp <dgp@users.sourceforge.net> | 2019-03-08 14:46:26 (GMT) |
commit | df5dff900864760f02f1b93de275b401a5505f0e (patch) | |
tree | 8a25decae54c49bf39a7c7a266ebc4dfc2b24dc3 | |
parent | 2680fee6ce5b83af58184dcdb82ec765d431bbb1 (diff) | |
parent | c5abbcaaf4c32c6bfce25ff1a589f6e704116729 (diff) | |
download | tcl-df5dff900864760f02f1b93de275b401a5505f0e.zip tcl-df5dff900864760f02f1b93de275b401a5505f0e.tar.gz tcl-df5dff900864760f02f1b93de275b401a5505f0e.tar.bz2 |
[39fed4dae5] Make sure return value from Tcl_PkgRequire*() survives long enough
for caller to use it.
-rw-r--r-- | generic/tclPkg.c | 38 | ||||
-rw-r--r-- | generic/tclTestProcBodyObj.c | 47 | ||||
-rw-r--r-- | tests/proc.test | 3 |
3 files changed, 67 insertions, 21 deletions
diff --git a/generic/tclPkg.c b/generic/tclPkg.c index d4080c2..c1e2078 100644 --- a/generic/tclPkg.c +++ b/generic/tclPkg.c @@ -40,10 +40,7 @@ typedef struct PkgAvail { */ typedef struct Package { - char *version; /* Version that has been supplied in this - * interpreter via "package provide" - * (malloc'ed). NULL means the package doesn't - * exist in this interpreter yet. */ + Tcl_Obj *version; PkgAvail *availPtr; /* First in list of all available versions of * this package. */ const void *clientData; /* Client data. */ @@ -150,12 +147,13 @@ Tcl_PkgProvideEx( pkgPtr = FindPackage(interp, name); if (pkgPtr->version == NULL) { - DupString(pkgPtr->version, version); + pkgPtr->version = Tcl_NewStringObj(version, -1); + Tcl_IncrRefCount(pkgPtr->version); pkgPtr->clientData = clientData; return TCL_OK; } - if (CheckVersionAndConvert(interp, pkgPtr->version, &pvi, + if (CheckVersionAndConvert(interp, Tcl_GetString(pkgPtr->version), &pvi, NULL) != TCL_OK) { return TCL_ERROR; } else if (CheckVersionAndConvert(interp, version, &vi, NULL) != TCL_OK) { @@ -175,7 +173,7 @@ Tcl_PkgProvideEx( } Tcl_SetObjResult(interp, Tcl_ObjPrintf( "conflicting versions provided for package \"%s\": %s, then %s", - name, pkgPtr->version, version)); + name, Tcl_GetString(pkgPtr->version), version)); Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "VERSIONCONFLICT", NULL); return TCL_ERROR; } @@ -318,7 +316,7 @@ Tcl_PkgRequireEx( if (version == NULL) { if (Tcl_PkgRequireProc(interp, name, 0, NULL, clientDataPtr) == TCL_OK) { - result = Tcl_GetStringResult(interp); + result = Tcl_GetString(Tcl_GetObjResult(interp)); Tcl_ResetResult(interp); } } else { @@ -332,7 +330,7 @@ Tcl_PkgRequireEx( } Tcl_IncrRefCount(ov); if (Tcl_PkgRequireProc(interp, name, 1, &ov, clientDataPtr) == TCL_OK) { - result = Tcl_GetStringResult(interp); + result = Tcl_GetString(Tcl_GetObjResult(interp)); Tcl_ResetResult(interp); } TclDecrRefCount(ov); @@ -474,7 +472,8 @@ PkgRequireCoreFinal(ClientData data[], Tcl_Interp *interp, int result) { */ if (reqc != 0) { - CheckVersionAndConvert(interp, reqPtr->pkgPtr->version, &pkgVersionI, NULL); + CheckVersionAndConvert(interp, Tcl_GetString(reqPtr->pkgPtr->version), + &pkgVersionI, NULL); satisfies = SomeRequirementSatisfied(pkgVersionI, reqc, reqv); ckfree(pkgVersionI); @@ -482,7 +481,7 @@ PkgRequireCoreFinal(ClientData data[], Tcl_Interp *interp, int result) { if (!satisfies) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "version conflict for package \"%s\": have %s, need", - name, reqPtr->pkgPtr->version)); + name, Tcl_GetString(reqPtr->pkgPtr->version))); Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "VERSIONCONFLICT", NULL); AddRequirementsToResult(interp, reqc, reqv); @@ -495,7 +494,7 @@ PkgRequireCoreFinal(ClientData data[], Tcl_Interp *interp, int result) { *ptr = reqPtr->pkgPtr->clientData; } - Tcl_SetObjResult(interp, Tcl_NewStringObj(reqPtr->pkgPtr->version, -1)); + Tcl_SetObjResult(interp, reqPtr->pkgPtr->version); return TCL_OK; } @@ -694,8 +693,8 @@ SelectPackageFinal(ClientData data[], Tcl_Interp *interp, int result) { } else { char *pvi, *vi; - if (CheckVersionAndConvert(interp, reqPtr->pkgPtr->version, &pvi, - NULL) != TCL_OK) { + if (TCL_OK != CheckVersionAndConvert(interp, + Tcl_GetString(reqPtr->pkgPtr->version), &pvi, NULL)) { result = TCL_ERROR; } else if (CheckVersionAndConvert(interp, versionToProvide, &vi, NULL) != TCL_OK) { @@ -712,7 +711,7 @@ SelectPackageFinal(ClientData data[], Tcl_Interp *interp, int result) { "attempt to provide package %s %s failed:" " package %s %s provided instead", name, versionToProvide, - name, reqPtr->pkgPtr->version)); + name, Tcl_GetString(reqPtr->pkgPtr->version))); Tcl_SetErrorCode(interp, "TCL", "PACKAGE", "WRONGPROVIDE", NULL); } @@ -750,7 +749,7 @@ SelectPackageFinal(ClientData data[], Tcl_Interp *interp, int result) { */ if (reqPtr->pkgPtr->version != NULL) { - ckfree(reqPtr->pkgPtr->version); + Tcl_DecrRefCount(reqPtr->pkgPtr->version); reqPtr->pkgPtr->version = NULL; } reqPtr->pkgPtr->clientData = NULL; @@ -926,7 +925,7 @@ TclNRPackageObjCmd( pkgPtr = Tcl_GetHashValue(hPtr); Tcl_DeleteHashEntry(hPtr); if (pkgPtr->version != NULL) { - ckfree(pkgPtr->version); + Tcl_DecrRefCount(pkgPtr->version); } while (pkgPtr->availPtr != NULL) { availPtr = pkgPtr->availPtr; @@ -1084,8 +1083,7 @@ TclNRPackageObjCmd( if (hPtr != NULL) { pkgPtr = Tcl_GetHashValue(hPtr); if (pkgPtr->version != NULL) { - Tcl_SetObjResult(interp, - Tcl_NewStringObj(pkgPtr->version, -1)); + Tcl_SetObjResult(interp, pkgPtr->version); } } return TCL_OK; @@ -1378,7 +1376,7 @@ TclFreePackageInfo( hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { pkgPtr = Tcl_GetHashValue(hPtr); if (pkgPtr->version != NULL) { - ckfree(pkgPtr->version); + Tcl_DecrRefCount(pkgPtr->version); } while (pkgPtr->availPtr != NULL) { availPtr = pkgPtr->availPtr; diff --git a/generic/tclTestProcBodyObj.c b/generic/tclTestProcBodyObj.c index 4d32c5a..fba2844 100644 --- a/generic/tclTestProcBodyObj.c +++ b/generic/tclTestProcBodyObj.c @@ -21,13 +21,14 @@ */ static const char packageName[] = "procbodytest"; -static const char packageVersion[] = "1.0"; +static const char packageVersion[] = "1.1"; /* * Name of the commands exported by this package */ static const char procCommand[] = "proc"; +static const char checkCommand[] = "check"; /* * this struct describes an entry in the table of command names and command @@ -46,6 +47,8 @@ typedef struct CmdTable { static int ProcBodyTestProcObjCmd(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); +static int ProcBodyTestCheckObjCmd(ClientData dummy, + Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static int ProcBodyTestInitInternal(Tcl_Interp *interp, int isSafe); static int RegisterCommand(Tcl_Interp* interp, const char *namespace, const CmdTable *cmdTablePtr); @@ -57,11 +60,13 @@ static int RegisterCommand(Tcl_Interp* interp, static const CmdTable commands[] = { { procCommand, ProcBodyTestProcObjCmd, 1 }, + { checkCommand, ProcBodyTestCheckObjCmd, 1 }, { 0, 0, 0 } }; static const CmdTable safeCommands[] = { { procCommand, ProcBodyTestProcObjCmd, 1 }, + { checkCommand, ProcBodyTestCheckObjCmd, 1 }, { 0, 0, 0 } }; @@ -301,6 +306,46 @@ ProcBodyTestProcObjCmd( } /* + *---------------------------------------------------------------------- + * + * ProcBodyTestCheckObjCmd -- + * + * Implements the "procbodytest::check" command. Here is the command + * description: + * procbodytest::check + * + * Performs an internal check that the Tcl_PkgPresent() command returns + * the same version number as was registered when the procbodytest package + * was provided. Places a boolean in the interp result indicating the + * test outcome. + * + * Results: + * Returns a standard Tcl code. + * + *---------------------------------------------------------------------- + */ + +static int +ProcBodyTestCheckObjCmd( + ClientData dummy, /* context; not used */ + Tcl_Interp *interp, /* the current interpreter */ + int objc, /* argument count */ + Tcl_Obj *const objv[]) /* arguments */ +{ + const char *version; + + if (objc != 1) { + Tcl_WrongNumArgs(interp, 1, objv, ""); + return TCL_ERROR; + } + + version = Tcl_PkgPresent(interp, packageName, packageVersion, 1); + Tcl_SetObjResult(interp, Tcl_NewBooleanObj( + strcmp(version, packageVersion) == 0)); + return TCL_OK; +} + +/* * Local Variables: * mode: c * c-basic-offset: 4 diff --git a/tests/proc.test b/tests/proc.test index 8b25b0a..9be056f 100644 --- a/tests/proc.test +++ b/tests/proc.test @@ -321,6 +321,9 @@ test proc-4.8 {TclCreateProc, procbody obj, no leak on multiple iterations} -set rename getbytes {} unset -nocomplain end i tmp leakedBytes } -result 0 +test proc-4.9 {[39fed4dae5] Valid Tcl_PkgPresent return} procbodytest { + procbodytest::check +} 1 test proc-5.1 {Bytecompiling noop; test for correct argument substitution} -body { proc p args {} ; # this will be bytecompiled into t |