Ensure that hooks are unaffected by a request to stop emulation. (#1154)

This change removes the check for stop requests from the hook loop
macro.

Requests to stop emulation (uc_emu_stop) should only affect whether
the emulation stops. This isn't the case at present for the invocation
of hooks. If emulation is requested to be stopped (which is indicated
by `uc->stop_request`), the hooks will skip all execution. This means
that when the emulation stop is requested, some expected operations
may not occur before the emulation exits - leaving the system in an
inconsistent or broken state.

This is particularly obvious in the case where a CPU interrupt is
required, and a hook has been registered for such cases. The expected
operation is that the hook be called, and no CPU exception be raised
(because the hook has handled it). However, because of the short-cut
in the case where the `uc_emu_stop` function has been called out of
band (eg on another thread), this hook would not be called. In such
cases the execution would terminate with an error that an 'unhandled
CPU exception' occurred, and the hook would never have been called.

This probably affects other parts of the system, such as hooks which
handle remapping of memory on demand (UC_HOOK_MEM_READ_UNMAPPED and
friends) where the remap would not happen and instead an error about
the unmapped memory would be raised.

In all cases, it makes sense that execution continue normally until
the outer loop which controls the execution determines that the
emulation should stop. This will mean that for any given sequence of
events all the emulation operations are completed deterministically
regardless of when the stop request was received.
This commit is contained in:
Charles Ferguson 2020-05-05 01:36:50 +01:00 committed by GitHub
parent 625399774c
commit f0b509c176
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -120,9 +120,7 @@ enum uc_hook_idx {
#define HOOK_FOREACH(uc, hh, idx) \
for ( \
cur = (uc)->hook[idx##_IDX].head; \
cur != NULL && ((hh) = (struct hook *)cur->data) \
/* stop excuting callbacks on stop request */ \
&& !uc->stop_request; \
cur != NULL && ((hh) = (struct hook *)cur->data); \
cur = cur->next)
// if statement to check hook bounds