From ff4d6608c0fe8d118b36788b47b981082c597bfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Fri, 3 Jul 2026 17:31:30 +0200 Subject: [PATCH] Add rz_bv_append_inplace() (#6592) Warning: this also swaps the arguments of the old rz_bv_append() to be consistend with the new inplace variant. The reason why the inplace function has the low as the first operand is that it can be more efficient to append to an existing vector inplace than to prepend to it. Then, the first argument is being used as the in-out one in all other inplace functions. --- librz/il/theory_bitv.c | 2 +- librz/include/rz_util/rz_bitvector.h | 3 ++- librz/util/bitvector.c | 20 ++++++++++++++++---- test/unit/test_bitvector.c | 8 +++++++- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/librz/il/theory_bitv.c b/librz/il/theory_bitv.c index c780479a89..17106c75b3 100644 --- a/librz/il/theory_bitv.c +++ b/librz/il/theory_bitv.c @@ -134,7 +134,7 @@ void *rz_il_handler_append(RzILVM *vm, RzILOpBitVector *op, RzILTypePure *type) RzBitVector *high = rz_il_evaluate_bitv(vm, op_append->high); RzBitVector *low = rz_il_evaluate_bitv(vm, op_append->low); - RzBitVector *result = high && low ? rz_bv_append(high, low) : NULL; + RzBitVector *result = high && low ? rz_bv_append(low, high) : NULL; rz_bv_free(low); rz_bv_free(high); diff --git a/librz/include/rz_util/rz_bitvector.h b/librz/include/rz_util/rz_bitvector.h index a6ddd365e5..3fb5aba0d5 100644 --- a/librz/include/rz_util/rz_bitvector.h +++ b/librz/include/rz_util/rz_bitvector.h @@ -40,7 +40,8 @@ typedef struct bitvector_t { RZ_API bool rz_bv_init(RZ_NONNULL RzBitVector *bv, ut32 length); RZ_API RZ_OWN RzBitVector *rz_bv_new(ut32 length); RZ_API RZ_OWN RzBitVector *rz_bv_dup(const RZ_NONNULL RzBitVector *bv); -RZ_API RZ_OWN RzBitVector *rz_bv_append(RZ_NONNULL RzBitVector *bv1, RZ_NONNULL RzBitVector *bv2); +RZ_API RZ_OWN RzBitVector *rz_bv_append(RZ_NONNULL const RzBitVector *low, RZ_NONNULL const RzBitVector *high); +RZ_API void rz_bv_append_inplace(RZ_INOUT RZ_NONNULL RzBitVector *low, RZ_NONNULL const RzBitVector *high); RZ_API ut32 rz_bv_copy(RZ_NONNULL RzBitVector *dst, RZ_NONNULL const RzBitVector *src); RZ_API ut32 rz_bv_copy_nbits( RZ_NONNULL RzBitVector *dst, ut32 dst_start_pos, diff --git a/librz/util/bitvector.c b/librz/util/bitvector.c index b50bd2a69e..bed7ec5194 100644 --- a/librz/util/bitvector.c +++ b/librz/util/bitvector.c @@ -601,19 +601,31 @@ RZ_API RZ_OWN RzBitVector *rz_bv_cut_tail(RZ_NONNULL RzBitVector *bv, ut32 delta } /** - * Append bv2 to bv1 to get new bitvector - * \param high bitvector to occupy the most significant part of the result + * Append high to low to get new bitvector * \param low bitvector to occupy the least significant part of the result + * \param high bitvector to occupy the most significant part of the result * \return ret RzBitVector, the new bitvector */ -RZ_API RZ_OWN RzBitVector *rz_bv_append(RZ_NONNULL RzBitVector *high, RZ_NONNULL RzBitVector *low) { - rz_return_val_if_fail(high && low, NULL); +RZ_API RZ_OWN RzBitVector *rz_bv_append(RZ_NONNULL const RzBitVector *low, RZ_NONNULL const RzBitVector *high) { + rz_return_val_if_fail(low && high, NULL); RzBitVector *ret = rz_bv_new(high->len + low->len); rz_bv_copy_nbits(ret, 0, low, 0, low->len); rz_bv_copy_nbits(ret, low->len, high, 0, high->len); return ret; } +/** + * Append high to low to get new bitvector + * \param low bitvector to occupy the least significant part of the result, and pointer to write the result to + * \param high bitvector to occupy the most significant part of the result + */ +RZ_API void rz_bv_append_inplace(RZ_INOUT RZ_NONNULL RzBitVector *low, RZ_NONNULL const RzBitVector *high) { + rz_return_if_fail(low && low); + ut32 low_len = low->len; + rz_bv_cast_inplace(low, low->len + high->len, false); + rz_bv_copy_nbits(low, low_len, high, 0, high->len); +} + /** * Set a bit at position to true or false * \param bv RzBitVector, pointer to bv diff --git a/test/unit/test_bitvector.c b/test/unit/test_bitvector.c index bc6a589772..793d188cfb 100644 --- a/test/unit/test_bitvector.c +++ b/test/unit/test_bitvector.c @@ -724,7 +724,7 @@ bool test_rz_bv_operation(void) { mu_assert_streq_free(s, "0x0", "string hex value of bv"); rz_bv_free(res); - res = rz_bv_append(x, y); + res = rz_bv_append(y, x); mu_assert("append x and y", is_equal_bv(res, concat)); s = rz_bv_as_string(res); mu_assert_streq_free(s, "000010001011", "string bit value of bv"); @@ -732,6 +732,12 @@ bool test_rz_bv_operation(void) { mu_assert_streq_free(s, "0x08b", "string hex value of bv"); rz_bv_free(res); + res = rz_bv_new_from_ut64(4, 0x5); + rz_bv_append_inplace(res, x); + s = rz_bv_as_hex_string(res, true); + mu_assert_streq_free(s, "0x085", "string hex value of bv"); + rz_bv_free(res); + rz_bv_free(prep); rz_bv_free(append); rz_bv_free(cut_h);