Sean Anderson [Sun, 11 Jun 2023 03:54:26 +0000 (23:54 -0400)]
vhpi: Fix use-after-free when removing callbacks (part 2)
I made a first attempt at this back in commit a21a360e ("vhpi: Fix
use-after-free when removing callbacks"), but I didn't fix the global or
value callbacks. These can also have use-after-frees, which can be
triggered consistently with a pair of "mutually-removing" callbacks.
They are set up so that they trigger on the next cycle, and they try to
remove themselves. This fails without the fixes in this commit.
The main approach is to give rt_watch_t the same treatment that
c_callback got: adding a flag to free the watch after the callback
completes. Global callbacks are a bit simpler, and can mostly be treated
like timeout callbacks; if we don't find anything to remove, the
callback must be currently-enqueued, so we shouldn't free it.
Fixes: d6e523a4 ("vhpi: Free callbacks in remove")
Sean Anderson [Sat, 10 Jun 2023 23:04:30 +0000 (19:04 -0400)]
vhpi: Fix incorrect range calculation
Null ranges have zero length. Detect them properly by basing the
direvction of the range on IsUp instead of whether LeftBound >
RightBound. The comparison in init_indexedName can stay the same since
it is guarded by build_indexedNames.
Fixes: 2052a42f ("vhpi: Rework size calculation") Fixes: 9416eb6e ("vhpi: Add support for IndexedNames")
Sean Anderson [Sat, 10 Jun 2023 21:06:48 +0000 (17:06 -0400)]
vhpi: Fix NULL-pointer dereference in vhpi_get_by_name
strtok_r returns NULL when there are no more tokens in the string. When
passed a name matching scope's name, but without a colon or period, we
call strtok_r twice, getting NULL the second time. Because the name
matches the region, fix this by returning the region.
Sean Anderson [Mon, 29 May 2023 21:39:41 +0000 (17:39 -0400)]
vhpi: Add support for getting/putting IndexedNames
This allows getting/putting nested arrays, and individual elements of an
array. The final index calculation is done lazily, although this
could be done eagerly by moving it to init_indexedName.
The tests for indexednames and the various enum types are extended now
that it is easier to access them.
Sean Anderson [Mon, 29 May 2023 21:49:14 +0000 (17:49 -0400)]
vhpi: Fix vhpi_get_value with EnumVecVal format
The Logic, SmallEnum, and Enum formats were not treated consistently.
Sometimes the wrong value type was used to store signals, and the
variable signal size of Enum was not handled properly. The correct
relationships for these types may be seen in the following table:
Format Value type Signal size
================ ============== ===========
vhpiLogicVal vhpiEnumT 8
vhpiSmallEnumVal vhpiSmallEnumT 8
vhpiEnumVal vhpiEnumT variable
In order to handle the variable size of Enum, we need to use FOR_ALL_SIZES
from model.c. Move it to util.h, and rename a conflicting macro with a
similar purpose. This also adds support for getting SmallEnumVecs.
This adds a test for the Vec versions of these formats; the non-vec
versions will be tested when indexedName get/put support is added.
Sean Anderson [Mon, 29 May 2023 21:04:52 +0000 (17:04 -0400)]
vhpi: Add support for IndexedNames
IndexedNames (e.g. `a(0)` or `a(2, 3)`) are necessary to access elements
of nested or multidimensional arrays (which have too many dimensions for
vhpiLogicVecVal) or to set individual elements of single-dimensional
arrays. Add basic support for these objects.
Although objDecls are names too, they also include the decl properties
which we don't want. Therefore, we use a separate hierarchy for
exprs/names. For future work, it might be nice to use the object
framework (tree_t, type_t, etc) for VHPI as well.
IndexedNames are created lazily. This is useful for nested arrays. For
example, a signal like
type a is array(0 to 9) of std_logic_vector(31 downto 0);
signal b: a;
might only be accessed like `b(0)` and never like `b(2)(3)`.
The encoding of prefixedName varies slightly from the UML. To reuse the
above example, while the UML says that the prefix of `b(0)` is `b`,
we set prefix as NULL in this situation, using simpleName instead. This
makes it easier to walk nested prefixes, since we don't have to compare
prefix to simpleName.
To populate IndexedNames, we must iterate over all constraints on the
array, and create `c_indexedName`s for each. One option here would be to
pass BaseIndex to init_indexedName. However, this would require decoding
the BaseIndex into indices for each constraint. Indead, I chose to pass
the indices directly, and create BaseIndex from them. I think this is
easier, because it doesn't involve any division.
Sean Anderson [Mon, 29 May 2023 20:11:56 +0000 (16:11 -0400)]
vhpi: Rework size calculation
IndexedNames represent a subset of the elements in a signal. Their size
is dependent on their type. In preparation for adding IndexedName
support, rework the size calculation to be based on the type of the
object instead of the width of the backing signal.
Sean Anderson [Mon, 29 May 2023 19:45:06 +0000 (15:45 -0400)]
vhpi: Support constraints
Add support for range constraints on arrays and subtypes. I think the
from/to on unconstrained ranges should reflect the from/to of the
underlying type, but I have left that out for now. Currently no
properties are supported, but that will change soon.
Sean Anderson [Mon, 29 May 2023 19:23:07 +0000 (15:23 -0400)]
vhpi: Add support for subtypes
Add very basic support for subtypes. This is just enough to place them
in the type hierarchy, and not much else. Array subtypes are always
created as arrayTypeDecls, since this will let us expose the element
subtype properly.
Sean Anderson [Mon, 29 May 2023 23:02:31 +0000 (19:02 -0400)]
vhpi: Pass type directly to init_typeDecl
Anonymous types can't be looked up by their ident, so the decl is for
their base type instead. Pass the type directly instead of using
tree_type to ensure the type matches what it represents.
Sean Anderson [Mon, 29 May 2023 18:36:17 +0000 (14:36 -0400)]
vhpi: Move iterator initialization to init_iterator
In preparation for merging the logic in vhpi_iterator with
vhpi_handle_for_index, split off iterator initialization into its own
function. This replaces new_iterator so we can avoid a memory
allocation if possible in vhpi_handle_for_index.
Sean Anderson [Mon, 29 May 2023 17:09:37 +0000 (13:09 -0400)]
vhpi: Move BaseType to c_typeDecl
Each Type has a BaseType. Except for subtypes, the BaseType is the Type
itself. In preparation for adding subTypeDecls, move BaseType to
typeDecl. This allows us to calculate the BaseType when necessary,
removing the need to have a redundant BaseType reference.
Sean Anderson [Mon, 22 May 2023 16:01:38 +0000 (12:01 -0400)]
Fix coverage generation for unary operators
Unary functions (such as reductions) cause an assertion failure in
lower_logic_expr_coverage. As they operate on arrays, and arrays are
skipped anyway, modify this function to skip such operators. Also remove
a debug print while we're here.
Add a test case to ensure such functions are excluded from coverage.
Sean Anderson [Sat, 20 May 2023 21:02:19 +0000 (17:02 -0400)]
vhpi: Calculate callback timeout at registration
Callback timeouts must be calculated at registration, not at enabling:
> Disabling a callback simply determines whether or not the callback will
> be triggered when its trigger event occurs. For example, disabling a
> callback that is registered to trigger after a given delay and
> subsequently enabling before expiry of the delay does not postpone the
> time at which the trigger event occurs.
Additionally, any data in cb_data_p that we do not save (such as time)
may not be accessed after we return from registration.
Sean Anderson [Sat, 20 May 2023 18:05:38 +0000 (14:05 -0400)]
vhpi: Fix use-after-free when removing callbacks
Callbacks can generally be in a few states:
- Disabled or mature
- Actively executing
- Waiting to execute
For all callbacks except for AfterDelay, when the callback is waiting to
execute then clearing it will prevent further execution. However,
AfterDelay callbacks can be absent from the eventq_heap in the driverq
workqueue awaiting execution. Clearing these callbacks will not prevent
them from executing.
To work around this, make model_clear_timeout_cb return a boolean
indicating whether a callback was actually cleared. If no callback was
cleared and the callback is not currently executing, then the callback
is in a workqueue. In this case, just free the callback later.
Otherwise, we have actually removed a callback and we can be sure that
it will not execute, so free it now.
Fixes: d6e523a4 ("vhpi: Free callbacks in remove")
Sean Anderson [Sat, 20 May 2023 18:00:08 +0000 (14:00 -0400)]
vhpi: Allow disabling ValueChange callbacks
Allow disabling ValueChange callbacks by clearing the individual
wakeables. This function could take rt_signal_t and user data, but the
signal is calculated for VHPI callbacks, and it is easier to just store
the watch instead.
Sean Anderson [Sat, 20 May 2023 17:55:37 +0000 (13:55 -0400)]
model: Correct timing of RT_LAST_KNOWN_DELTA_CYCLE
According to the spec, vhpiCbLastKnownDeltaCycle callbacks can create
further delta cycles:
> h) If the next simulation cycle will be a delta cycle, the remainder of
> step h) is skipped. Otherwise, the following actions occur in the
> indicated order:
>
> 1. Each registered and enabled `vhpiCbLastKnownDeltaCycle` and
> `vhpiCbRepLastKnownDeltaCycle` callback is executed. T_n is
> recalculated according to the rules of 14.7.5.1.
> 2. If the next simulation cycle will be a delta cycle, the remainder
> of step h) is skipped.
> 3. ...
Fire RT_LAST_KNOWN_DELTA_CYCLE before disabling delta cycles to allow
this to happen.