Menu

#168 CommandLimit patch

closed-out-of-date
5
2014-08-18
2000-10-26
Anonymous
No

OriginalBugID: 5799 RFE
Version: 8.3.1
SubmitDate: '2000-06-02'
LastModified: '2000-10-25'
Severity: LOW
Status: UnAssn
Submitter: techsupp
OS: Linux-Red Hat
FixedDate: '2000-10-25'
ClosedDate: '2000-10-25'

Name:

Jonathan Booth

Comments:

Thanks for the time. This patch could possibly use the improvment of a

way to set a limited number of commands for a child interpreter, for the

'interp' tcl command, but the C stuff here is a needed, and useful, base

to that.

DesiredBehavior:

For Tcl to be a truly good embeddable scripting language, it needs a way to catch when user entered code has gone awry, into an infinate (or long) loop. To do this, it needs to support limits on the number of commands that can be exexcuted in a particular, or in all interpreters combined. The patch below implements this in a simple way.

Patch:

Index: stock.1/generic/tcl.decls

*** stock.1/generic/tcl.decls Thu, 01 Jun 2000 01:33:14 -0500 kamikaze (tcl/k/3>

--- clp.1/generic/tcl.decls Fri, 02 Jun 2000 15:13:38 -0500 kamikaze (tcl/k/39_>

***************

*** 1358,1363 ****

--- 1358,1378 ----

ClientData clientData, int stackSize, int flags)

}

+ # Jonathan Booth <kamikaze@imsa.edu>, June 1, 2000

+ # Command Limits Patch

+ #

+ # C-Level API for restricting the number of commands that an

+ # interpreter, and all interpreters may execute. This is useful to

+ # make sure that malicious or incorrect user-input-code does not cause

+ # the application to lock up in an infinate loop.

+

+ declare 394 generic {

+ int Tcl_SetCommandLimit (Tcl_Interp *interp, int limit)

+ }

+ declare 395 generic {

+ int Tcl_SetGlobalCommandLimit (int limit)

+ }

+

##############################################################################

# Define the platform specific public Tcl interface. These functions are

Index: stock.1/generic/tclInt.h

