Age | Commit message (Collapse) | Author |
|
The previously introduced signal handler restoration logic did not take
the signal dispatching pipe into account.
Extend the `uc_vm_signal_handlers_reset()` function to also close any
related pipe handles.
Fixes: #255
Fixes: f9d2faf ("vm: reset signals when freeing VM")
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
The previous code refactoring inadvertently broke the signal setup
condition check.
Fixes: #254
Fixes: f9d2faf ("vm: reset signals when freeing VM")
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
When invoking `uc_vm_free()` on a VM with enabled `.setup_signal_handlers`
configuration, reset system signal handlers back to their default actions.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Introduce an extensible private TLS context structure and use it within
libucode to store global state such as active object iterators.
This allows using libucode concurrently in multiple threads without
unintentionally sharing global state among them.
Also adjust the signal dispatching setup logic in `uc_vm_init()` to only
enable signal handling if no other VM in the same thread already handles
signals.
Suggested-by: Isaac de Wolff <idewolff@vincitech.nl>
[squash commits, move signal handler vm pointer and object iterator list
into common extensible TLS context, whitespace and naming adjustments,
extended signal setup logic]
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Commit e5fe6b1 ("treewide: refactor vector usage code") accidentially dropped
the upvalue resolving logic from uc_vm_stack_push(), leading to unresolved
upvalues leaking into the script execution context.
Fixes: e5fe6b1 ("treewide: refactor vector usage code")
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
utils: improve vector macros
|
|
Utilize uc_vector_push() and uc_vector_foreach() where applicable.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
When keys are added to the object currently being iterated by a for loop,
the insert operation might cause a hashtable resize with a subsequent
memory reallocation and a different table base pointer, clobbering the
entry pointers held by iterators pointing to the containing object of the
resized table.
In order to address this issue while keeping the iteration overhead low,
extend the object key insert logic to check whether the insertion will
trigger a reallocation and backup and restore the iterator pointers when
needed.
This slightly increases the size of the iterator states but the overhead
for this should be neglectible as there'll only be a low amount of
concurrently active iterations at any time.
Fixes: #230
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
- Ensure that testing for array membership does strict equality tests
- Ensure that `(NaN in [ NaN ]) == true`
- Do not perform implicit value conversion when testing for object keys,
to avoid nonsensical results such as `([] in { "[ ]": true }) == true`
- Add test cases for the `in` operator
Fixes: #193
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Ensure that deleting object keys during iteration is safe by keeping a
global chain of per-object iterators which are advanced to the next key
when the entry that is about to be iterated is deleted.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
When building against glibc with enabled source fortification, gcc reports
the following issue:
.../vm.c: In function ‘uc_vm_signal_raise’:
.../vm.c:3161:9: error: ignoring return value of ‘write’ declared with attribute ‘warn_unused_result’ [-Werror=unused-result]
3161 | write(vm->signal.sigpipe[1], &signum, sizeof(signum));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Since we cannot do any meaningful handling of a potential write error in
the affected signal handler context, simply solve this issue by wrapping
the `write()` call into an empty `if ()` statement.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Get rid of most __APPLE__ guards by introducing a central platform.c unit
providing drop-in replacements for missing APIs.
Also move system signal definitions into the new platform file to be able
to share them with the upcoming debug library.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Introduce the basic facilities to implement UNIX process signal handling
in ucode. The VM structure is extended by a bitmap keeping track of
received signal numbers, a sigaction structure which holds a generic
signal handler to update the bitmap, a pipe where the generic signal
handler will send received signal numbers to and an array of managed
signal handler functions, indexed by signal number.
Additionally, three new C API functions are added to control signal
delivery in the VM instance:
- `uc_vm_signal_dispatch()`
This function invokes signal handler callbacks for each received
signal number, clears the bitmap and empties the pipe. The VM itself
will invoke this function after each executed bytecode instruction.
In some cases however it is useful for C code driving the VM to
force immediate signal delivery, e.g. from within long running C
functions that do not return to ucode (to the next bytecode
instruction) in a timely manner.
- `uc_vm_signal_raise()`
This function will deliver the given signal number, so that it is
picked up by the next call to `uc_vm_signal_dispatch()`. It is used
by the generic C signal handler function to forward received signals
to the VM instance.
- `uc_vm_signal_notifyfd()`
This functions returns the read end of the internal signal pipe.
It is mainly useful for integration into select or poll based event
loops, in order to be notified when there's pending signals for
delivery into the VM instance.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Ensure to release the `this` context and the temporary argument stash
when we raise a non iterable type exception due to non-iterable values
while precessing spread operations in function call arguments.
Those values would've been garbage collected eventually but explicitly
releasing them here will allow the vm to free them immediately.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
This avoids unnecessary gc calls when configuring a gc interval while also
explicitly calling ucv_gc from C code embedding a vm at convenient points in
time.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
|
When compiling logical assignment expressions, ensure that the right hand
side of the assignment is not evaluated when the assignment condition is
unfulfilled.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Instead of having one global export table per VM instance maintain one table
per program instance. This is required to avoid clobbering the export list
in case `import` using code is loaded at runtime through `require()`,
`loadfile()` etc.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Introduce two new VM api functions uc_vm_gc_start() and uc_vm_gc_stop()
which allow starting and stopping automatic periodic garbage collection
of cyclic objects in the VM context.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
The I_DYNLOAD opcode is basically a bytecode level instruction for
uc_require() with semantics similar to I_IMPORT. It allows loading
a dynamic extension library at runtime and treating values from the
resulting module context object like exports from a compile time source
module.
For example the statement `import { readfile, writefile } from "fs"`
would import the readfile() and writefile() functions of fs.so as
readonly live bindings into the current file scope.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Try to resolve the source offset to line and character position and only
fall back to report the location as instruction offset if we weren't able
to determine the line number.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Module function upvalues are patched through import operations, ensure to
leave them uninitialized when loading and executing the module constructor.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
The upcoming compile-time module support will require the configured
extension search path in the compiler as well, so move it to the
already shared uc_parse_config_t structure and add the appropriate
utility functions to initialize, append and free the search path
vector.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Introduce new opcodes to realize module imports and exports. The export
operation will capture a local variable as upvalue and store it in VM
wide module export registry while the import operation will connect an
upvalue from the module export registry with a preallocated upvalue in
the running function scope.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Reject modifications on object and array values with a type exception when
the constant flag is set on the value operated upon.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Resolve upvalue references to their actual values when pushing such
references onto the stack (or when attempting to call them as method).
This allows constructing objects of pointers, as needed for wildcard
module imports.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Upcoming module support will rely on upresolved upvalues which are patched
at runtime to realize module imports, make sure the VM trace code does not
choke on such unresolved upvalues.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
The upcoming module support requires maintaining multiple source objects
within the same program, so add the necessary infrastructure for it.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
When a managed function is indirectly invoked during bytecode execution,
e.g. when calling the tostring() method of an object prototype during
string concatenation, the invoked function must stop executing bytecode
upon return to hand control back to caller.
Extend `uc_vm_execute_chunk()` to track the amount of nested function
calls it performs and hand back control to the caller once the toplevel
callframe returns. Also bubble unhandled exceptions only as far as up
to the original caller.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Move the invocation of the unhandled exception callback handler out of
`uc_vm_execute_chunk()` into both `uc_vm_execute()` and `uc_vm_invoke()`
in order to consistently report exceptions exactly once regardless of
whether a native or managed code function is executed as topmost VM
call.
This solves cases where the unhandled exception callback was either
called multiple times or never at all.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
When invoking a native function as toplevel VM call which indirectly
triggers an unhandled exception in managed code, the callframes are
completely reset before the C function returns, leading to invalid
memory accesses when `uc_vm_call_native()` subsequently popped it's
own callframe again.
This issue did not surface by executing script code through the
interpreter since in this case the VM will always execute a managed
code as toplevel call, but it could be triggered by invoking a native
function triggering an exception through the C API using `uc_vm_call()`
on a fresh `uc_vm_t` context or by utilizing the CLI interpreters `-l`
flag to preload a native code library triggering an exception.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
When executing an object literal declaration using non-string computed
property name values, the VM crashed caused by an attempt to use a NULL
pointer (result of ucv_string_get() on a non-string value) as hash table
key.
Fix this issue by using the `ucv_key_set()` infrastructure which deals
with the implicit stringification of non-string key values.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
- Support ES2016 exponentiation (**) and exponentiation assignment (**=)
- Support ES2020 nullish coalescing (??) and logical nullish assignment (??=)
- Support ES2021 logical and assignment (&&=) and logical or assignment (||=)
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
When attempting to invoke a non-function value as method or when the the
internal recursion limit was exceeded, `uc_vm_call_function()` emitted
and internal runtime exception and freed the function value but not the
`this` context associated with the method call.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
- Instead of treating individual program functions as managed ucode types,
demote uc_function_t values to pointers into a uc_program_t entity
- Promote uc_program_t to a managed type
- Let uc_closure_t claim references to the owning program of the enclosed
uc_function_t
- Redefine public APIs uc_compile() and uc_vm_execute() APIs to return and
expect an uc_program_t object respectively
- Remove vallist indirection for function loading and let the compiler
emit the function id directly when producing function construction code
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Clang emits code which evaluates function call argument expressions in a
different order, causing `uc_dump_insn()` to receive the instruction pointer
address after decoding the instruction, not before.
Avoid that problem by explicitly caching the pre-decode address in a
temporary variable which is then passed to `uc_dump_insn()`.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
The internal uc_vm_call_function() helper may fail in different ways before
the stack frame has been set up, e.g. if the provided function value was not
actually a callable function. In such cases an exception is raised but the
actual function value is leaked since there's not yet a stackframe referring
to it.
Solve the issue by freeing the function value explicitly in these exit cases.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
- Move source object pointer into program entity which is referenced by
each function
- Move lineinfo related routines into source.c and use them from lexer.c
since lineinfo encoding does not belong into the lexical analyzer.
- Implement initial infrastructure for detecting source file type,
this is required later to differentiate between plaintext and
precompiled bytecode files
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Instead of storing constant values per function, maintain a global program
wide list for all constant values within the current compilation unit.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
- Introduce a new "program" entity which holds the list of functions
created during compilation
- Instead of storing pointers to the in-memory function representation
in the constant list, store the index of the function within the
program's function list
- When loading functions from the constant list, retrieve the function
by index from the program entity
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
When concatenating strings, avoid allocating three times the required
memory in the worst case. Instead of first allocating the string
representations of the operands followed by the memory for the final
string, allocate a string buffer and print the operands into it. This
will grow the target memory as needed and avoid redundant internal
copies of the involved strings.
Also handle the special where the final string fits into a tagged
pointer and deal with it accordingly.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
- Parse integer literals as unsigned numeric values in order to be able
to represent the entire unsigned 64bit value range
- Stop parsing minus-prefixed integer literals as negative numbers but
treat them as separate minus operator followed by a positive integer
instead
- Only store unsigned numeric constants in bytecode
- Rework numeric comparison logic to be able to handle full 64bit
unsigned integers
- If possible, yield unsigned 64 bit results for additions
- Simplify numeric value conversion API
- Compile code with -fwrapv for defined signed overflow semantics
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Introduce a new, lazily allocated value registry which can be used by C
code to store values which should not be garbage collected.
The registry is a plain ucode object internally and treated as GC root
but not exposed to ucode script code, this allows it to retain references
to values which are otherwise completely unreachable from ucode scripts.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Fix various misspelling of "resource".
This commit changes the exported libucode ABI.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
No functional changes.
Fixes: ff52440 ("treewide: consolidate typedef naming")
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Allow querying object properties on resource values. A resource value may
have a prototype object set whose properties should be enumerable.
Support that use case in the VM.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Fix instances of misspelled "resource".
This commit breaks the exported libucode ABI.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
syntax: introduce optional chaining operators
|
|
Introduce new operators `?.`, `?.[…]` and `?.(…)` to simplify looking up
deeply nested property chain in a secure manner.
The `?.` operator behaves like the `.` property access operator but yields
`null` if the left hand side is `null` or not an object.
Like `?.`, the `?.[…]` operator behaves like the `[…]` computed property
access but yields `null` if the left hand side is `null` or neither an
object or array.
Finally the `?.(…)` operator behaves like the function call operator `(…)`
but yields `null` if the left hand side is `null` or not a callable
function.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|
|
Reset all callframes when dealing with an unhandled exception to avoid
resuming the code which raised the exception when restarting the VM
later, e.g. through uc_vm_call() or uc_vm_invoke().
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
|