From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from [87.239.111.99] (localhost [127.0.0.1]) by dev.tarantool.org (Postfix) with ESMTP id EA0A86ECCD; Wed, 22 Jul 2026 17:01:00 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org EA0A86ECCD DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1784728861; bh=j/b+HQ+sLwu1qLQ7cU3VFBl0u1E9gWNo5sS8x7RgPk0=; h=To:Date:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:Cc:From; b=NlQ+iiiKCVsnsewvmlY0qqG/0MxhngCi3sTr+dQLkkx2oRDdXsLh9vlAdspLjiXES NSmYVGAylKpox8dEi/8ya/c/UHFeoJShkrg93I1SYVWAPELO7ycBujS3ku8U+eCjXL No7grYGLfOyy4OLLIA0SOpxMtqQduWnaD+G+i7ZA= Received: from send129.i.mail.ru (send129.i.mail.ru [89.221.237.224]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 24DCC6ECCD for ; Wed, 22 Jul 2026 17:00:59 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 24DCC6ECCD Received: by exim-smtp-86556fd747-2df77 with esmtpa (envelope-from ) id 1wmXVJ-00000000JBn-3WKo; Wed, 22 Jul 2026 17:00:58 +0300 To: Sergey Bronnikov , Evgeniy Temirgaleev Date: Wed, 22 Jul 2026 17:00:36 +0300 Message-ID: <20260722140036.3606677-1-skaplun@tarantool.org> X-Mailer: git-send-email 2.55.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Mailru-Src: smtp X-7564579A: 646B95376F6C166E X-77F55803: 4F1203BC0FB41BD93ED3C6BF6FFA701F0B3D367FDA022B56BB42D82DE118CAD0182A05F538085040E68580A6C7BBC0BD3DE06ABAFEAF670518469F04BE15F86E95D65BD7C4D8B004E49391A50CB82CE1 X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE7A8325FA649D0A450EA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F7900637F88016AB904663428638F802B75D45FF914D58D5BE9E6BC1A93B80C6DEB9DEE97C6FB206A91F05B287346D580F2A3ABB2E070BE324C7D3C4349EB2325F54D101F6B57BC7E64490618DEB871D839B73339E8FC8737B5C2249E232F00D8D26902CA471835C12D1D9774AD6D5ED66289B52BA9C0B312567BB23117882F446042972877693876707352033AC447995A7AD18E5D25F19253116ADD2E47CDBA5A96583BA9C0B312567BB2376E601842F6C81A19E625A9149C048EE0AC5B80A05675ACD043FB282AF95FB6BD8FC6C240DEA76429C9F4D5AE37F343AA9539A8B242431040A6AB1C7CE11FEE3E3786DD2C77EBDAA6136E347CC761E07C4224003CC836476E2F48590F00D11D6E2021AF6380DFAD1A18204E546F3947C2FFDA4F57982C5F42E808ACE2090B5E1725E5C173C3A84C3C5EA940A35A165FF2DBA43225CD8A89F0A35B161A8BF67C1CE5475246E174218B5C8C57E37DE458BEDA766A37F9254B7 X-C1DE0DAB: 0D63561A33F958A53AD30FFC7E9C13865002B1117B3ED69609ED1D5E3F4E60C59E040399BDE4761E823CB91A9FED034534781492E4B8EEAD03B4017E30074F69C79554A2A72441328621D336A7BC284946AD531847A6065A535571D14F44ED41 X-C8649E89: 1C3962B70DF3F0AD73CAD6646DEDE191716CD42B3DD1D34C77DD89D51EBB774225B6776AC983F447FC0B9F89525902EE6F57B2FD27647F25E66C117BDB76D6592DEE446C99992F6A86EB02824B660731DDFA29138815CF0DAC469820EDADAA12D679041485F9E7BDB8341EE9D5BE9A0ACEDCBD67E1412AD84775A29CDFD8D024D8445E345E954E2FC7CEAA0681F5848F4C41F94D744909CECFA6C6B0C050A61A8CAF69B82BA93681CD72808BE417F3B9E0E7457915DAA85F X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu53w8ahmwBjZKM/YPHZyZHvz5uv+WouB9+ObcCpyrx6l7KImUglyhkEat/+ysWwi0gdhEs0JGjl6ggRWTy1haxBpVdbIX1nthFXMZebaIdHP2ghjoIc/363UZI6Kf1ptIMVWmxowtcrDwUpmRqe6fv8II= X-Mailru-Sender: 520A125C2F17F0B17094CDC02B85F11B044D0CDEFE8604F93DE06ABAFEAF670518469F04BE15F86EB7CBEF92542CD7C88B0A2698F12F5C9EC77752E0C033A69E86920BD37369036789A8C6A0E60D2BB63A5DB60FBEB33A8A0DA7A0AF5A3A8387 X-Mras: Ok Subject: [Tarantool-patches] [PATCH luajit] test: add tests for the leb128 encode/decode X-BeenThere: tarantool-patches@dev.tarantool.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Sergey Kaplun via Tarantool-patches Reply-To: Sergey Kaplun Cc: tarantool-patches@dev.tarantool.org Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" This patch is a follow-up to the commit 7058e9215f8a50d00701302ecbb510503d21148d ("utils: introduce leb128 reader and writer"). The leb128 encoding is used inside our profilers (memprof/sysprof). But there are no tests for this module, so its coverage is low, since only `lj_utils_write_uleb128()` is used. Also, there is no correctness check for this implementation. This patch adapts the LuaVela tests [1] to cover this module. Since the initial version of the module wasn't adapted as is, the guarded version of the reader functions has different behaviour for zero-sized requested reads. Hence, this case is removed for now. The readers with a requested size are unused in our code, so this is not crucial at the moment. Also, this patch fixes the UBSan warning in the `lj_utils_write_leb128()` on checking the remaining value to be written by fixing the cast to uint64_t. [1]: https://github.com/luavela/luavela/blob/288e8a95218ed47dad93016259533406e30b109b/tests/impl/uJIT-tests-C/suite/test_leb128.c --- The main idea of the patch is to increase coverage for the lj_utils_leb128.c. The UBSan "bug" (not really, since this part is unused, anyway) is fixed as a side effect. You may compare the coverage between master [1] and this branch [2] with coveralls. Branch: https://github.com/tarantool/luajit/tree/skaplun/gh-noticket-leb128-testsing [1]: https://coveralls.io/builds/80394140/source?filename=src%2Flj_utils_leb128.c [2]: https://coveralls.io/builds/80728053/source?filename=src%2Flj_utils_leb128.c src/lj_utils_leb128.c | 2 +- test/tarantool-c-tests/unit-leb128.test.c | 366 ++++++++++++++++++++++ 2 files changed, 367 insertions(+), 1 deletion(-) create mode 100644 test/tarantool-c-tests/unit-leb128.test.c diff --git a/src/lj_utils_leb128.c b/src/lj_utils_leb128.c index d66961da..5ad2bd3c 100644 --- a/src/lj_utils_leb128.c +++ b/src/lj_utils_leb128.c @@ -105,7 +105,7 @@ size_t LJ_FASTCALL lj_utils_write_leb128(uint8_t *buffer, int64_t value) size_t i = 0; /* LEB_SIGN_BIT propagation to check the remaining value. */ - while ((uint64_t)(value + LEB_SIGN_BIT) >= MIN_TWOBYTE_VALUE) { + while ((uint64_t)value + LEB_SIGN_BIT >= MIN_TWOBYTE_VALUE) { buffer[i++] = (uint8_t)((value & PAYLOAD_MASK) | LINK_BIT); value >>= SHIFT_STEP; } diff --git a/test/tarantool-c-tests/unit-leb128.test.c b/test/tarantool-c-tests/unit-leb128.test.c new file mode 100644 index 00000000..142476fb --- /dev/null +++ b/test/tarantool-c-tests/unit-leb128.test.c @@ -0,0 +1,366 @@ +/* +** Testing of LEB128/ULEB128 encoding. +** +** Major portions taken verbatim or adapted from the LuaVela. +** Copyright (C) 2020-2026 LuaVela Authors. +** Copyright (C) 2015-2020 IPONWEB Ltd. +*/ + +#include +#include + +#include "test.h" + +#include "lj_utils.h" + +#define BUFFER_SIZE 16 + +static int test_write_uleb128(void *state) +{ + size_t bytes_written = 0; + uint8_t buffer[BUFFER_SIZE] = {0}; + + UNUSED(state); + + bytes_written = lj_utils_write_uleb128(buffer, 0); + assert_true(bytes_written == 1); + assert_true(buffer[0] == 0x0); + + bytes_written = lj_utils_write_uleb128(buffer, 64); + assert_true(bytes_written == 1); + assert_true(buffer[0] == 0x40); + + bytes_written = lj_utils_write_uleb128(buffer, 128); + assert_true(bytes_written == 2); + assert_true(buffer[0] == 0x80 && buffer[1] == 0x01); + + bytes_written = lj_utils_write_uleb128(buffer, UINT64_MAX); + assert_true(bytes_written == 10); + assert_true(buffer[0] == 0xff && buffer[1] == 0xff && + buffer[2] == 0xff && buffer[3] == 0xff && + buffer[4] == 0xff && buffer[5] == 0xff && + buffer[6] == 0xff && buffer[7] == 0xff && + buffer[8] == 0xff && buffer[9] == 0x01); + + return TEST_EXIT_SUCCESS; +} + +static int test_write_leb128(void *state) +{ + size_t bytes_written = 0; + uint8_t buffer[BUFFER_SIZE] = {0}; + + UNUSED(state); + + bytes_written = lj_utils_write_leb128(buffer, 0); + assert_true(bytes_written == 1); + assert_true(buffer[0] == 0x0); + + bytes_written = lj_utils_write_leb128(buffer, -624485); + assert_true(bytes_written == 3); + assert_true(buffer[0] == 0x9b && buffer[1] == 0xf1 && + buffer[2] == 0x59); + + bytes_written = lj_utils_write_leb128(buffer, INT64_MIN); + assert_true(bytes_written == 10); + assert_true(buffer[0] == 0x80 && buffer[1] == 0x80 && + buffer[2] == 0x80 && buffer[3] == 0x80 && + buffer[4] == 0x80 && buffer[5] == 0x80 && + buffer[6] == 0x80 && buffer[7] == 0x80 && + buffer[8] == 0x80 && buffer[9] == 0x7f); + + bytes_written = lj_utils_write_leb128(buffer, INT64_MAX); + assert_true(bytes_written == 10); + assert_true(buffer[0] == 0xff && buffer[1] == 0xff && + buffer[2] == 0xff && buffer[3] == 0xff && + buffer[4] == 0xff && buffer[5] == 0xff && + buffer[6] == 0xff && buffer[7] == 0xff && + buffer[8] == 0xff && buffer[9] == 0x00); + + return TEST_EXIT_SUCCESS; +} + +/* Test miscellaneous writes, both signed and unsigned. */ +static int test_misc_writes(void *state) +{ + size_t bytes_written = 0; + uint8_t buffer[BUFFER_SIZE] = {0}; + + UNUSED(state); + + bytes_written = lj_utils_write_leb128(buffer, 0x10); + assert_true(bytes_written == 1); + assert_true(buffer[0] == 0x10); + + bytes_written = lj_utils_write_uleb128(buffer, 0x10); + assert_true(bytes_written == 1); + assert_true(buffer[0] == 0x10); + + bytes_written = lj_utils_write_leb128(buffer, -0x3b); + assert_true(bytes_written == 1); + assert_true(buffer[0] == 0x45); + + bytes_written = lj_utils_write_uleb128(buffer, 0x45); + assert_true(bytes_written == 1); + assert_true(buffer[0] == 0x45); + + bytes_written = lj_utils_write_leb128(buffer, 0x190e); + assert_true(bytes_written == 2); + assert_true(buffer[0] == 0x8e && buffer[1] == 0x32); + + bytes_written = lj_utils_write_uleb128(buffer, 0x190e); + assert_true(bytes_written == 2); + assert_true(buffer[0] == 0x8e && buffer[1] == 0x32); + + bytes_written = lj_utils_write_leb128(buffer, -0x143f); + assert_true(bytes_written == 2); + assert_true(buffer[0] == 0xc1 && buffer[1] == 0x57); + + bytes_written = lj_utils_write_uleb128(buffer, 0x2bc1); + assert_true(bytes_written == 2); + assert_true(buffer[0] == 0xc1 && buffer[1] == 0x57); + + bytes_written = lj_utils_write_leb128(buffer, 0x7e00000); + assert_true(bytes_written == 4); + assert_true(buffer[0] == 0x80 && buffer[1] == 0x80 && + buffer[2] == 0x80 && buffer[3] == 0x3f); + + bytes_written = lj_utils_write_uleb128(buffer, 0x7e00000); + assert_true(bytes_written == 4); + assert_true(buffer[0] == 0x80 && buffer[1] == 0x80 && + buffer[2] == 0x80 && buffer[3] == 0x3f); + + bytes_written = lj_utils_write_leb128(buffer, -0x6200000); + assert_true(bytes_written == 4); + assert_true(buffer[0] == 0x80 && buffer[1] == 0x80 && + buffer[2] == 0x80 && buffer[3] == 0x4f); + + bytes_written = lj_utils_write_uleb128(buffer, 0x9e00000); + assert_true(bytes_written == 4); + assert_true(buffer[0] == 0x80 && buffer[1] == 0x80 && + buffer[2] == 0x80 && buffer[3] == 0x4f); + + return TEST_EXIT_SUCCESS; +} + +static int test_read_uleb128(void *state) +{ + uint64_t value = 0; + size_t bytes_read = 0; + uint8_t buffer[BUFFER_SIZE] = {0}; + + UNUSED(state); + + bytes_read = lj_utils_read_uleb128(&value, buffer); + assert_true(bytes_read == 1); + assert_true(value == 0); + + buffer[0] = 0x40; + bytes_read = lj_utils_read_uleb128(&value, buffer); + assert_true(bytes_read == 1); + assert_true(value == 64); + + buffer[0] = 0x80; + buffer[1] = 0x01; + bytes_read = lj_utils_read_uleb128(&value, buffer); + assert_true(bytes_read == 2); + assert_true(value == 128); + + memset(buffer, 0xff, 9); + buffer[9] = 0x01; + bytes_read = lj_utils_read_uleb128(&value, buffer); + assert_true(bytes_read == 10); + assert_true(value == UINT64_MAX); + + return TEST_EXIT_SUCCESS; +} + +static int test_read_leb128(void *state) +{ + int64_t value = 0; + size_t bytes_read = 0; + uint8_t buffer[BUFFER_SIZE] = {0}; + + UNUSED(state); + + bytes_read = lj_utils_read_leb128(&value, buffer); + assert_true(bytes_read == 1); + assert_true(value == 0); + + buffer[0] = 0x9b; + buffer[1] = 0xf1; + buffer[2] = 0x59; + bytes_read = lj_utils_read_leb128(&value, buffer); + assert_true(bytes_read == 3); + assert_true(value == (int64_t)-624485); + + memset(buffer, 0x80, 9); + buffer[9] = 0x7f; + bytes_read = lj_utils_read_leb128(&value, buffer); + assert_true(bytes_read == 10); + assert_true(value == INT64_MIN); + + memset(buffer, 0xff, 9); + buffer[9] = 0x00; + bytes_read = lj_utils_read_leb128(&value, buffer); + assert_true(bytes_read == 10); + assert_true(value == INT64_MAX); + + return TEST_EXIT_SUCCESS; +} + +/* Test miscellaneous reads, both signed and unsigned. */ +static int test_misc_reads(void *state) +{ + int64_t i_value = 0; + uint64_t u_value = 0; + + size_t bytes_read = 0; + uint8_t buffer[BUFFER_SIZE] = {0}; + + UNUSED(state); + + buffer[0] = 0x10; + + bytes_read = lj_utils_read_leb128(&i_value, buffer); + assert_true(bytes_read == 1); + assert_true(i_value == (int64_t)0x10); + + bytes_read = lj_utils_read_uleb128(&u_value, buffer); + assert_true(bytes_read == 1); + assert_true(u_value == (uint64_t)0x10); + + buffer[0] = 0x45; + + bytes_read = lj_utils_read_leb128(&i_value, buffer); + assert_true(bytes_read == 1); + assert_true(i_value == (int64_t)-0x3b); + + bytes_read = lj_utils_read_uleb128(&u_value, buffer); + assert_true(bytes_read == 1); + assert_true(u_value == (uint64_t)0x45); + + buffer[0] = 0x8e; + buffer[1] = 0x32; + + bytes_read = lj_utils_read_leb128(&i_value, buffer); + assert_true(bytes_read == 2); + assert_true(i_value == (int64_t)0x190e); + + bytes_read = lj_utils_read_uleb128(&u_value, buffer); + assert_true(bytes_read == 2); + assert_true(u_value == (uint64_t)0x190e); + + buffer[0] = 0xc1; + buffer[1] = 0x57; + + bytes_read = lj_utils_read_leb128(&i_value, buffer); + assert_true(bytes_read == 2); + assert_true(i_value == (int64_t)-0x143f); + + bytes_read = lj_utils_read_uleb128(&u_value, buffer); + assert_true(bytes_read == 2); + assert_true(u_value == (uint64_t)0x2bc1); + + buffer[0] = 0xc1; + buffer[1] = 0x57; + + bytes_read = lj_utils_read_leb128(&i_value, buffer); + assert_true(bytes_read == 2); + assert_true(i_value == (int64_t)-0x143f); + + bytes_read = lj_utils_read_uleb128(&u_value, buffer); + assert_true(bytes_read == 2); + assert_true(u_value == (uint64_t)0x2bc1); + + buffer[0] = 0x80; + buffer[1] = 0x80; + buffer[2] = 0x80; + buffer[3] = 0x3f; + + bytes_read = lj_utils_read_leb128(&i_value, buffer); + assert_true(bytes_read == 4); + assert_true(i_value == (int64_t)0x7e00000); + + bytes_read = lj_utils_read_uleb128(&u_value, buffer); + assert_true(bytes_read == 4); + assert_true(u_value == (uint64_t)0x7e00000); + + buffer[0] = 0x80; + buffer[1] = 0x80; + buffer[2] = 0x80; + buffer[3] = 0x4f; + + bytes_read = lj_utils_read_leb128(&i_value, buffer); + assert_true(bytes_read == 4); + assert_true(i_value == (int64_t)-0x6200000); + + bytes_read = lj_utils_read_uleb128(&u_value, buffer); + assert_true(bytes_read == 4); + assert_true(u_value == (uint64_t)0x9e00000); + + return TEST_EXIT_SUCCESS; +} + +static int test_read_n(void *state) +{ + int64_t i_value = 0; + uint64_t u_value = 0; + + size_t bytes_read = 0; + uint8_t buffer[BUFFER_SIZE] = {0}; + + UNUSED(state); + + bytes_read = lj_utils_read_leb128_n(&i_value, buffer, 1); + assert_true(bytes_read == 1); + assert_true(i_value == 0); + + bytes_read = lj_utils_read_uleb128_n(&u_value, buffer, 1); + assert_true(bytes_read == 1); + assert_true(u_value == 0); + + buffer[0] = 0x80; + buffer[1] = 0x80; + buffer[2] = 0x80; + buffer[3] = 0x3f; + + assert_true(lj_utils_read_leb128_n(&i_value, buffer, 3) == 0); + assert_true(lj_utils_read_uleb128_n(&u_value, buffer, 3) == 0); + /* Values are untouched in case of failure. */ + assert_true(i_value == 0); + assert_true(u_value == 0); + + bytes_read = lj_utils_read_leb128_n(&i_value, buffer, 4); + assert_true(bytes_read == 4); + assert_true(i_value == (int64_t)0x7e00000); + + bytes_read = lj_utils_read_uleb128_n(&u_value, buffer, 4); + assert_true(bytes_read == 4); + assert_true(u_value == (uint64_t)0x7e00000); + + bytes_read = lj_utils_read_leb128_n(&i_value, buffer, 5); + assert_true(bytes_read == 4); + assert_true(i_value == (int64_t)0x7e00000); + + bytes_read = lj_utils_read_uleb128_n(&u_value, buffer, 5); + assert_true(bytes_read == 4); + assert_true(u_value == (uint64_t)0x7e00000); + + return TEST_EXIT_SUCCESS; +} + +int main(void) +{ + const struct test_unit tgroup[] = { + test_unit_def(test_write_uleb128), + test_unit_def(test_write_leb128), + test_unit_def(test_misc_writes), + test_unit_def(test_read_uleb128), + test_unit_def(test_read_leb128), + test_unit_def(test_misc_reads), + test_unit_def(test_read_n), + }; + const int test_result = test_run_group(tgroup, NULL); + return test_result; +} -- 2.55.0