*** stock.1/generic/tclInt.h Thu, 01 Jun 2000 01:33:14 -0500 kamikaze (tcl/k/46>

--- clp.1/generic/tclInt.h Fri, 02 Jun 2000 15:13:38 -0500 kamikaze (tcl/k/46_t>

***************

*** 1195,1200 ****

--- 1195,1203 ----

int cmdCount; /* Total number of times a command procedure

* has been called for this interpreter. */

+ int cmdMax; /* Total number of commands that may be

+ * called in this interpreter. If set to

+ * -1, then there is no limit. */

int evalFlags; /* Flags to control next call to Tcl_Eval.

* Normally zero, but may be set before

* calling Tcl_Eval. See below for valid

***************

*** 1525,1530 ****

--- 1528,1534 ----

extern TclPlatformType tclPlatform;

extern char * tclpFileAttrStrings[];

extern CONST TclFileAttrProcs tclpFileAttrProcs[];

+ extern int tclCmdMax;

/*

* Variables denoting the Tcl object types defined in the core.

Index: stock.1/generic/tclDecls.h

*** stock.1/generic/tclDecls.h Thu, 01 Jun 2000 01:33:14 -0500 kamikaze (tcl/k/>

--- clp.1/generic/tclDecls.h Fri, 02 Jun 2000 15:13:38 -0500 kamikaze (tcl/k/48>

***************

*** 1228,1233 ****

--- 1228,1238 ----

Tcl_ThreadCreateProc proc,

ClientData clientData, int stackSize,

int flags));

+ /* 394 */

+ EXTERN int Tcl_SetCommandLimit _ANSI_ARGS_((Tcl_Interp * interp,

+ int limit));

+ /* 395 */

+ EXTERN int Tcl_SetGlobalCommandLimit _ANSI_ARGS_((int limit));

typedef struct TclStubHooks {

struct TclPlatStubs *tclPlatStubs;

***************

*** 1689,1694 ****

--- 1694,1701 ----

void (*tcl_ConditionFinalize) _ANSI_ARGS_((Tcl_Condition * condPtr)); /* >

void (*tcl_MutexFinalize) _ANSI_ARGS_((Tcl_Mutex * mutex)); /* 392 */

int (*tcl_CreateThread) _ANSI_ARGS_((Tcl_ThreadId * idPtr, Tcl_ThreadCrea>

+ int (*tcl_SetCommandLimit) _ANSI_ARGS_((Tcl_Interp * interp, int limit));>

+ int (*tcl_SetGlobalCommandLimit) _ANSI_ARGS_((int limit)); /* 395 */

} TclStubs;

#ifdef __cplusplus

***************

*** 3309,3314 ****

--- 3316,3329 ----

#ifndef Tcl_CreateThread

#define Tcl_CreateThread \

(tclStubsPtr->tcl_CreateThread) /* 393 */

+ #endif

+ #ifndef Tcl_SetCommandLimit

+ #define Tcl_SetCommandLimit \

+ (tclStubsPtr->tcl_SetCommandLimit) /* 394 */

+ #endif

+ #ifndef Tcl_SetGlobalCommandLimit

+ #define Tcl_SetGlobalCommandLimit \

+ (tclStubsPtr->tcl_SetGlobalCommandLimit) /* 395 */

#endif

#endif /* defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) */

Index: stock.1/generic/tclStubInit.c

*** stock.1/generic/tclStubInit.c Thu, 01 Jun 2000 01:33:14 -0500 kamikaze (tcl>

--- clp.1/generic/tclStubInit.c Fri, 02 Jun 2000 15:13:38 -0500 kamikaze (tcl/l>

***************

*** 791,796 ****

--- 791,798 ----

Tcl_ConditionFinalize, /* 391 */

Tcl_MutexFinalize, /* 392 */

Tcl_CreateThread, /* 393 */

+ Tcl_SetCommandLimit, /* 394 */

+ Tcl_SetGlobalCommandLimit, /* 395 */

};

/* !END!: Do not edit above this line. */

Index: stock.1/generic/tclExecute.c

*** stock.1/generic/tclExecute.c Thu, 01 Jun 2000 01:33:14 -0500 kamikaze (tcl/>

--- clp.1/generic/tclExecute.c Fri, 02 Jun 2000 15:13:38 -0500 kamikaze (tcl/l/>

***************

*** 100,105 ****

--- 100,112 ----

"+", "-", "*", "/", "%", "+", "-", "~", "!",

"BUILTIN FUNCTION", "FUNCTION"

};

+

+ /*

+ * Global command limit -- maximum number of commands that may be

+ * executed by all interpreters. Keeps (safe) interpreters from

+ * entering infinate loops. Set via Tcl_SetGlobalCommandLimit().

+ */

+ int tclCmdMax = -1;

/*

* Mapping from Tcl result codes to strings; used for error and debugging

***************

*** 612,617 ****

--- 619,638 ----

#ifdef TCL_COMPILE_STATS

iPtr->stats.instructionCount[*pc]++;

#endif

+

+ if (tclCmdMax > 0) {

+ tclCmdMax--;

+ }

+ if (iPtr->cmdMax > 0) {

+ iPtr->cmdMax--;

+ }

+ if ((iPtr->cmdMax == 0) || (tclCmdMax == 0)) {

+ result = TCL_ERROR;

+ Tcl_ResetResult(interp);

+ Tcl_AppendToObj(Tcl_GetObjResult(interp), "command limit reached">

+ goto abnormalReturn;

+ }

+

switch (*pc) {

case INST_DONE:

/*

Index: stock.1/generic/tclBasic.c

*** stock.1/generic/tclBasic.c Thu, 01 Jun 2000 01:33:14 -0500 kamikaze (tcl/m/>

--- clp.1/generic/tclBasic.c Fri, 02 Jun 2000 15:13:38 -0500 kamikaze (tcl/m/10>

***************

*** 326,331 ****

--- 326,332 ----

Tcl_InitHashTable(&iPtr->packageTable, TCL_STRING_KEYS);

iPtr->packageUnknown = NULL;

iPtr->cmdCount = 0;

+ iPtr->cmdMax = -1;

iPtr->termOffset = 0;

TclInitLiteralTable(&(iPtr->literalTable));

iPtr->compileEpoch = 0;

***************

*** 4180,4185 ****

--- 4181,4264 ----

old = iPtr->maxNestingDepth;

if (depth > 0) {

iPtr->maxNestingDepth = depth;

+ }

+ return old;

+ }

+ ^L

+ /*

+ *----------------------------------------------------------------------

+ *

+ * Tcl_SetCommandLimit --

+ *

+ * Set the maximum number of function calls that may be done

+ * for an interpreter. Set the number to 0 to disable the limit,

+ * -1 to get the current limit.

+ *

+ * Must be reset before each call to Tcl_Eval*()

+ *

+ * Results:

+ * The return value is the number of commands executable before

+ * the limit terminates execution.

+ *

+ * Side effects:

+ * None.

+ *

+ *----------------------------------------------------------------------

+ */

+

+ int

+ Tcl_SetCommandLimit(interp, limit)

+ Tcl_Interp *interp; /* Interpreter whose command li>

+ * is to be set. */

+ int limit; /* New value for maximimum numb>

+ * of commands executed. */

+ {

+ Interp *iPtr = (Interp *) interp;

+ int old;

+

+ old = iPtr->cmdMax;

+ if (limit == 0) {

+ iPtr->cmdMax = -1;

+ } else if (limit > 0) {

+ iPtr->cmdMax = limit;

+ }

+ return old;

+ }

+ ^L

+ /*

+ *----------------------------------------------------------------------

+ *

+ * Tcl_SetGlobalCommandLimit --

+ *

+ * Set the maximum number of function calls that may be done

+ * by all interpreters together. This will catch nasty

+ * attacks that try to use other interpreters to do long running

+ * things.

+ *

+ * Must be reset before each call to Tcl_Eval*()

+ *

+ * Results:

+ * The return value is the number of commands executable before

+ * the limit terminates execution.

+ *

+ * Side effects:

+ * None.

+ *

+ *----------------------------------------------------------------------

+ */

+

+ int

+ Tcl_SetGlobalCommandLimit(limit)

+ int limit; /* New value for maximimum numb>

+ * of commands executed. */

+ {

+ int old;

+

+ old = tclCmdMax;

+ if (limit == 0) {

+ tclCmdMax = -1;

+ } else if (limit > 0) {

+ tclCmdMax = limit;

}

return old;

}

PatchFiles:

generic/tcl.decls

generic/tclInt.h

generic/tclDecls.h

generic/tclStubInit.c

generic/tclExecute.c

generic/tclBasic.c

Discussion

  • Donal K. Fellows

    • milestone: 102436 --> 102413
     
  • Donal K. Fellows

    This change should go through the TIP mechanism. It does sound like a good idea though (from a cursory glance.)

     
  • Donal K. Fellows

    • labels: 104246 --> 105682
     
  • Don Porter

    Don Porter - 2001-04-03
    • labels: 105682 --> 45. Parsing and Eval
     
  • Donal K. Fellows

    • assigned_to: nobody --> msofer
     
  • miguel sofer

    miguel sofer - 2004-03-26

    Logged In: YES
    user_id=148712

    This is part of TIP 143,assigning to dkf.

     
  • miguel sofer

    miguel sofer - 2004-03-26
    • assigned_to: msofer --> dkf
     
  • Donal K. Fellows

    Logged In: YES
    user_id=79902

    Deeper review indicates that this won't work. The code
    doesn't deal with interpreted commands, doesn't count
    commands at all (!) but instructions instead, has no
    introspection, has no thread locking on the global command
    limit (!!!), and probably has other problems I can't spot
    without really working at it. Some of these problems are
    resolvable, some are resolvable only with a significant
    performance hit, and others require a rethink.

    Keeping open to remind me to work in the TIP#143 C API,
    which will obsolete this FRQ (the global limit stuff is a
    no-no because of inter-thread problems, and there's no
    provision of installing other kinds of limits, which #143
    addresses.)

     
  • Donal K. Fellows

    Logged In: YES
    user_id=79902

    See Patch 926771

     
  • Donal K. Fellows

    • status: open --> closed-out-of-date
     
  • Donal K. Fellows

    Logged In: YES
    user_id=79902

    Tcl 8.5 will include an implementation of TIP#143 (see
    http://purl.org/tcl/tip/143.html for details) which
    completely subsumes the functionality proposed by this patch
    as well as providing for time-limits as well.