From d1573a45315634609abe16f9e17e99a17370c10d Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Thu, 28 Mar 2024 11:59:08 +0000 Subject: [PATCH] Replace vhpiHandleT with a reference counted handle --- src/vhpi/vhpi-model.c | 351 +++++++++++++++++++++++++++++------------- src/vhpi/vhpi-str.c | 59 +++---- src/vhpi/vhpi-util.h | 1 + test/vhpi/vhpi1.c | 8 +- test/vhpi/vhpi2.c | 10 +- test/vhpi/vhpi3.c | 5 +- test/vhpi/vhpi5.c | 23 ++- tools/run.sh | 2 +- 8 files changed, 311 insertions(+), 148 deletions(-) diff --git a/src/vhpi/vhpi-model.c b/src/vhpi/vhpi-model.c index 809b0284..cac0260b 100644 --- a/src/vhpi/vhpi-model.c +++ b/src/vhpi/vhpi-model.c @@ -43,6 +43,7 @@ typedef vhpiSmallEnumT vhpiBooleanT; typedef struct { vhpiClassKindT kind; + vhpiHandleT handle; loc_t loc; } c_vhpiObject; @@ -392,22 +393,15 @@ typedef struct { DEF_CLASS(forGenerate, vhpiForGenerateK, region.object); -typedef enum { - CB_INACTIVE, - CB_ACTIVE, - CB_FREE_LATER -} callback_status_t; - typedef struct { - c_vhpiObject object; - vhpiStateT State; - vhpiEnumT Reason; - vhpiCbDataT data; + c_vhpiObject object; + vhpiStateT State; + vhpiEnumT Reason; + vhpiCbDataT data; union { - uint64_t when; - rt_watch_t *w; + uint64_t when; + rt_watch_t *watch; }; - callback_status_t status; } c_callback; DEF_CLASS(callback, vhpiCallbackK, object); @@ -422,14 +416,26 @@ typedef struct { DEF_CLASS(iterator, vhpiIteratorK, object); +#define HANDLE_BITS (sizeof(vhpiHandleT) * 8) +#define HANDLE_MAX_SLOT ((UINT64_C(1) << (HANDLE_BITS / 2)) - 1) + +typedef struct { + c_vhpiObject *obj; + uint32_t refcount; + uint32_t generation; +} handle_slot_t; + typedef struct _vhpi_context { - c_tool *tool; - c_rootInst *root; - shash_t *strtab; - rt_model_t *model; - hash_t *objcache; - tree_t top; - jit_t *jit; + c_tool *tool; + c_rootInst *root; + shash_t *strtab; + rt_model_t *model; + hash_t *objcache; + tree_t top; + jit_t *jit; + handle_slot_t *handles; + unsigned num_handles; + unsigned free_hint; } vhpi_context_t; static c_typeDecl *cached_typeDecl(type_t type, c_vhpiObject *obj); @@ -441,6 +447,7 @@ static void *vhpi_get_value_ptr(c_vhpiObject *obj); static c_typeDecl *vhpi_get_type(c_vhpiObject *obj); static vhpiClassKindT vhpi_get_prefix_kind(c_vhpiObject *obj); static void vhpi_build_stmts(tree_t container, c_abstractRegion *region); +static const char *handle_pp(vhpiHandleT handle); static vhpi_context_t *global_context = NULL; // TODO: thread local @@ -455,17 +462,116 @@ static inline vhpi_context_t *vhpi_context(void) return global_context; } +static handle_slot_t *decode_handle(vhpi_context_t *c, vhpiHandleT handle) +{ + const uintptr_t bits = (uintptr_t)handle; + const uint32_t index = bits & HANDLE_MAX_SLOT; + const uint32_t generation = bits >> HANDLE_BITS/2; + + if (handle == NULL || index >= c->num_handles) + return NULL; + + handle_slot_t *slot = &(c->handles[index]); + if (slot->obj == NULL) + return NULL; + else if (slot->generation != generation) + return NULL; // Use-after-free + + assert(slot->refcount > 0); + assert(slot->obj->handle == handle); + + return slot; +} + static vhpiHandleT handle_for(c_vhpiObject *obj) { - return (vhpiHandleT)obj; + assert(obj != NULL); + + vhpi_context_t *c = vhpi_context(); + + if (obj->handle != NULL) { + handle_slot_t *slot = decode_handle(c, obj->handle); + assert(slot != NULL); + assert(slot->refcount > 0); + assert(slot->obj == obj); + + slot->refcount++; + return obj->handle; + } + + uint32_t index = c->free_hint; + if (index >= c->num_handles || c->handles[index].obj != NULL) { + for (index = 0; index < c->num_handles; index++) { + if (c->handles[index].obj == NULL) + break; + } + } + + if (unlikely(index > HANDLE_MAX_SLOT)) { + vhpi_error(vhpiFailure, NULL, "too many active handles"); + return NULL; + } + else if (index == c->num_handles) { + const int new_size = MAX(c->num_handles * 2, 128); + c->handles = xrealloc_array(c->handles, new_size, sizeof(handle_slot_t)); + c->num_handles = new_size; + + for (int i = index; i < new_size; i++) { + c->handles[i].obj = NULL; + c->handles[i].refcount = 0; + c->handles[i].generation = 1; + } + } + + handle_slot_t *slot = &(c->handles[index]); + assert(slot->refcount == 0); + slot->refcount = 1; + slot->obj = obj; + + c->free_hint = index + 1; + + const uintptr_t bits = (uintptr_t)slot->generation << HANDLE_BITS/2 | index; + return (obj->handle = (vhpiHandleT)bits); +} + +static void drop_handle(vhpiHandleT handle) +{ + vhpi_context_t *c = vhpi_context(); + + handle_slot_t *slot = decode_handle(c, handle); + if (slot == NULL) + return; + + assert(slot->refcount > 0); + if (--(slot->refcount) > 0) + return; + + c_vhpiObject *obj = slot->obj; + slot->obj = NULL; + slot->generation++; + + obj->handle = NULL; + + c->free_hint = slot - c->handles; + + switch (obj->kind) { + case vhpiCallbackK: + case vhpiIteratorK: + free(obj); + break; + default: + break; + } } -static c_vhpiObject *from_handle(vhpiHandleT handle) +static inline c_vhpiObject *from_handle(vhpiHandleT handle) { - if (handle == NULL) - vhpi_error(vhpiError, NULL, "invalid handle"); + handle_slot_t *slot = decode_handle(vhpi_context(), handle); + if (slot != NULL) + return slot->obj; - return (c_vhpiObject *)handle; + vhpi_error(vhpiError, NULL, "invalid handle %p", handle); + return NULL; } static c_abstractRegion *is_abstractRegion(c_vhpiObject *obj) @@ -676,19 +782,28 @@ static const char *handle_pp(vhpiHandleT handle) tb_printf(tb, "%p:{", handle); c_vhpiObject *obj = from_handle(handle); - tb_cat(tb, vhpi_class_str(obj->kind)); + if (obj == NULL) + tb_cat(tb, "INVALID"); + else { + tb_cat(tb, vhpi_class_str(obj->kind)); - c_abstractDecl *decl = is_abstractDecl(obj); - if (decl != NULL) - tb_printf(tb, " Name=%s", decl->Name); + c_abstractDecl *decl = is_abstractDecl(obj); + if (decl != NULL) + tb_printf(tb, " Name=%s", decl->Name); - c_name *n = is_name(obj); - if (n != NULL) - tb_printf(tb, " Name=%s", n->Name); + c_name *n = is_name(obj); + if (n != NULL) + tb_printf(tb, " Name=%s", n->Name); - c_iterator *it = is_iterator(obj); - if (it != NULL && it->list != NULL) - tb_printf(tb, " pos=%d/%d", it->pos, it->list->count); + c_iterator *it = is_iterator(obj); + if (it != NULL && it->list != NULL) + tb_printf(tb, " pos=%d/%d", it->pos, it->list->count); + + c_callback *cb = is_callback(obj); + if (cb != NULL) + tb_printf(tb, " Reason=%s State=%s", vhpi_cb_reason_str(cb->Reason), + vhpi_state_str(cb->State)); + } tb_append(tb, '}'); @@ -1242,50 +1357,61 @@ static bool init_iterator(c_iterator *it, vhpiOneToManyT type, c_vhpiObject *obj return false; } -static void vhpi_do_callback(c_callback *cb) +static void vhpi_signal_event_cb(uint64_t now, rt_signal_t *signal, + rt_watch_t *watch, void *user) { - if (cb->State == vhpiEnable) { - cb->status = CB_ACTIVE; - (cb->data.cb_rtn)(&(cb->data)); + c_vhpiObject *obj = from_handle(user); + if (obj == NULL) + return; - if (!vhpi_is_repetitive(cb->Reason)) - cb->State = vhpiMature; + c_callback *cb = is_callback(obj); + if (cb == NULL) + return; + + vhpiTimeT time; + if (cb->data.time != NULL) { + vhpi_get_time(&time, NULL); + cb->data.time = &time; } - if (cb->status == CB_FREE_LATER) - free(cb); - else - cb->status = CB_INACTIVE; + if (cb->State == vhpiEnable) + (cb->data.cb_rtn)(&(cb->data)); } -static void vhpi_timeout_cb(rt_model_t *m, void *user) +static void vhpi_global_cb(rt_model_t *m, void *user) { - c_callback *cb; - if ((cb = is_callback(user))) - vhpi_do_callback(cb); -} + vhpiHandleT handle = user; -static void vhpi_signal_event_cb(uint64_t now, rt_signal_t *signal, - rt_watch_t *watch, void *user) -{ - vhpiTimeT time; + { + c_vhpiObject *obj = from_handle(handle); + if (obj == NULL) + return; - c_callback *cb; - if ((cb = is_callback(user))) { - if (cb->data.time) { - vhpi_get_time(&time, NULL); - cb->data.time = &time; - } + c_callback *cb = is_callback(obj); + if (cb == NULL) + return; + + if (cb->State != vhpiEnable) + return; - vhpi_do_callback(cb); + (cb->data.cb_rtn)(&(cb->data)); } -} -static void vhpi_global_cb(rt_model_t *m, void *user) -{ - c_callback *cb; - if ((cb = is_callback(user))) - vhpi_do_callback(cb); + // The handle may be invalidated by the user call + + { + c_vhpiObject *obj = from_handle(handle); + if (obj == NULL) + return; + + c_callback *cb = is_callback(obj); + assert(cb != NULL); + + if (!vhpi_is_repetitive(cb->Reason)) { + cb->State = vhpiMature; + drop_handle(handle); + } + } } static rt_scope_t *vhpi_get_scope_abstractRegion(c_abstractRegion *region) @@ -1534,22 +1660,12 @@ int vhpi_release_handle(vhpiHandleT handle) VHPI_TRACE("handle=%s", handle_pp(handle)); c_vhpiObject *obj = from_handle(handle); - if (obj == NULL) + if (obj == NULL) { + vhpi_error(vhpiError, NULL, "invalid handle %p", handle); return 1; - - c_callback *cb = is_callback(obj); - if (cb != NULL) { - if (cb->status != CB_INACTIVE) - cb->status = CB_FREE_LATER; - else - free(cb); - return 0; } - c_iterator *it = is_iterator(obj); - if (it != NULL) - free(it); - + drop_handle(handle); return 0; } @@ -1570,12 +1686,12 @@ static int enable_cb(c_callback *cb) case vhpiCbStartOfNextCycle: case vhpiCbRepStartOfNextCycle: model_set_global_cb(vhpi_context()->model, vhpi_get_rt_event(cb->Reason), - vhpi_global_cb, cb); + vhpi_global_cb, handle_for(&(cb->object))); return 0; case vhpiCbAfterDelay: model_set_timeout_cb(vhpi_context()->model, cb->when, - vhpi_timeout_cb, cb); + vhpi_global_cb, handle_for(&(cb->object))); return 0; case vhpiCbValueChange: @@ -1592,8 +1708,9 @@ static int enable_cb(c_callback *cb) if (signal == NULL) return 1; - cb->w = model_set_event_cb(vhpi_context()->model, signal, - vhpi_signal_event_cb, cb, false); + vhpiHandleT handle = handle_for(&(cb->object)); + cb->watch = model_set_event_cb(vhpi_context()->model, signal, + vhpi_signal_event_cb, handle, false); return 0; } @@ -1641,7 +1758,7 @@ err: return NULL; } -static bool disable_cb(c_callback *cb) +static bool disable_cb(c_callback *cb, vhpiHandleT handle) { switch (cb->Reason) { case vhpiCbRepEndOfProcesses: @@ -1656,19 +1773,19 @@ static bool disable_cb(c_callback *cb) case vhpiCbRepEndOfTimeStep: return model_clear_global_cb(vhpi_context()->model, vhpi_get_rt_event(cb->Reason), - vhpi_global_cb, cb); - return true; + vhpi_global_cb, handle); case vhpiCbAfterDelay: return model_clear_timeout_cb(vhpi_context()->model, cb->when, - vhpi_timeout_cb, cb); + vhpi_global_cb, handle); case vhpiCbValueChange: - return model_clear_event_cb(vhpi_context()->model, cb->w); + return model_clear_event_cb(vhpi_context()->model, cb->watch); default: - assert(false); - return true; + vhpi_error(vhpiInternal, NULL, + "unsupported reason %d in vhpi_remove_cb", cb->Reason); + return 1; } } @@ -1687,14 +1804,12 @@ int vhpi_remove_cb(vhpiHandleT handle) if (cb == NULL) return 1; - VHPI_TRACE("cb.reason=%s", vhpi_cb_reason_str(cb->Reason)); + if (cb->State == vhpiEnable) + disable_cb(cb, handle); - if (cb->State != vhpiEnable || (disable_cb(cb) && cb->status == CB_INACTIVE)) - free(cb); - else { - cb->State = vhpiDisable; - cb->status = CB_FREE_LATER; - } + cb->State = vhpiMature; + + drop_handle(handle); return 0; } @@ -1713,15 +1828,13 @@ int vhpi_disable_cb(vhpiHandleT cb_obj) if (cb == NULL) return 1; - VHPI_TRACE("cb.reason=%s", vhpi_cb_reason_str(cb->Reason)); - if (cb->State != vhpiEnable) { vhpi_error(vhpiWarning, &(obj->loc), "callback must be enabled in order to disable it"); return 1; } - disable_cb(cb); + disable_cb(cb, cb_obj); cb->State = vhpiDisable; return 0; } @@ -1784,8 +1897,10 @@ vhpiHandleT vhpi_handle(vhpiOneToOneT type, vhpiHandleT referenceHandle) case vhpiBaseType: { c_typeDecl *td = is_typeDecl(obj); - if (td != NULL) - return handle_for(&(td->BaseType->decl.object)); + if (td != NULL) { + td = td->BaseType ?: td; + return handle_for(&(td->decl.object)); + } c_expr *e = is_expr(obj); if (e != NULL) { @@ -1832,8 +1947,10 @@ vhpiHandleT vhpi_handle(vhpiOneToOneT type, vhpiHandleT referenceHandle) return handle_for(&(iu->DesignUnit->object)); } + case vhpiPrimaryUnit: return handle_for(&(cast_secondaryUnit(obj)->PrimaryUnit->object)); + case vhpiPrefix: { c_prefixedName *pn = cast_prefixedName(obj); @@ -3715,12 +3832,40 @@ vhpi_context_t *vhpi_context_new(tree_t top, rt_model_t *model, jit_t *jit, return c; } +static void vhpi_check_leaks(vhpi_context_t *c) +{ + int nactive = 0; + for (int i = 0; i < c->num_handles; i++) { + if (c->handles[i].obj != NULL) + nactive++; + } + + if (nactive > 0) { + diag_t *d = diag_new(DIAG_WARN, NULL); + diag_printf(d, "VHPI program exited with %d active handles", + nactive); + + for (int i = 0; i < c->num_handles; i++) { + handle_slot_t *slot = &(c->handles[i]); + if (slot->obj != NULL) + diag_printf(d, "\n%s with %d references", + handle_pp(slot->obj->handle), slot->refcount); + } + + diag_emit(d); + } +} + void vhpi_context_free(vhpi_context_t *c) { + if (opt_get_int(OPT_VHPI_DEBUG)) + vhpi_check_leaks(c); + assert(c == global_context); global_context = NULL; shash_free(c->strtab); hash_free(c->objcache); + free(c->handles); free(c); } diff --git a/src/vhpi/vhpi-str.c b/src/vhpi/vhpi-str.c index f7f45707..713c4531 100644 --- a/src/vhpi/vhpi-str.c +++ b/src/vhpi/vhpi-str.c @@ -20,6 +20,13 @@ LCOV_EXCL_START +static const char *vhpi_fallback_str(int value) +{ + static char buf[16]; + checked_sprintf(buf, sizeof(buf), "%d", value); + return buf; +} + const char *vhpi_property_str(int property) { switch (property) { @@ -132,12 +139,7 @@ const char *vhpi_property_str(int property) case DEPRECATED_vhpiSimTimeUnitP: return "DEPRECATED_vhpiSimTimeUnitP"; case vhpiResolutionLimitP: return "vhpiResolutionLimitP"; case vhpiTimeP: return "vhpiTimeP"; - default: - { - static char buf[64]; - checked_sprintf(buf, sizeof(buf), "%d", property); - return buf; - } + default: return vhpi_fallback_str(property); } } @@ -268,12 +270,7 @@ const char *vhpi_class_str(vhpiClassKindT kind) case vhpiSeqSigAssignStmtK: return "vhpiSeqSigAssignStmtK"; case vhpiProtectedTypeInstK: return "vhpiProtectedTypeInstK"; case vhpiVerilogModuleK: return "vhpiVerilogModuleK"; - default: - { - static char buf[64]; - checked_sprintf(buf, sizeof(buf), "%d", kind); - return buf; - } + default: return vhpi_fallback_str(kind); } } @@ -371,12 +368,7 @@ const char *vhpi_one_to_one_str(vhpiOneToOneT kind) case vhpiCompDecl: return "vhpiCompDecl"; case vhpiProtectedTypeInst: return "vhpiProtectedTypeInst"; case vhpiGenIndex: return "vhpiGenIndex"; - default: - { - static char buf[64]; - checked_sprintf(buf, sizeof(buf), "%d", kind); - return buf; - } + default: return vhpi_fallback_str(kind); } } @@ -450,12 +442,7 @@ const char *vhpi_one_to_many_str(vhpiOneToManyT kind) case vhpiEqProcessStmts: return "vhpiEqProcessStmts"; case vhpiEntityClassEntries: return "vhpiEntityClassEntries"; case vhpiSensitivities: return "vhpiSensitivities"; - default: - { - static char buf[64]; - checked_sprintf(buf, sizeof(buf), "%d", kind); - return buf; - } + default: return vhpi_fallback_str(kind); } } @@ -511,12 +498,7 @@ const char *vhpi_cb_reason_str(int reason) case vhpiCbTimeOut: return "vhpiCbTimeOut"; case vhpiCbRepTimeOut: return "vhpiCbRepTimeOut"; case vhpiCbSensitivity: return "vhpiCbSensitivity"; - default: - { - static char buf[64]; - checked_sprintf(buf, sizeof(buf), "%d", reason); - return buf; - } + default: return vhpi_fallback_str(reason); } } @@ -529,12 +511,17 @@ const char *vhpi_put_value_mode_str(vhpiPutValueModeT mode) case vhpiForcePropagate: return "vhpiForcePropagate"; case vhpiRelease: return "vhpiRelease"; case vhpiSizeConstraint: return "vhpiSizeConstraint"; - default: - { - static char buf[64]; - checked_sprintf(buf, sizeof(buf), "%d", mode); - return buf; - } + default: return vhpi_fallback_str(mode); + } +} + +const char *vhpi_state_str(vhpiStateT state) +{ + switch (state) { + case vhpiEnable: return "vhpiEnable"; + case vhpiDisable: return "vhpiEnable"; + case vhpiMature: return "vhpiMature"; + default: return vhpi_fallback_str(state); } } diff --git a/src/vhpi/vhpi-util.h b/src/vhpi/vhpi-util.h index 98e5dbf0..11765d4d 100644 --- a/src/vhpi/vhpi-util.h +++ b/src/vhpi/vhpi-util.h @@ -57,5 +57,6 @@ const char *vhpi_one_to_one_str(vhpiOneToOneT kind); const char *vhpi_class_str(vhpiClassKindT kind); const char *vhpi_property_str(int property); const char *vhpi_put_value_mode_str(vhpiPutValueModeT mode); +const char *vhpi_state_str(vhpiStateT state); #endif // _VHPI_UTIL_H diff --git a/test/vhpi/vhpi1.c b/test/vhpi/vhpi1.c index 92c60e8f..56c0541f 100644 --- a/test/vhpi/vhpi1.c +++ b/test/vhpi/vhpi1.c @@ -299,6 +299,7 @@ static void after_5ns(const vhpiCbDataT *cb_data) cb = vhpi_register_cb(&cb_data5, vhpiReturnCb); check_error(); fail_if(vhpi_remove_cb(cb)); + vhpi_release_handle(cb); cb_data5.cb_rtn = mutual; cb_data5.user_data = mutual_cb3; @@ -407,7 +408,6 @@ static void end_of_init(const vhpiCbDataT *cb_data) vhpi_printf("arch name is %s", vhpi_get_str(vhpiNameP, arch)); vhpi_printf("arch unit name is %s", vhpi_get_str(vhpiUnitNameP, arch)); - vhpi_release_handle(arch); vhpiHandleT entity = vhpi_handle(vhpiPrimaryUnit, arch); check_error(); @@ -417,6 +417,7 @@ static void end_of_init(const vhpiCbDataT *cb_data) vhpi_printf("entity name is %s", vhpi_get_str(vhpiNameP, entity)); vhpi_printf("entity unit name is %s", vhpi_get_str(vhpiUnitNameP, entity)); vhpi_release_handle(entity); + vhpi_release_handle(arch); handle_x = vhpi_handle_by_name("x", root); check_error(); @@ -525,6 +526,11 @@ static void end_of_init(const vhpiCbDataT *cb_data) vhpi_printf("full case name is %s", vhpi_get_str(vhpiFullCaseNameP, handle_case)); vhpi_release_handle(root); + check_error(); + + // Releasing the handle twice should report an error + vhpi_release_handle(root); + fail_unless(vhpi_check_error(&info)); } void vhpi1_startup(void) diff --git a/test/vhpi/vhpi2.c b/test/vhpi/vhpi2.c index 4d2bec98..548b909f 100644 --- a/test/vhpi/vhpi2.c +++ b/test/vhpi/vhpi2.c @@ -7,7 +7,6 @@ static vhpiHandleT handle_x; static vhpiHandleT handle_y; -static vhpiHandleT handle_sos; static vhpiHandleT end_of_timestep_cb; static int sequence = 0; @@ -51,6 +50,7 @@ static void end_of_timestep(const vhpiCbDataT *cb_data) vhpi_remove_cb(end_of_timestep_cb); check_error(); + vhpi_release_handle(end_of_timestep_cb); } static void start_of_sim(const vhpiCbDataT *cb_data) @@ -80,7 +80,12 @@ static void start_of_sim(const vhpiCbDataT *cb_data) check_error(); fail_unless(vhpi_get(vhpiIsScalarP, y_type)); check_error(); + + vhpiHandleT y_base = vhpi_handle(vhpiBaseType, y_type); + fail_unless(vhpi_compare_handles(y_base, y_type)); + vhpi_release_handle(y_type); + vhpi_release_handle(y_base); vhpiValueT value = { .format = vhpiObjTypeVal @@ -127,7 +132,8 @@ void vhpi2_startup(void) .cb_rtn = start_of_sim, .user_data = (char *)"some user data", }; - handle_sos = vhpi_register_cb(&cb_data1, vhpiReturnCb); + vhpiHandleT handle_sos = vhpi_register_cb(&cb_data1, vhpiReturnCb); check_error(); fail_unless(vhpi_get(vhpiStateP, handle_sos) == vhpiEnable); + vhpi_release_handle(handle_sos); } diff --git a/test/vhpi/vhpi3.c b/test/vhpi/vhpi3.c index b6df2f52..98379841 100644 --- a/test/vhpi/vhpi3.c +++ b/test/vhpi/vhpi3.c @@ -7,7 +7,7 @@ static int64_t phys_to_i64(vhpiPhysT phys) { - return ((int64_t)phys.high) << 32 | phys.low; + return ((uint64_t)phys.high) << 32 | phys.low; } static void start_of_sim(const vhpiCbDataT *cb_data) @@ -71,6 +71,7 @@ static void start_of_sim(const vhpiCbDataT *cb_data) check_error(); fail_unless(phys_to_i64(weight_right) == 4000); + vhpi_release_handle(handle_weight_cons_iter); vhpi_release_handle(handle_weight_cons); vhpi_release_handle(handle_weight_type); vhpi_release_handle(handle_x); @@ -86,6 +87,6 @@ void vhpi3_startup(void) .cb_rtn = start_of_sim, .user_data = NULL, }; - (void)vhpi_register_cb(&cb_data1, vhpiReturnCb); + vhpi_register_cb(&cb_data1, 0); check_error(); } diff --git a/test/vhpi/vhpi5.c b/test/vhpi/vhpi5.c index bb891e7f..25fa2809 100644 --- a/test/vhpi/vhpi5.c +++ b/test/vhpi/vhpi5.c @@ -23,8 +23,11 @@ void delta_recursive(vhpiHandleT parent, int base, int scale) vhpiHandleT children = vhpi_iterator(vhpiSelectedNames, parent); for (vhpiHandleT child = vhpi_scan(children); child; - child = vhpi_scan(children), i++) + child = vhpi_scan(children), i++) { delta_recursive(child, base + i * scale, scale / 16); + vhpi_release_handle(child); + } + vhpi_release_handle(children); children = vhpi_iterator(vhpiIndexedNames, parent); for (vhpiHandleT child = vhpi_scan(children); @@ -35,7 +38,9 @@ void delta_recursive(vhpiHandleT parent, int base, int scale) scale / 256); else delta_recursive(child, base + i * scale, scale / 16); + vhpi_release_handle(child); } + vhpi_release_handle(children); if (!i) { vhpiValueT val = { @@ -75,11 +80,19 @@ void start_recursive(vhpiHandleT parent, int base, int scale, bool by_name) snprintf(name, sizeof(name), "%s.%s", parent_name, vhpi_get_str(vhpiNameP, suffix)); fail_if(strcmp(name, (char *)vhpi_get_str(vhpiNameP, child))); - if (by_name) - fail_unless(vhpi_handle_by_name(name, NULL) == child); + if (by_name) { + vhpiHandleT child2 = vhpi_handle_by_name(name, NULL); + fail_unless(child2 == child); + vhpi_release_handle(child2); + } start_recursive(child, base + i * scale, scale / 16, by_name); + + vhpi_release_handle(prefix); + vhpi_release_handle(suffix); + vhpi_release_handle(child); } + vhpi_release_handle(children); children = vhpi_iterator(vhpiIndexedNames, parent); for (vhpiHandleT child = vhpi_scan(children); @@ -90,7 +103,9 @@ void start_recursive(vhpiHandleT parent, int base, int scale, bool by_name) scale / 256, false); else start_recursive(child, base + i * scale, scale / 16, false); + vhpi_release_handle(child); } + vhpi_release_handle(children); if (!i) { vhpiValueT val = { @@ -136,7 +151,9 @@ static void start_of_sim(const vhpiCbDataT *cb_data) for (vhpiHandleT elem = vhpi_scan(elems); elem; elem = vhpi_scan(elems), i++) { vhpi_printf("m elem %d is %s", i, vhpi_get_str(vhpiNameP, elem)); fail_unless(vhpi_get(vhpiPositionP, elem) == i); + vhpi_release_handle(elem); } + vhpi_release_handle(elems); fail_unless(vhpi_get(vhpiNumFieldsP, m_type) == i); n = vhpi_handle_by_name("n", root); diff --git a/tools/run.sh b/tools/run.sh index 8f556a46..4ebcbeca 100755 --- a/tools/run.sh +++ b/tools/run.sh @@ -1,5 +1,5 @@ #!/bin/sh -std=${STD:-02} +std=${STD:-08} export NVC_LIBPATH=./lib/ export NVC_IMP_LIB=./lib/ root=$(git rev-parse --show-toplevel) -- 2.39.2