Fossil SCM
Add workaround for bug in Tcl_EvalObjCmd when compiled against Tcl 8.6.
Commit
3a6265696af8e634d1e32916f93ea1d93e79f60c
Parent
cba0f25bf2996f9…
1 file changed
+26
-2
+26
-2
| --- src/th_tcl.c | ||
| +++ src/th_tcl.c | ||
| @@ -4,10 +4,22 @@ | ||
| 4 | 4 | |
| 5 | 5 | #include "config.h" |
| 6 | 6 | #include "th.h" |
| 7 | 7 | #include "tcl.h" |
| 8 | 8 | |
| 9 | +/* | |
| 10 | +** Are we being compiled against Tcl 8.6 or higher? | |
| 11 | + */ | |
| 12 | +#if (TCL_MAJOR_VERSION > 8) || \ | |
| 13 | + ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 6)) | |
| 14 | +/* | |
| 15 | +** Workaround NRE-specific issue in Tcl_EvalObjCmd (SF bug #3399564) by using | |
| 16 | +** Tcl_EvalObjv instead of invoking the objProc directly. | |
| 17 | + */ | |
| 18 | +#define USE_TCL_EVALOBJV 1 | |
| 19 | +#endif | |
| 20 | + | |
| 9 | 21 | /* |
| 10 | 22 | ** These macros are designed to reduce the redundant code required to marshal |
| 11 | 23 | ** arguments from TH1 to Tcl. |
| 12 | 24 | */ |
| 13 | 25 | #define USE_ARGV_TO_OBJV() \ |
| @@ -159,16 +171,20 @@ | ||
| 159 | 171 | int argc, |
| 160 | 172 | const char **argv, |
| 161 | 173 | int *argl |
| 162 | 174 | ){ |
| 163 | 175 | Tcl_Interp *tclInterp; |
| 176 | +#ifndef USE_TCL_EVALOBJV | |
| 164 | 177 | Tcl_Command command; |
| 165 | 178 | Tcl_CmdInfo cmdInfo; |
| 179 | +#endif | |
| 166 | 180 | int rc; |
| 167 | 181 | int nResult; |
| 168 | 182 | const char *zResult; |
| 183 | +#ifndef USE_TCL_EVALOBJV | |
| 169 | 184 | Tcl_Obj *objPtr; |
| 185 | +#endif | |
| 170 | 186 | USE_ARGV_TO_OBJV(); |
| 171 | 187 | |
| 172 | 188 | if( argc<2 ){ |
| 173 | 189 | return Th_WrongNumArgs(interp, "tclInvoke command ?arg ...?"); |
| 174 | 190 | } |
| @@ -176,10 +192,11 @@ | ||
| 176 | 192 | if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){ |
| 177 | 193 | Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0); |
| 178 | 194 | return TH_ERROR; |
| 179 | 195 | } |
| 180 | 196 | Tcl_Preserve((ClientData)tclInterp); |
| 197 | +#ifndef USE_TCL_EVALOBJV | |
| 181 | 198 | objPtr = Tcl_NewStringObj(argv[1], argl[1]); |
| 182 | 199 | Tcl_IncrRefCount(objPtr); |
| 183 | 200 | command = Tcl_GetCommandFromObj(tclInterp, objPtr); |
| 184 | 201 | if( !command || Tcl_GetCommandInfoFromToken(command,&cmdInfo)==0 ){ |
| 185 | 202 | Th_ErrorMessage(interp, "Tcl command not found:", argv[1], argl[1]); |
| @@ -192,13 +209,18 @@ | ||
| 192 | 209 | Tcl_DecrRefCount(objPtr); |
| 193 | 210 | Tcl_Release((ClientData)tclInterp); |
| 194 | 211 | return TH_ERROR; |
| 195 | 212 | } |
| 196 | 213 | Tcl_DecrRefCount(objPtr); |
| 214 | +#endif | |
| 197 | 215 | COPY_ARGV_TO_OBJV(); |
| 216 | +#ifdef USE_TCL_EVALOBJV | |
| 217 | + rc = Tcl_EvalObjv(tclInterp, objc, objv, 0); | |
| 218 | +#else | |
| 198 | 219 | Tcl_ResetResult(tclInterp); |
| 199 | 220 | rc = cmdInfo.objProc(cmdInfo.objClientData, tclInterp, objc, objv); |
| 221 | +#endif | |
| 200 | 222 | FREE_ARGV_TO_OBJV(); |
| 201 | 223 | zResult = getTclResult(tclInterp, &nResult); |
| 202 | 224 | Th_SetResult(interp, zResult, nResult); |
| 203 | 225 | Tcl_Release((ClientData)tclInterp); |
| 204 | 226 | return rc; |
| @@ -213,19 +235,20 @@ | ||
| 213 | 235 | ClientData clientData, |
| 214 | 236 | Tcl_Interp *interp, |
| 215 | 237 | int objc, |
| 216 | 238 | Tcl_Obj *CONST objv[] |
| 217 | 239 | ){ |
| 218 | - Th_Interp *th1Interp = (Th_Interp *)clientData; | |
| 240 | + Th_Interp *th1Interp; | |
| 219 | 241 | int nArg; |
| 220 | 242 | const char *arg; |
| 221 | 243 | int rc; |
| 222 | 244 | |
| 223 | 245 | if( objc!=2 ){ |
| 224 | 246 | Tcl_WrongNumArgs(interp, 1, objv, "arg"); |
| 225 | 247 | return TCL_ERROR; |
| 226 | 248 | } |
| 249 | + th1Interp = (Th_Interp *)clientData; | |
| 227 | 250 | if( !th1Interp ){ |
| 228 | 251 | Tcl_AppendResult(interp, "invalid TH1 interpreter", NULL); |
| 229 | 252 | return TCL_ERROR; |
| 230 | 253 | } |
| 231 | 254 | arg = Tcl_GetStringFromObj(objv[1], &nArg); |
| @@ -244,19 +267,20 @@ | ||
| 244 | 267 | ClientData clientData, |
| 245 | 268 | Tcl_Interp *interp, |
| 246 | 269 | int objc, |
| 247 | 270 | Tcl_Obj *CONST objv[] |
| 248 | 271 | ){ |
| 249 | - Th_Interp *th1Interp = (Th_Interp *)clientData; | |
| 272 | + Th_Interp *th1Interp; | |
| 250 | 273 | int nArg; |
| 251 | 274 | const char *arg; |
| 252 | 275 | int rc; |
| 253 | 276 | |
| 254 | 277 | if( objc!=2 ){ |
| 255 | 278 | Tcl_WrongNumArgs(interp, 1, objv, "arg"); |
| 256 | 279 | return TCL_ERROR; |
| 257 | 280 | } |
| 281 | + th1Interp = (Th_Interp *)clientData; | |
| 258 | 282 | if( !th1Interp ){ |
| 259 | 283 | Tcl_AppendResult(interp, "invalid TH1 interpreter", NULL); |
| 260 | 284 | return TCL_ERROR; |
| 261 | 285 | } |
| 262 | 286 | arg = Tcl_GetStringFromObj(objv[1], &nArg); |
| 263 | 287 |
| --- src/th_tcl.c | |
| +++ src/th_tcl.c | |
| @@ -4,10 +4,22 @@ | |
| 4 | |
| 5 | #include "config.h" |
| 6 | #include "th.h" |
| 7 | #include "tcl.h" |
| 8 | |
| 9 | /* |
| 10 | ** These macros are designed to reduce the redundant code required to marshal |
| 11 | ** arguments from TH1 to Tcl. |
| 12 | */ |
| 13 | #define USE_ARGV_TO_OBJV() \ |
| @@ -159,16 +171,20 @@ | |
| 159 | int argc, |
| 160 | const char **argv, |
| 161 | int *argl |
| 162 | ){ |
| 163 | Tcl_Interp *tclInterp; |
| 164 | Tcl_Command command; |
| 165 | Tcl_CmdInfo cmdInfo; |
| 166 | int rc; |
| 167 | int nResult; |
| 168 | const char *zResult; |
| 169 | Tcl_Obj *objPtr; |
| 170 | USE_ARGV_TO_OBJV(); |
| 171 | |
| 172 | if( argc<2 ){ |
| 173 | return Th_WrongNumArgs(interp, "tclInvoke command ?arg ...?"); |
| 174 | } |
| @@ -176,10 +192,11 @@ | |
| 176 | if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){ |
| 177 | Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0); |
| 178 | return TH_ERROR; |
| 179 | } |
| 180 | Tcl_Preserve((ClientData)tclInterp); |
| 181 | objPtr = Tcl_NewStringObj(argv[1], argl[1]); |
| 182 | Tcl_IncrRefCount(objPtr); |
| 183 | command = Tcl_GetCommandFromObj(tclInterp, objPtr); |
| 184 | if( !command || Tcl_GetCommandInfoFromToken(command,&cmdInfo)==0 ){ |
| 185 | Th_ErrorMessage(interp, "Tcl command not found:", argv[1], argl[1]); |
| @@ -192,13 +209,18 @@ | |
| 192 | Tcl_DecrRefCount(objPtr); |
| 193 | Tcl_Release((ClientData)tclInterp); |
| 194 | return TH_ERROR; |
| 195 | } |
| 196 | Tcl_DecrRefCount(objPtr); |
| 197 | COPY_ARGV_TO_OBJV(); |
| 198 | Tcl_ResetResult(tclInterp); |
| 199 | rc = cmdInfo.objProc(cmdInfo.objClientData, tclInterp, objc, objv); |
| 200 | FREE_ARGV_TO_OBJV(); |
| 201 | zResult = getTclResult(tclInterp, &nResult); |
| 202 | Th_SetResult(interp, zResult, nResult); |
| 203 | Tcl_Release((ClientData)tclInterp); |
| 204 | return rc; |
| @@ -213,19 +235,20 @@ | |
| 213 | ClientData clientData, |
| 214 | Tcl_Interp *interp, |
| 215 | int objc, |
| 216 | Tcl_Obj *CONST objv[] |
| 217 | ){ |
| 218 | Th_Interp *th1Interp = (Th_Interp *)clientData; |
| 219 | int nArg; |
| 220 | const char *arg; |
| 221 | int rc; |
| 222 | |
| 223 | if( objc!=2 ){ |
| 224 | Tcl_WrongNumArgs(interp, 1, objv, "arg"); |
| 225 | return TCL_ERROR; |
| 226 | } |
| 227 | if( !th1Interp ){ |
| 228 | Tcl_AppendResult(interp, "invalid TH1 interpreter", NULL); |
| 229 | return TCL_ERROR; |
| 230 | } |
| 231 | arg = Tcl_GetStringFromObj(objv[1], &nArg); |
| @@ -244,19 +267,20 @@ | |
| 244 | ClientData clientData, |
| 245 | Tcl_Interp *interp, |
| 246 | int objc, |
| 247 | Tcl_Obj *CONST objv[] |
| 248 | ){ |
| 249 | Th_Interp *th1Interp = (Th_Interp *)clientData; |
| 250 | int nArg; |
| 251 | const char *arg; |
| 252 | int rc; |
| 253 | |
| 254 | if( objc!=2 ){ |
| 255 | Tcl_WrongNumArgs(interp, 1, objv, "arg"); |
| 256 | return TCL_ERROR; |
| 257 | } |
| 258 | if( !th1Interp ){ |
| 259 | Tcl_AppendResult(interp, "invalid TH1 interpreter", NULL); |
| 260 | return TCL_ERROR; |
| 261 | } |
| 262 | arg = Tcl_GetStringFromObj(objv[1], &nArg); |
| 263 |
| --- src/th_tcl.c | |
| +++ src/th_tcl.c | |
| @@ -4,10 +4,22 @@ | |
| 4 | |
| 5 | #include "config.h" |
| 6 | #include "th.h" |
| 7 | #include "tcl.h" |
| 8 | |
| 9 | /* |
| 10 | ** Are we being compiled against Tcl 8.6 or higher? |
| 11 | */ |
| 12 | #if (TCL_MAJOR_VERSION > 8) || \ |
| 13 | ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 6)) |
| 14 | /* |
| 15 | ** Workaround NRE-specific issue in Tcl_EvalObjCmd (SF bug #3399564) by using |
| 16 | ** Tcl_EvalObjv instead of invoking the objProc directly. |
| 17 | */ |
| 18 | #define USE_TCL_EVALOBJV 1 |
| 19 | #endif |
| 20 | |
| 21 | /* |
| 22 | ** These macros are designed to reduce the redundant code required to marshal |
| 23 | ** arguments from TH1 to Tcl. |
| 24 | */ |
| 25 | #define USE_ARGV_TO_OBJV() \ |
| @@ -159,16 +171,20 @@ | |
| 171 | int argc, |
| 172 | const char **argv, |
| 173 | int *argl |
| 174 | ){ |
| 175 | Tcl_Interp *tclInterp; |
| 176 | #ifndef USE_TCL_EVALOBJV |
| 177 | Tcl_Command command; |
| 178 | Tcl_CmdInfo cmdInfo; |
| 179 | #endif |
| 180 | int rc; |
| 181 | int nResult; |
| 182 | const char *zResult; |
| 183 | #ifndef USE_TCL_EVALOBJV |
| 184 | Tcl_Obj *objPtr; |
| 185 | #endif |
| 186 | USE_ARGV_TO_OBJV(); |
| 187 | |
| 188 | if( argc<2 ){ |
| 189 | return Th_WrongNumArgs(interp, "tclInvoke command ?arg ...?"); |
| 190 | } |
| @@ -176,10 +192,11 @@ | |
| 192 | if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){ |
| 193 | Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0); |
| 194 | return TH_ERROR; |
| 195 | } |
| 196 | Tcl_Preserve((ClientData)tclInterp); |
| 197 | #ifndef USE_TCL_EVALOBJV |
| 198 | objPtr = Tcl_NewStringObj(argv[1], argl[1]); |
| 199 | Tcl_IncrRefCount(objPtr); |
| 200 | command = Tcl_GetCommandFromObj(tclInterp, objPtr); |
| 201 | if( !command || Tcl_GetCommandInfoFromToken(command,&cmdInfo)==0 ){ |
| 202 | Th_ErrorMessage(interp, "Tcl command not found:", argv[1], argl[1]); |
| @@ -192,13 +209,18 @@ | |
| 209 | Tcl_DecrRefCount(objPtr); |
| 210 | Tcl_Release((ClientData)tclInterp); |
| 211 | return TH_ERROR; |
| 212 | } |
| 213 | Tcl_DecrRefCount(objPtr); |
| 214 | #endif |
| 215 | COPY_ARGV_TO_OBJV(); |
| 216 | #ifdef USE_TCL_EVALOBJV |
| 217 | rc = Tcl_EvalObjv(tclInterp, objc, objv, 0); |
| 218 | #else |
| 219 | Tcl_ResetResult(tclInterp); |
| 220 | rc = cmdInfo.objProc(cmdInfo.objClientData, tclInterp, objc, objv); |
| 221 | #endif |
| 222 | FREE_ARGV_TO_OBJV(); |
| 223 | zResult = getTclResult(tclInterp, &nResult); |
| 224 | Th_SetResult(interp, zResult, nResult); |
| 225 | Tcl_Release((ClientData)tclInterp); |
| 226 | return rc; |
| @@ -213,19 +235,20 @@ | |
| 235 | ClientData clientData, |
| 236 | Tcl_Interp *interp, |
| 237 | int objc, |
| 238 | Tcl_Obj *CONST objv[] |
| 239 | ){ |
| 240 | Th_Interp *th1Interp; |
| 241 | int nArg; |
| 242 | const char *arg; |
| 243 | int rc; |
| 244 | |
| 245 | if( objc!=2 ){ |
| 246 | Tcl_WrongNumArgs(interp, 1, objv, "arg"); |
| 247 | return TCL_ERROR; |
| 248 | } |
| 249 | th1Interp = (Th_Interp *)clientData; |
| 250 | if( !th1Interp ){ |
| 251 | Tcl_AppendResult(interp, "invalid TH1 interpreter", NULL); |
| 252 | return TCL_ERROR; |
| 253 | } |
| 254 | arg = Tcl_GetStringFromObj(objv[1], &nArg); |
| @@ -244,19 +267,20 @@ | |
| 267 | ClientData clientData, |
| 268 | Tcl_Interp *interp, |
| 269 | int objc, |
| 270 | Tcl_Obj *CONST objv[] |
| 271 | ){ |
| 272 | Th_Interp *th1Interp; |
| 273 | int nArg; |
| 274 | const char *arg; |
| 275 | int rc; |
| 276 | |
| 277 | if( objc!=2 ){ |
| 278 | Tcl_WrongNumArgs(interp, 1, objv, "arg"); |
| 279 | return TCL_ERROR; |
| 280 | } |
| 281 | th1Interp = (Th_Interp *)clientData; |
| 282 | if( !th1Interp ){ |
| 283 | Tcl_AppendResult(interp, "invalid TH1 interpreter", NULL); |
| 284 | return TCL_ERROR; |
| 285 | } |
| 286 | arg = Tcl_GetStringFromObj(objv[1], &nArg); |
| 287 |