Changeset 14893 in webkit


Ignore:
Timestamp:
Jun 16, 2006 4:47:20 PM (18 years ago)
Author:
andersca
Message:

2006-06-17 Anders Carlsson <acarlsson@apple.com>

Reviewed by Maciej and Geoff.

http://bugzilla.opendarwin.org/show_bug.cgi?id=7080
Provide some way to stop a JavaScript infinite loop


  • kjs/completion.h: (KJS::): Add Interrupted completion type.


  • kjs/function.cpp: (KJS::FunctionImp::callAsFunction): (KJS::GlobalFuncImp::callAsFunction): Only set the exception on the new ExecState if the current one has had one.


  • kjs/interpreter.cpp: (KJS::TimeoutChecker::startTimeoutCheck): (KJS::TimeoutChecker::stopTimeoutCheck): (KJS::TimeoutChecker::alarmHandler): (KJS::TimeoutChecker::pauseTimeoutCheck): (KJS::TimeoutChecker::resumeTimeoutCheck): New TimeoutChecker class which handles setting Interpreter::m_timedOut flag after a given period of time. This currently only works on Unix platforms where setitimer and signals are used.


(KJS::Interpreter::Interpreter):
Initialize new member variables.


(KJS::Interpreter::~Interpreter):
Destroy the timeout checker.


(KJS::Interpreter::startTimeoutCheck):
(KJS::Interpreter::stopTimeoutCheck):
(KJS::Interpreter::pauseTimeoutCheck):
(KJS::Interpreter::resumeTimeoutCheck):
Call the timeout checker.


(KJS::Interpreter::handleTimeout):
Called on timeout. Resets the m_timedOut flag and calls shouldInterruptScript.


  • kjs/interpreter.h: (KJS::Interpreter::setTimeoutTime): New function for setting the timeout time.


(KJS::Interpreter::shouldInterruptScript):
New function. The idea is that this should be overridden by subclasses in order to for example
pop up a dialog asking the user if the script should be interrupted.


(KJS::Interpreter::checkTimeout):
New function which checks the m_timedOut flag and calls handleTimeout if it's set.


  • kjs/nodes.cpp: (DoWhileNode::execute): (WhileNode::execute): (ForNode::execute): Call Interpreter::checkTimeout after each iteration of the loop.
