Skip to content

Commit b155c8c

Browse files
committed
fix(event-loop): no exception should be thrown when an invalid timeoutID is passed to clearTimeout, silently do nothing instead
1 parent 471ce4b commit b155c8c

3 files changed

Lines changed: 26 additions & 5 deletions

File tree

include/PyEventLoop.hh

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,12 @@ public:
5555
_timeoutIdMap.push_back(std::move(handle));
5656
return _timeoutIdMap.size() - 1; // the index in `_timeoutIdMap`
5757
}
58-
static inline AsyncHandle &fromId(uint32_t timeoutID) {
59-
return _timeoutIdMap.at(timeoutID);
58+
static inline AsyncHandle *fromId(uint32_t timeoutID) {
59+
try {
60+
return &_timeoutIdMap.at(timeoutID);
61+
} catch (...) { // std::out_of_range&
62+
return nullptr; // invalid timeoutID
63+
}
6064
}
6165

6266
/**

src/modules/pythonmonkey/pythonmonkey.cc

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -234,13 +234,22 @@ static bool setTimeout(JSContext *cx, unsigned argc, JS::Value *vp) {
234234
static bool clearTimeout(JSContext *cx, unsigned argc, JS::Value *vp) {
235235
using AsyncHandle = PyEventLoop::AsyncHandle;
236236
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
237+
JS::HandleValue timeoutIdArg = args.get(0);
238+
239+
args.rval().setUndefined();
240+
241+
// silently does nothing when an invalid timeoutID is passed in
242+
if (!timeoutIdArg.isNumber()) {
243+
return true;
244+
}
237245

238246
// Retrieve the AsyncHandle by `timeoutID`
239-
double timeoutID = args[0].toNumber();
240-
AsyncHandle &handle = AsyncHandle::fromId((uint32_t)timeoutID);
247+
double timeoutID = timeoutIdArg.toNumber();
248+
AsyncHandle *handle = AsyncHandle::fromId((uint32_t)timeoutID);
249+
if (!handle) return true; // does nothing on invalid timeoutID
241250

242251
// Cancel this job on Python event-loop
243-
handle.cancel();
252+
handle->cancel();
244253

245254
return true;
246255
}

tests/python/test_pythonmonkey_eval.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,14 @@ def to_raise(msg):
677677
# TODO (Tom Tang): test `setTimeout` setting delay to 0 if < 0
678678
# TODO (Tom Tang): test `setTimeout` accepting string as the delay, coercing to a number like parseFloat
679679

680+
# passing an invalid ID to `clearTimeout` should silently do nothing; no exception is thrown.
681+
pm.eval("clearTimeout(NaN)")
682+
pm.eval("clearTimeout(999)")
683+
pm.eval("clearTimeout(-1)")
684+
pm.eval("clearTimeout('a')")
685+
pm.eval("clearTimeout(undefined)")
686+
pm.eval("clearTimeout()")
687+
680688
# making sure the async_fn is run
681689
return True
682690
assert asyncio.run(async_fn())

0 commit comments

Comments
 (0)