<HTML><BODY><div class="cl-mnsuhy9gzi"><div>Hi, Sergey! Thanks for the patch!</div><div> </div><div>LGTM<br> </div><div data-signature-widget="container"><div data-signature-widget="content"><div>--<br>Best regards,</div><div>Evgeniy Temirgaleev</div></div></div><br><div class="mail-quote-collapse"><blockquote style="border-left:1px solid #0857A6;margin:10px;padding:0 0 0 10px"><span>From: Sergey Kaplun <<a href="mailto:skaplun@tarantool.org">skaplun@tarantool.org</a>><br>To: Sergey Bronnikov <<a href="mailto:sergeyb@tarantool.org">sergeyb@tarantool.org</a>>, Evgeniy Temirgaleev <<a href="mailto:e.temirgaleev@tarantool.org">e.temirgaleev@tarantool.org</a>><br>Cc: tarantool-patches@dev.tarantool.org, Sergey Kaplun <<a href="mailto:skaplun@tarantool.org">skaplun@tarantool.org</a>><br>Date: Wednesday, July 22, 2026 5:00 PM +03:00</span><br> <div><div id=""><div class="cl-qsmcos12hs"><div class="js-helper_mr_css_attr js-readmsg-msg_mr_css_attr"><div id="style_17847288581760086382_mr_css_attr"><div id="style_17847288581760086382_BODY_mr_css_attr">This patch is a follow-up to the commit<br>7058e9215f8a50d00701302ecbb510503d21148d ("utils: introduce leb128<br>reader and writer").<br><br>The leb128 encoding is used inside our profilers (memprof/sysprof). But<br>there are no tests for this module, so its coverage is low, since only<br>`lj_utils_write_uleb128()` is used. Also, there is no correctness check<br>for this implementation.<br><br>This patch adapts the LuaVela tests [1] to cover this module. Since the<br>initial version of the module wasn't adapted as is, the guarded version<br>of the reader functions has different behaviour for zero-sized requested<br>reads. Hence, this case is removed for now. The readers with a requested<br>size are unused in our code, so this is not crucial at the moment.<br><br>Also, this patch fixes the UBSan warning in the<br>`lj_utils_write_leb128()` on checking the remaining value to be written<br>by fixing the cast to uint64_t.<br><br>[1]: <a href="https://github.com/luavela/luavela/blob/288e8a95218ed47dad93016259533406e30b109b/tests/impl/uJIT-tests-C/suite/test_leb128.c">https://github.com/luavela/luavela/blob/288e8a95218ed47dad93016259533406e30b109b/tests/impl/uJIT-tests-C/suite/test_leb128.c</a><br>---<br><br>The main idea of the patch is to increase coverage for the<br>lj_utils_leb128.c. The UBSan "bug" (not really, since this part is<br>unused, anyway) is fixed as a side effect. You may compare the coverage<br>between master [1] and this branch [2] with coveralls.<br><br>Branch: <a href="https://github.com/tarantool/luajit/tree/skaplun/gh-noticket-leb128-testsing">https://github.com/tarantool/luajit/tree/skaplun/gh-noticket-leb128-testsing</a><br><br>[1]: <a href="https://coveralls.io/builds/80394140/source?filename=src%2Flj_utils_leb128.c">https://coveralls.io/builds/80394140/source?filename=src%2Flj_utils_leb128.c</a><br>[2]: <a href="https://coveralls.io/builds/80728053/source?filename=src%2Flj_utils_leb128.c">https://coveralls.io/builds/80728053/source?filename=src%2Flj_utils_leb128.c</a><br><br>src/lj_utils_leb128.c | 2 +-<br>test/tarantool-c-tests/unit-leb128.test.c | 366 ++++++++++++++++++++++<br>2 files changed, 367 insertions(+), 1 deletion(-)<br>create mode 100644 test/tarantool-c-tests/unit-leb128.test.c<br><br>diff --git a/src/lj_utils_leb128.c b/src/lj_utils_leb128.c<br>index d66961da..5ad2bd3c 100644<br>--- a/src/lj_utils_leb128.c<br>+++ b/src/lj_utils_leb128.c<br>@@ -105,7 +105,7 @@ size_t LJ_FASTCALL lj_utils_write_leb128(uint8_t *buffer, int64_t value)<br>size_t i = 0;<br><br>/* LEB_SIGN_BIT propagation to check the remaining value. */<br>- while ((uint64_t)(value + LEB_SIGN_BIT) >= MIN_TWOBYTE_VALUE) {<br>+ while ((uint64_t)value + LEB_SIGN_BIT >= MIN_TWOBYTE_VALUE) {<br>buffer[i++] = (uint8_t)((value & PAYLOAD_MASK) | LINK_BIT);<br>value >>= SHIFT_STEP;<br>}<br>diff --git a/test/tarantool-c-tests/unit-leb128.test.c b/test/tarantool-c-tests/unit-leb128.test.c<br>new file mode 100644<br>index 00000000..142476fb<br>--- /dev/null<br>+++ b/test/tarantool-c-tests/unit-leb128.test.c<br>@@ -0,0 +1,366 @@<br>+/*<br>+** Testing of LEB128/ULEB128 encoding.<br>+**<br>+** Major portions taken verbatim or adapted from the LuaVela.<br>+** Copyright (C) 2020-2026 LuaVela Authors.<br>+** Copyright (C) 2015-2020 IPONWEB Ltd.<br>+*/<br>+<br>+#include <stdint.h><br>+#include <string.h><br>+<br>+#include "test.h"<br>+<br>+#include "lj_utils.h"<br>+<br>+#define BUFFER_SIZE 16<br>+<br>+static int test_write_uleb128(void *state)<br>+{<br>+ size_t bytes_written = 0;<br>+ uint8_t buffer[BUFFER_SIZE] = {0};<br>+<br>+ UNUSED(state);<br>+<br>+ bytes_written = lj_utils_write_uleb128(buffer, 0);<br>+ assert_true(bytes_written == 1);<br>+ assert_true(buffer[0] == 0x0);<br>+<br>+ bytes_written = lj_utils_write_uleb128(buffer, 64);<br>+ assert_true(bytes_written == 1);<br>+ assert_true(buffer[0] == 0x40);<br>+<br>+ bytes_written = lj_utils_write_uleb128(buffer, 128);<br>+ assert_true(bytes_written == 2);<br>+ assert_true(buffer[0] == 0x80 && buffer[1] == 0x01);<br>+<br>+ bytes_written = lj_utils_write_uleb128(buffer, UINT64_MAX);<br>+ assert_true(bytes_written == 10);<br>+ assert_true(buffer[0] == 0xff && buffer[1] == 0xff &&<br>+ buffer[2] == 0xff && buffer[3] == 0xff &&<br>+ buffer[4] == 0xff && buffer[5] == 0xff &&<br>+ buffer[6] == 0xff && buffer[7] == 0xff &&<br>+ buffer[8] == 0xff && buffer[9] == 0x01);<br>+<br>+ return TEST_EXIT_SUCCESS;<br>+}<br>+<br>+static int test_write_leb128(void *state)<br>+{<br>+ size_t bytes_written = 0;<br>+ uint8_t buffer[BUFFER_SIZE] = {0};<br>+<br>+ UNUSED(state);<br>+<br>+ bytes_written = lj_utils_write_leb128(buffer, 0);<br>+ assert_true(bytes_written == 1);<br>+ assert_true(buffer[0] == 0x0);<br>+<br>+ bytes_written = lj_utils_write_leb128(buffer, -624485);<br>+ assert_true(bytes_written == 3);<br>+ assert_true(buffer[0] == 0x9b && buffer[1] == 0xf1 &&<br>+ buffer[2] == 0x59);<br>+<br>+ bytes_written = lj_utils_write_leb128(buffer, INT64_MIN);<br>+ assert_true(bytes_written == 10);<br>+ assert_true(buffer[0] == 0x80 && buffer[1] == 0x80 &&<br>+ buffer[2] == 0x80 && buffer[3] == 0x80 &&<br>+ buffer[4] == 0x80 && buffer[5] == 0x80 &&<br>+ buffer[6] == 0x80 && buffer[7] == 0x80 &&<br>+ buffer[8] == 0x80 && buffer[9] == 0x7f);<br>+<br>+ bytes_written = lj_utils_write_leb128(buffer, INT64_MAX);<br>+ assert_true(bytes_written == 10);<br>+ assert_true(buffer[0] == 0xff && buffer[1] == 0xff &&<br>+ buffer[2] == 0xff && buffer[3] == 0xff &&<br>+ buffer[4] == 0xff && buffer[5] == 0xff &&<br>+ buffer[6] == 0xff && buffer[7] == 0xff &&<br>+ buffer[8] == 0xff && buffer[9] == 0x00);<br>+<br>+ return TEST_EXIT_SUCCESS;<br>+}<br>+<br>+/* Test miscellaneous writes, both signed and unsigned. */<br>+static int test_misc_writes(void *state)<br>+{<br>+ size_t bytes_written = 0;<br>+ uint8_t buffer[BUFFER_SIZE] = {0};<br>+<br>+ UNUSED(state);<br>+<br>+ bytes_written = lj_utils_write_leb128(buffer, 0x10);<br>+ assert_true(bytes_written == 1);<br>+ assert_true(buffer[0] == 0x10);<br>+<br>+ bytes_written = lj_utils_write_uleb128(buffer, 0x10);<br>+ assert_true(bytes_written == 1);<br>+ assert_true(buffer[0] == 0x10);<br>+<br>+ bytes_written = lj_utils_write_leb128(buffer, -0x3b);<br>+ assert_true(bytes_written == 1);<br>+ assert_true(buffer[0] == 0x45);<br>+<br>+ bytes_written = lj_utils_write_uleb128(buffer, 0x45);<br>+ assert_true(bytes_written == 1);<br>+ assert_true(buffer[0] == 0x45);<br>+<br>+ bytes_written = lj_utils_write_leb128(buffer, 0x190e);<br>+ assert_true(bytes_written == 2);<br>+ assert_true(buffer[0] == 0x8e && buffer[1] == 0x32);<br>+<br>+ bytes_written = lj_utils_write_uleb128(buffer, 0x190e);<br>+ assert_true(bytes_written == 2);<br>+ assert_true(buffer[0] == 0x8e && buffer[1] == 0x32);<br>+<br>+ bytes_written = lj_utils_write_leb128(buffer, -0x143f);<br>+ assert_true(bytes_written == 2);<br>+ assert_true(buffer[0] == 0xc1 && buffer[1] == 0x57);<br>+<br>+ bytes_written = lj_utils_write_uleb128(buffer, 0x2bc1);<br>+ assert_true(bytes_written == 2);<br>+ assert_true(buffer[0] == 0xc1 && buffer[1] == 0x57);<br>+<br>+ bytes_written = lj_utils_write_leb128(buffer, 0x7e00000);<br>+ assert_true(bytes_written == 4);<br>+ assert_true(buffer[0] == 0x80 && buffer[1] == 0x80 &&<br>+ buffer[2] == 0x80 && buffer[3] == 0x3f);<br>+<br>+ bytes_written = lj_utils_write_uleb128(buffer, 0x7e00000);<br>+ assert_true(bytes_written == 4);<br>+ assert_true(buffer[0] == 0x80 && buffer[1] == 0x80 &&<br>+ buffer[2] == 0x80 && buffer[3] == 0x3f);<br>+<br>+ bytes_written = lj_utils_write_leb128(buffer, -0x6200000);<br>+ assert_true(bytes_written == 4);<br>+ assert_true(buffer[0] == 0x80 && buffer[1] == 0x80 &&<br>+ buffer[2] == 0x80 && buffer[3] == 0x4f);<br>+<br>+ bytes_written = lj_utils_write_uleb128(buffer, 0x9e00000);<br>+ assert_true(bytes_written == 4);<br>+ assert_true(buffer[0] == 0x80 && buffer[1] == 0x80 &&<br>+ buffer[2] == 0x80 && buffer[3] == 0x4f);<br>+<br>+ return TEST_EXIT_SUCCESS;<br>+}<br>+<br>+static int test_read_uleb128(void *state)<br>+{<br>+ uint64_t value = 0;<br>+ size_t bytes_read = 0;<br>+ uint8_t buffer[BUFFER_SIZE] = {0};<br>+<br>+ UNUSED(state);<br>+<br>+ bytes_read = lj_utils_read_uleb128(&value, buffer);<br>+ assert_true(bytes_read == 1);<br>+ assert_true(value == 0);<br>+<br>+ buffer[0] = 0x40;<br>+ bytes_read = lj_utils_read_uleb128(&value, buffer);<br>+ assert_true(bytes_read == 1);<br>+ assert_true(value == 64);<br>+<br>+ buffer[0] = 0x80;<br>+ buffer[1] = 0x01;<br>+ bytes_read = lj_utils_read_uleb128(&value, buffer);<br>+ assert_true(bytes_read == 2);<br>+ assert_true(value == 128);<br>+<br>+ memset(buffer, 0xff, 9);<br>+ buffer[9] = 0x01;<br>+ bytes_read = lj_utils_read_uleb128(&value, buffer);<br>+ assert_true(bytes_read == 10);<br>+ assert_true(value == UINT64_MAX);<br>+<br>+ return TEST_EXIT_SUCCESS;<br>+}<br>+<br>+static int test_read_leb128(void *state)<br>+{<br>+ int64_t value = 0;<br>+ size_t bytes_read = 0;<br>+ uint8_t buffer[BUFFER_SIZE] = {0};<br>+<br>+ UNUSED(state);<br>+<br>+ bytes_read = lj_utils_read_leb128(&value, buffer);<br>+ assert_true(bytes_read == 1);<br>+ assert_true(value == 0);<br>+<br>+ buffer[0] = 0x9b;<br>+ buffer[1] = 0xf1;<br>+ buffer[2] = 0x59;<br>+ bytes_read = lj_utils_read_leb128(&value, buffer);<br>+ assert_true(bytes_read == 3);<br>+ assert_true(value == (int64_t)-624485);<br>+<br>+ memset(buffer, 0x80, 9);<br>+ buffer[9] = 0x7f;<br>+ bytes_read = lj_utils_read_leb128(&value, buffer);<br>+ assert_true(bytes_read == 10);<br>+ assert_true(value == INT64_MIN);<br>+<br>+ memset(buffer, 0xff, 9);<br>+ buffer[9] = 0x00;<br>+ bytes_read = lj_utils_read_leb128(&value, buffer);<br>+ assert_true(bytes_read == 10);<br>+ assert_true(value == INT64_MAX);<br>+<br>+ return TEST_EXIT_SUCCESS;<br>+}<br>+<br>+/* Test miscellaneous reads, both signed and unsigned. */<br>+static int test_misc_reads(void *state)<br>+{<br>+ int64_t i_value = 0;<br>+ uint64_t u_value = 0;<br>+<br>+ size_t bytes_read = 0;<br>+ uint8_t buffer[BUFFER_SIZE] = {0};<br>+<br>+ UNUSED(state);<br>+<br>+ buffer[0] = 0x10;<br>+<br>+ bytes_read = lj_utils_read_leb128(&i_value, buffer);<br>+ assert_true(bytes_read == 1);<br>+ assert_true(i_value == (int64_t)0x10);<br>+<br>+ bytes_read = lj_utils_read_uleb128(&u_value, buffer);<br>+ assert_true(bytes_read == 1);<br>+ assert_true(u_value == (uint64_t)0x10);<br>+<br>+ buffer[0] = 0x45;<br>+<br>+ bytes_read = lj_utils_read_leb128(&i_value, buffer);<br>+ assert_true(bytes_read == 1);<br>+ assert_true(i_value == (int64_t)-0x3b);<br>+<br>+ bytes_read = lj_utils_read_uleb128(&u_value, buffer);<br>+ assert_true(bytes_read == 1);<br>+ assert_true(u_value == (uint64_t)0x45);<br>+<br>+ buffer[0] = 0x8e;<br>+ buffer[1] = 0x32;<br>+<br>+ bytes_read = lj_utils_read_leb128(&i_value, buffer);<br>+ assert_true(bytes_read == 2);<br>+ assert_true(i_value == (int64_t)0x190e);<br>+<br>+ bytes_read = lj_utils_read_uleb128(&u_value, buffer);<br>+ assert_true(bytes_read == 2);<br>+ assert_true(u_value == (uint64_t)0x190e);<br>+<br>+ buffer[0] = 0xc1;<br>+ buffer[1] = 0x57;<br>+<br>+ bytes_read = lj_utils_read_leb128(&i_value, buffer);<br>+ assert_true(bytes_read == 2);<br>+ assert_true(i_value == (int64_t)-0x143f);<br>+<br>+ bytes_read = lj_utils_read_uleb128(&u_value, buffer);<br>+ assert_true(bytes_read == 2);<br>+ assert_true(u_value == (uint64_t)0x2bc1);<br>+<br>+ buffer[0] = 0xc1;<br>+ buffer[1] = 0x57;<br>+<br>+ bytes_read = lj_utils_read_leb128(&i_value, buffer);<br>+ assert_true(bytes_read == 2);<br>+ assert_true(i_value == (int64_t)-0x143f);<br>+<br>+ bytes_read = lj_utils_read_uleb128(&u_value, buffer);<br>+ assert_true(bytes_read == 2);<br>+ assert_true(u_value == (uint64_t)0x2bc1);<br>+<br>+ buffer[0] = 0x80;<br>+ buffer[1] = 0x80;<br>+ buffer[2] = 0x80;<br>+ buffer[3] = 0x3f;<br>+<br>+ bytes_read = lj_utils_read_leb128(&i_value, buffer);<br>+ assert_true(bytes_read == 4);<br>+ assert_true(i_value == (int64_t)0x7e00000);<br>+<br>+ bytes_read = lj_utils_read_uleb128(&u_value, buffer);<br>+ assert_true(bytes_read == 4);<br>+ assert_true(u_value == (uint64_t)0x7e00000);<br>+<br>+ buffer[0] = 0x80;<br>+ buffer[1] = 0x80;<br>+ buffer[2] = 0x80;<br>+ buffer[3] = 0x4f;<br>+<br>+ bytes_read = lj_utils_read_leb128(&i_value, buffer);<br>+ assert_true(bytes_read == 4);<br>+ assert_true(i_value == (int64_t)-0x6200000);<br>+<br>+ bytes_read = lj_utils_read_uleb128(&u_value, buffer);<br>+ assert_true(bytes_read == 4);<br>+ assert_true(u_value == (uint64_t)0x9e00000);<br>+<br>+ return TEST_EXIT_SUCCESS;<br>+}<br>+<br>+static int test_read_n(void *state)<br>+{<br>+ int64_t i_value = 0;<br>+ uint64_t u_value = 0;<br>+<br>+ size_t bytes_read = 0;<br>+ uint8_t buffer[BUFFER_SIZE] = {0};<br>+<br>+ UNUSED(state);<br>+<br>+ bytes_read = lj_utils_read_leb128_n(&i_value, buffer, 1);<br>+ assert_true(bytes_read == 1);<br>+ assert_true(i_value == 0);<br>+<br>+ bytes_read = lj_utils_read_uleb128_n(&u_value, buffer, 1);<br>+ assert_true(bytes_read == 1);<br>+ assert_true(u_value == 0);<br>+<br>+ buffer[0] = 0x80;<br>+ buffer[1] = 0x80;<br>+ buffer[2] = 0x80;<br>+ buffer[3] = 0x3f;<br>+<br>+ assert_true(lj_utils_read_leb128_n(&i_value, buffer, 3) == 0);<br>+ assert_true(lj_utils_read_uleb128_n(&u_value, buffer, 3) == 0);<br>+ /* Values are untouched in case of failure. */<br>+ assert_true(i_value == 0);<br>+ assert_true(u_value == 0);<br>+<br>+ bytes_read = lj_utils_read_leb128_n(&i_value, buffer, 4);<br>+ assert_true(bytes_read == 4);<br>+ assert_true(i_value == (int64_t)0x7e00000);<br>+<br>+ bytes_read = lj_utils_read_uleb128_n(&u_value, buffer, 4);<br>+ assert_true(bytes_read == 4);<br>+ assert_true(u_value == (uint64_t)0x7e00000);<br>+<br>+ bytes_read = lj_utils_read_leb128_n(&i_value, buffer, 5);<br>+ assert_true(bytes_read == 4);<br>+ assert_true(i_value == (int64_t)0x7e00000);<br>+<br>+ bytes_read = lj_utils_read_uleb128_n(&u_value, buffer, 5);<br>+ assert_true(bytes_read == 4);<br>+ assert_true(u_value == (uint64_t)0x7e00000);<br>+<br>+ return TEST_EXIT_SUCCESS;<br>+}<br>+<br>+int main(void)<br>+{<br>+ const struct test_unit tgroup[] = {<br>+ test_unit_def(test_write_uleb128),<br>+ test_unit_def(test_write_leb128),<br>+ test_unit_def(test_misc_writes),<br>+ test_unit_def(test_read_uleb128),<br>+ test_unit_def(test_read_leb128),<br>+ test_unit_def(test_misc_reads),<br>+ test_unit_def(test_read_n),<br>+ };<br>+ const int test_result = test_run_group(tgroup, NULL);<br>+ return test_result;<br>+}<br>--<br>2.55.0</div></div></div></div></div></div></blockquote></div></div></BODY></HTML>