Location:
trunk/JavaScriptCore
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/ChangeLog

    r14883 r14893  
     12006-06-17  Anders Carlsson  <acarlsson@apple.com>
     2
     3        Reviewed by Maciej and Geoff.
     4
     5        http://bugzilla.opendarwin.org/show_bug.cgi?id=7080
     6        Provide some way to stop a JavaScript infinite loop
     7       
     8        * kjs/completion.h:
     9        (KJS::):
     10        Add Interrupted completion type.
     11       
     12        * kjs/function.cpp:
     13        (KJS::FunctionImp::callAsFunction):
     14        (KJS::GlobalFuncImp::callAsFunction):
     15        Only set the exception on the new ExecState if the current one has had one.
     16       
     17        * kjs/interpreter.cpp:
     18        (KJS::TimeoutChecker::startTimeoutCheck):
     19        (KJS::TimeoutChecker::stopTimeoutCheck):
     20        (KJS::TimeoutChecker::alarmHandler):
     21        (KJS::TimeoutChecker::pauseTimeoutCheck):
     22        (KJS::TimeoutChecker::resumeTimeoutCheck):
     23        New TimeoutChecker class which handles setting Interpreter::m_timedOut flag after a given
     24        period of time. This currently only works on Unix platforms where setitimer and signals are used.
     25       
     26        (KJS::Interpreter::Interpreter):
     27        Initialize new member variables.
     28       
     29        (KJS::Interpreter::~Interpreter):
     30        Destroy the timeout checker.
     31       
     32        (KJS::Interpreter::startTimeoutCheck):
     33        (KJS::Interpreter::stopTimeoutCheck):
     34        (KJS::Interpreter::pauseTimeoutCheck):
     35        (KJS::Interpreter::resumeTimeoutCheck):
     36        Call the timeout checker.
     37       
     38        (KJS::Interpreter::handleTimeout):
     39        Called on timeout. Resets the m_timedOut flag and calls shouldInterruptScript.
     40       
     41        * kjs/interpreter.h:
     42        (KJS::Interpreter::setTimeoutTime):
     43        New function for setting the timeout time.
     44       
     45        (KJS::Interpreter::shouldInterruptScript):
     46        New function. The idea is that this should be overridden by subclasses in order to for example
     47        pop up a dialog asking the user if the script should be interrupted.
     48       
     49        (KJS::Interpreter::checkTimeout):
     50        New function which checks the m_timedOut flag and calls handleTimeout if it's set.
     51       
     52        * kjs/nodes.cpp:
     53        (DoWhileNode::execute):
     54        (WhileNode::execute):
     55        (ForNode::execute):
     56        Call Interpreter::checkTimeout after each iteration of the loop.
     57
    1582006-06-15  Timothy Hatcher  <timothy@apple.com>
    259
  • trunk/JavaScriptCore/kjs/completion.h

    r12317 r14893  
    3434   * Completion types.
    3535   */
    36   enum ComplType { Normal, Break, Continue, ReturnValue, Throw };
     36  enum ComplType { Normal, Break, Continue, ReturnValue, Throw, Interrupted };
    3737
    3838  /**
  • trunk/JavaScriptCore/kjs/function.cpp

    r14834 r14893  
    7575                 codeType(), exec->context(), this, &args);
    7676  ExecState newExec(exec->dynamicInterpreter(), &ctx);
    77   newExec.setException(exec->exception()); // could be null
     77  if (exec->hadException())
     78    newExec.setException(exec->exception());
    7879
    7980  // assign user supplied arguments to parameters
     
    809810       
    810811        ExecState newExec(exec->dynamicInterpreter(), &ctx);
    811         newExec.setException(exec->exception()); // could be null
     812        if (exec->hadException())
     813            newExec.setException(exec->exception());
    812814       
    813815        // execute the code
  • trunk/JavaScriptCore/kjs/interpreter.cpp

    r14834 r14893  
    5151#endif
    5252
     53#if HAVE(SYS_TIME_H)
     54#include <sys/time.h>
     55#endif
     56
    5357#include <assert.h>
    5458#include <math.h>
     
    5761namespace KJS {
    5862
     63class TimeoutChecker {
     64public:
     65    void startTimeoutCheck(Interpreter*);
     66    void stopTimeoutCheck(Interpreter*);
     67    void pauseTimeoutCheck(Interpreter*);
     68    void resumeTimeoutCheck(Interpreter*);
     69
     70private:
     71#if HAVE(SYS_TIME_H)
     72    static Interpreter* s_executingInterpreter;
     73    static void alarmHandler(int);
     74   
     75    Interpreter* m_oldInterpreter;
     76    itimerval m_oldtv;
     77    itimerval m_pausetv;   
     78    void (*m_oldAlarmHandler)(int);
     79#endif
     80};
     81
     82#if HAVE(SYS_TIME_H)
     83Interpreter* TimeoutChecker::s_executingInterpreter = 0;
     84#endif
     85
     86void TimeoutChecker::startTimeoutCheck(Interpreter *interpreter)
     87{   
     88    if (!interpreter->m_timeoutTime)
     89        return;
     90   
     91    interpreter->m_startTimeoutCheckCount++;
     92   
     93#if HAVE(SYS_TIME_H)
     94    if (s_executingInterpreter == interpreter)
     95        return;
     96   
     97    // Block signals
     98    m_oldAlarmHandler = signal(SIGALRM, SIG_IGN);
     99
     100    m_oldInterpreter = s_executingInterpreter;
     101    s_executingInterpreter = interpreter;
     102   
     103    itimerval tv = {
     104      { interpreter->m_timeoutTime / 1000, (interpreter->m_timeoutTime % 1000) * 1000 },
     105      { interpreter->m_timeoutTime / 1000, (interpreter->m_timeoutTime % 1000) * 1000 }
     106    };
     107    setitimer(ITIMER_REAL, &tv, &m_oldtv);
     108   
     109    // Unblock signals
     110    signal(SIGALRM, alarmHandler);
     111#endif
     112}
     113
     114void TimeoutChecker::stopTimeoutCheck(Interpreter* interpreter)
     115{
     116    if (!interpreter->m_timeoutTime)
     117        return;
     118
     119    ASSERT(interpreter->m_startTimeoutCheckCount > 0);
     120   
     121    interpreter->m_startTimeoutCheckCount--;
     122   
     123    if (interpreter->m_startTimeoutCheckCount != 0)
     124        return;
     125       
     126#if HAVE(SYS_TIME_H)
     127    signal(SIGALRM, SIG_IGN);
     128
     129    s_executingInterpreter = m_oldInterpreter;
     130       
     131    setitimer(ITIMER_REAL, &m_oldtv, 0L);
     132    signal(SIGALRM, m_oldAlarmHandler);
     133#endif   
     134}
     135
     136#if HAVE(SYS_TIME_H)
     137void TimeoutChecker::alarmHandler(int)
     138{
     139    s_executingInterpreter->m_timedOut = true;
     140}
     141#endif
     142
     143void TimeoutChecker::pauseTimeoutCheck(Interpreter* interpreter)
     144{
     145    ASSERT(interpreter == s_executingInterpreter);
     146
     147#if HAVE(SYS_TIME_H)
     148    void (*currentSignalHandler)(int);
     149   
     150    // Block signal
     151    currentSignalHandler = signal(SIGALRM, SIG_IGN);
     152   
     153    if (currentSignalHandler != alarmHandler) {
     154        signal(SIGALRM, currentSignalHandler);
     155        return;
     156    }
     157
     158    setitimer(ITIMER_REAL, &m_pausetv, 0L);
     159#endif
     160
     161    interpreter->m_pauseTimeoutCheckCount++;
     162}
     163
     164void TimeoutChecker::resumeTimeoutCheck(Interpreter* interpreter)
     165{
     166    ASSERT(interpreter == s_executingInterpreter);
     167
     168    interpreter->m_pauseTimeoutCheckCount--;
     169
     170    if (interpreter->m_pauseTimeoutCheckCount != 0)
     171        return;
     172
     173#if HAVE(SYS_TIME_H)
     174    void (*currentSignalHandler)(int);
     175   
     176    // Check so we have the right handler
     177    currentSignalHandler = signal(SIGALRM, SIG_IGN);
     178   
     179    if (currentSignalHandler != SIG_IGN) {
     180        signal(SIGALRM, currentSignalHandler);
     181        return;
     182    }
     183
     184    setitimer(ITIMER_REAL, 0L, &m_pausetv);   
     185
     186    // Unblock signal
     187    currentSignalHandler = signal(SIGALRM, SIG_IGN);   
     188#endif
     189}
     190
    59191Interpreter* Interpreter::s_hook = 0;
    60192   
     
    67199   
    68200Interpreter::Interpreter(JSObject* globalObject)
    69     : m_globalExec(this, 0)
     201    : m_timeoutTime(0)
     202    , m_globalExec(this, 0)
    70203    , m_globalObject(globalObject)
    71204    , m_argumentsPropertyName(&argumentsPropertyName)
    72205    , m_specialPrototypePropertyName(&specialPrototypePropertyName)
     206    , m_timeoutChecker(0)
     207    , m_timedOut(false)
     208    , m_startTimeoutCheckCount(0)
     209    , m_pauseTimeoutCheckCount(0)
    73210{
    74211    init();
     
    76213
    77214Interpreter::Interpreter()
    78     : m_globalExec(this, 0)
     215    : m_timeoutTime(0)
     216    , m_globalExec(this, 0)
    79217    , m_globalObject(new JSObject())
    80218    , m_argumentsPropertyName(&argumentsPropertyName)
    81219    , m_specialPrototypePropertyName(&specialPrototypePropertyName)
     220    , m_timeoutChecker(0)
     221    , m_timedOut(false)
     222    , m_startTimeoutCheckCount(0)
     223    , m_pauseTimeoutCheckCount(0)
    82224{
    83225    init();
     
    111253{
    112254    JSLock lock;
     255   
     256    ASSERT (m_startTimeoutCheckCount == 0);
     257    ASSERT (m_pauseTimeoutCheckCount == 0);
     258   
     259    delete m_timeoutChecker;
    113260   
    114261    if (m_debugger)
     
    621768}
    622769
     770void Interpreter::startTimeoutCheck()
     771{
     772    if (!m_timeoutChecker)
     773        m_timeoutChecker = new TimeoutChecker;
     774   
     775    m_timeoutChecker->startTimeoutCheck(this);
     776}
     777
     778void Interpreter::stopTimeoutCheck()
     779{
     780    ASSERT(m_timeoutChecker);
     781   
     782    m_timeoutChecker->stopTimeoutCheck(this);
     783}
     784
     785void Interpreter::pauseTimeoutCheck()
     786{
     787    ASSERT(m_timeoutChecker);
     788   
     789    m_timeoutChecker->pauseTimeoutCheck(this);
     790}
     791
     792void Interpreter::resumeTimeoutCheck()
     793{
     794    ASSERT(m_timeoutChecker);
     795
     796    m_timeoutChecker->resumeTimeoutCheck(this);
     797}
     798
     799bool Interpreter::handleTimeout()
     800{
     801    m_timedOut = false;
     802   
     803    return shouldInterruptScript();
     804}
     805
     806
    623807SavedBuiltins::SavedBuiltins() :
    624808  _internal(0)
  • trunk/JavaScriptCore/kjs/interpreter.h

    r14834 r14893  
    3737  class SavedBuiltins;
    3838  class ScopeChain;
    39 
     39  class TimeoutChecker;
     40 
    4041  namespace Bindings {
    4142    class RootObject;
     
    5051  class Interpreter {
    5152      friend class Collector;
     53      friend class TimeoutChecker;
    5254  public:
    5355    /**
     
    323325   
    324326    static Interpreter* interpreterWithGlobalObject(JSObject*);
     327   
     328    void setTimeoutTime(unsigned timeoutTime) { m_timeoutTime = timeoutTime; }
     329
     330    void startTimeoutCheck();
     331    void stopTimeoutCheck();
     332
     333    void pauseTimeoutCheck();
     334    void resumeTimeoutCheck();
     335   
     336    bool checkTimeout();
     337   
     338protected:
     339    virtual bool shouldInterruptScript() { return true; }
     340    long m_timeoutTime;
     341
    325342private:
     343    bool handleTimeout();
    326344    void init();
    327345   
     
    355373    Context* m_context;
    356374    CompatMode m_compatMode;
     375
     376    TimeoutChecker* m_timeoutChecker;
     377    bool m_timedOut;
     378
     379    unsigned m_startTimeoutCheckCount;
     380    unsigned m_pauseTimeoutCheckCount;
    357381
    358382    ProtectedPtr<JSObject> m_Object;
     
    391415  };
    392416
     417  inline bool Interpreter::checkTimeout()
     418  {
     419    if (!m_timedOut)
     420      return false;
     421
     422    return handleTimeout();
     423  }
     424 
    393425} // namespace
    394426
  • trunk/JavaScriptCore/kjs/nodes.cpp

    r14834 r14893  
    17131713    c = statement->execute(exec);
    17141714    exec->context()->popIteration();
     1715   
     1716    if (exec->dynamicInterpreter()->checkTimeout())
     1717        return Completion(Interrupted);
     1718
    17151719    if (!((c.complType() == Continue) && ls.contains(c.target()))) {
    17161720      if ((c.complType() == Break) && ls.contains(c.target()))
     
    17571761    c = statement->execute(exec);
    17581762    exec->context()->popIteration();
     1763
     1764    if (exec->dynamicInterpreter()->checkTimeout())
     1765        return Completion(Interrupted);
     1766   
    17591767    if (c.isValueCompletion())
    17601768      value = c.value();
     
    18081816      return c;
    18091817    }
     1818   
     1819    if (exec->dynamicInterpreter()->checkTimeout())
     1820        return Completion(Interrupted);
     1821   
    18101822    if (expr3) {
    18111823      v = expr3->evaluate(exec);
Note: See TracChangeset for help on using the changeset viewer.