You can subscribe to this list here.
2002 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(1) |
Oct
(122) |
Nov
(152) |
Dec
(69) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2003 |
Jan
(6) |
Feb
(25) |
Mar
(73) |
Apr
(82) |
May
(24) |
Jun
(25) |
Jul
(10) |
Aug
(11) |
Sep
(10) |
Oct
(54) |
Nov
(203) |
Dec
(182) |
2004 |
Jan
(307) |
Feb
(305) |
Mar
(430) |
Apr
(312) |
May
(187) |
Jun
(342) |
Jul
(487) |
Aug
(637) |
Sep
(336) |
Oct
(373) |
Nov
(441) |
Dec
(210) |
2005 |
Jan
(385) |
Feb
(480) |
Mar
(636) |
Apr
(544) |
May
(679) |
Jun
(625) |
Jul
(810) |
Aug
(838) |
Sep
(634) |
Oct
(521) |
Nov
(965) |
Dec
(543) |
2006 |
Jan
(494) |
Feb
(431) |
Mar
(546) |
Apr
(411) |
May
(406) |
Jun
(322) |
Jul
(256) |
Aug
(401) |
Sep
(345) |
Oct
(542) |
Nov
(308) |
Dec
(481) |
2007 |
Jan
(427) |
Feb
(326) |
Mar
(367) |
Apr
(255) |
May
(244) |
Jun
(204) |
Jul
(223) |
Aug
(231) |
Sep
(354) |
Oct
(374) |
Nov
(497) |
Dec
(362) |
2008 |
Jan
(322) |
Feb
(482) |
Mar
(658) |
Apr
(422) |
May
(476) |
Jun
(396) |
Jul
(455) |
Aug
(267) |
Sep
(280) |
Oct
(253) |
Nov
(232) |
Dec
(304) |
2009 |
Jan
(486) |
Feb
(470) |
Mar
(458) |
Apr
(423) |
May
(696) |
Jun
(461) |
Jul
(551) |
Aug
(575) |
Sep
(134) |
Oct
(110) |
Nov
(157) |
Dec
(102) |
2010 |
Jan
(226) |
Feb
(86) |
Mar
(147) |
Apr
(117) |
May
(107) |
Jun
(203) |
Jul
(193) |
Aug
(238) |
Sep
(300) |
Oct
(246) |
Nov
(23) |
Dec
(75) |
2011 |
Jan
(133) |
Feb
(195) |
Mar
(315) |
Apr
(200) |
May
(267) |
Jun
(293) |
Jul
(353) |
Aug
(237) |
Sep
(278) |
Oct
(611) |
Nov
(274) |
Dec
(260) |
2012 |
Jan
(303) |
Feb
(391) |
Mar
(417) |
Apr
(441) |
May
(488) |
Jun
(655) |
Jul
(590) |
Aug
(610) |
Sep
(526) |
Oct
(478) |
Nov
(359) |
Dec
(372) |
2013 |
Jan
(467) |
Feb
(226) |
Mar
(391) |
Apr
(281) |
May
(299) |
Jun
(252) |
Jul
(311) |
Aug
(352) |
Sep
(481) |
Oct
(571) |
Nov
(222) |
Dec
(231) |
2014 |
Jan
(185) |
Feb
(329) |
Mar
(245) |
Apr
(238) |
May
(281) |
Jun
(399) |
Jul
(382) |
Aug
(500) |
Sep
(579) |
Oct
(435) |
Nov
(487) |
Dec
(256) |
2015 |
Jan
(338) |
Feb
(357) |
Mar
(330) |
Apr
(294) |
May
(191) |
Jun
(108) |
Jul
(142) |
Aug
(261) |
Sep
(190) |
Oct
(54) |
Nov
(83) |
Dec
(22) |
2016 |
Jan
(49) |
Feb
(89) |
Mar
(33) |
Apr
(50) |
May
(27) |
Jun
(34) |
Jul
(53) |
Aug
(53) |
Sep
(98) |
Oct
(206) |
Nov
(93) |
Dec
(53) |
2017 |
Jan
(65) |
Feb
(82) |
Mar
(102) |
Apr
(86) |
May
(187) |
Jun
(67) |
Jul
(23) |
Aug
(93) |
Sep
(65) |
Oct
(45) |
Nov
(35) |
Dec
(17) |
2018 |
Jan
(26) |
Feb
(35) |
Mar
(38) |
Apr
(32) |
May
(8) |
Jun
(43) |
Jul
(27) |
Aug
(30) |
Sep
(43) |
Oct
(42) |
Nov
(38) |
Dec
(67) |
2019 |
Jan
(32) |
Feb
(37) |
Mar
(53) |
Apr
(64) |
May
(49) |
Jun
(18) |
Jul
(14) |
Aug
(53) |
Sep
(25) |
Oct
(30) |
Nov
(49) |
Dec
(31) |
2020 |
Jan
(87) |
Feb
(45) |
Mar
(37) |
Apr
(51) |
May
(99) |
Jun
(36) |
Jul
(11) |
Aug
(14) |
Sep
(20) |
Oct
(24) |
Nov
(40) |
Dec
(23) |
2021 |
Jan
(14) |
Feb
(53) |
Mar
(85) |
Apr
(15) |
May
(19) |
Jun
(3) |
Jul
(14) |
Aug
(1) |
Sep
(57) |
Oct
(73) |
Nov
(56) |
Dec
(22) |
2022 |
Jan
(3) |
Feb
(22) |
Mar
(6) |
Apr
(55) |
May
(46) |
Jun
(39) |
Jul
(15) |
Aug
(9) |
Sep
(11) |
Oct
(34) |
Nov
(20) |
Dec
(36) |
2023 |
Jan
(79) |
Feb
(41) |
Mar
(99) |
Apr
(169) |
May
(48) |
Jun
(16) |
Jul
(16) |
Aug
(57) |
Sep
(83) |
Oct
(89) |
Nov
(97) |
Dec
(30) |
2024 |
Jan
(25) |
Feb
(73) |
Mar
(76) |
Apr
(122) |
May
(46) |
Jun
(44) |
Jul
(27) |
Aug
(30) |
Sep
(33) |
Oct
(67) |
Nov
(91) |
Dec
(70) |
2025 |
Jan
(44) |
Feb
(36) |
Mar
(85) |
Apr
(100) |
May
(138) |
Jun
(55) |
Jul
(107) |
Aug
(16) |
Sep
|
Oct
|
Nov
|
Dec
|
From: Florian K. <fk...@so...> - 2025-07-16 17:44:08
|
https://sourceware.org/cgit/valgrind/commit/?id=0593738843903c7c2d6299bf2a47f63ebc08e947 commit 0593738843903c7c2d6299bf2a47f63ebc08e947 Author: Florian Krohm <fl...@ei...> Date: Wed Jul 16 17:43:34 2025 +0000 Constant folding for Iop_CtzNat32/64. (BZ 506211) Part of fixing https://bugs.kde.org/show_bug.cgi?id=506211 Diff: --- VEX/priv/ir_opt.c | 35 +++++++++++++++++++++++++++++++++++ none/tests/iropt-test/irops.tab | 4 ++-- none/tests/iropt-test/unary.c | 23 +++++++++++++++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/VEX/priv/ir_opt.c b/VEX/priv/ir_opt.c index 140899480f..c37ff08a77 100644 --- a/VEX/priv/ir_opt.c +++ b/VEX/priv/ir_opt.c @@ -1365,6 +1365,30 @@ static UInt fold_ClzNat32 ( UInt value ) return 32; } +/* Helpers for folding CtzNat32/64. */ +static UInt fold_CtzNat_WRK ( ULong value, UInt num_bits ) +{ + UInt count = 0; + + for (UInt i = 1; i <= num_bits; ++i) { + if (value & 0x1) + return count; + value >>= 1; + ++count; + } + return count; +} + +static UInt fold_CtzNat64 ( ULong value ) +{ + return fold_CtzNat_WRK(value, 64); +} + +static UInt fold_CtzNat32 ( UInt value ) +{ + return fold_CtzNat_WRK(value, 32); +} + /* Helpers for folding PopCount32/64. https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan As many iterations as 1-bits present. @@ -1739,6 +1763,17 @@ static IRExpr* fold_Expr_WRK ( IRExpr** env, IRExpr* e ) break; } + case Iop_CtzNat32: { + UInt u32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32; + e2 = IRExpr_Const(IRConst_U32(fold_CtzNat32(u32))); + break; + } + case Iop_CtzNat64: { + ULong u64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64; + e2 = IRExpr_Const(IRConst_U64(fold_CtzNat64(u64))); + break; + } + case Iop_PopCount32: { UInt u32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32; e2 = IRExpr_Const(IRConst_U32(fold_PopCount32(u32))); diff --git a/none/tests/iropt-test/irops.tab b/none/tests/iropt-test/irops.tab index 1d06919d16..02afa6423a 100644 --- a/none/tests/iropt-test/irops.tab +++ b/none/tests/iropt-test/irops.tab @@ -101,8 +101,8 @@ { OPNAME(ClzNat32), Ity_I32, 1, Ity_I32 }, { OPNAME(ClzNat64), Ity_I64, 1, Ity_I64 }, -// { OPNAME(CtzNat32), Ity_I32, 1, Ity_I32 }, // no folding yet -// { OPNAME(CtzNat64), Ity_I64, 1, Ity_I64 }, // no folding yet + { OPNAME(CtzNat32), Ity_I32, 1, Ity_I32 }, + { OPNAME(CtzNat64), Ity_I64, 1, Ity_I64 }, { OPNAME(PopCount32), Ity_I32, 1, Ity_I32 }, { OPNAME(PopCount64), Ity_I64, 1, Ity_I64 }, diff --git a/none/tests/iropt-test/unary.c b/none/tests/iropt-test/unary.c index 6d664a1b84..e6554cef60 100644 --- a/none/tests/iropt-test/unary.c +++ b/none/tests/iropt-test/unary.c @@ -33,6 +33,7 @@ static void run_random_tests(const irop_t *, test_data_t *); static uint64_t left(uint64_t, unsigned); static uint32_t popcount(uint64_t); static uint32_t clz(uint64_t, unsigned); +static uint32_t ctz(uint64_t, unsigned); void @@ -201,6 +202,9 @@ check_result(const irop_t *op, const test_data_t *data) case Iop_ClzNat32: expected = clz(opnd, 32); break; case Iop_ClzNat64: expected = clz(opnd, 64); break; + case Iop_CtzNat32: expected = ctz(opnd, 32); break; + case Iop_CtzNat64: expected = ctz(opnd, 64); break; + default: panic("%s: operator %s not handled\n", __func__, op->name); } @@ -283,3 +287,22 @@ clz(uint64_t value, unsigned num_bits) } return num_bits - last_seen_1bit; } + + +static uint32_t +ctz(uint64_t value, unsigned num_bits ) +{ + unsigned count = 0; + unsigned num_nibbles = num_bits / 4; + + for (unsigned i = 0; i < num_nibbles; ++i) { + UInt nibble = value & 0xF; + if ((nibble & 0x1) == 0x1) return count; + if ((nibble & 0x2) == 0x2) return count + 1; + if ((nibble & 0x4) == 0x4) return count + 2; + if ((nibble & 0x8) == 0x8) return count + 3; + count += 4; + value >>= 4; + } + return count; +} |
From: Florian K. <fk...@so...> - 2025-07-16 14:55:15
|
https://sourceware.org/cgit/valgrind/commit/?id=c164cf37aca7661f76440e14d817dcfeb4c4fc82 commit c164cf37aca7661f76440e14d817dcfeb4c4fc82 Author: Florian Krohm <fl...@ei...> Date: Wed Jul 16 14:54:44 2025 +0000 Constant folding for Iop_ClzNat32/64. (BZ 506211) Part of fixing https://bugs.kde.org/show_bug.cgi?id=506211 Diff: --- VEX/priv/ir_opt.c | 30 ++++++++++++++++++++++++++++++ none/tests/iropt-test/irops.tab | 4 ++-- none/tests/iropt-test/unary.c | 18 ++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/VEX/priv/ir_opt.c b/VEX/priv/ir_opt.c index f0458cb285..140899480f 100644 --- a/VEX/priv/ir_opt.c +++ b/VEX/priv/ir_opt.c @@ -1346,6 +1346,25 @@ static UInt fold_Clz32 ( UInt value ) return 0; } +/* Helpers for folding ClzNat32/64. */ +static UInt fold_ClzNat64 ( ULong value ) +{ + UInt i; + for (i = 0; i < 64; ++i) { + if (0ULL != (value & (((ULong)1) << (63 - i)))) return i; + } + return 64; +} + +static UInt fold_ClzNat32 ( UInt value ) +{ + UInt i; + for (i = 0; i < 32; ++i) { + if (0 != (value & (((UInt)1) << (31 - i)))) return i; + } + return 32; +} + /* Helpers for folding PopCount32/64. https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan As many iterations as 1-bits present. @@ -1709,6 +1728,17 @@ static IRExpr* fold_Expr_WRK ( IRExpr** env, IRExpr* e ) break; } + case Iop_ClzNat32: { + UInt u32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32; + e2 = IRExpr_Const(IRConst_U32(fold_ClzNat32(u32))); + break; + } + case Iop_ClzNat64: { + ULong u64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64; + e2 = IRExpr_Const(IRConst_U64(fold_ClzNat64(u64))); + break; + } + case Iop_PopCount32: { UInt u32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32; e2 = IRExpr_Const(IRConst_U32(fold_PopCount32(u32))); diff --git a/none/tests/iropt-test/irops.tab b/none/tests/iropt-test/irops.tab index e73ec46a87..1d06919d16 100644 --- a/none/tests/iropt-test/irops.tab +++ b/none/tests/iropt-test/irops.tab @@ -98,8 +98,8 @@ // { OPNAME(Ctz32), Ity_I32, 1, Ity_I32 }, // deprecated, undefined behaviour // { OPNAME(Ctz64), Ity_I64, 1, Ity_I64 }, // deprecated, undefined behaviour -// { OPNAME(ClzNat32), Ity_I32, 1, Ity_I32 }, // no folding yet -// { OPNAME(ClzNat64), Ity_I64, 1, Ity_I64 }, // no folding yet + { OPNAME(ClzNat32), Ity_I32, 1, Ity_I32 }, + { OPNAME(ClzNat64), Ity_I64, 1, Ity_I64 }, // { OPNAME(CtzNat32), Ity_I32, 1, Ity_I32 }, // no folding yet // { OPNAME(CtzNat64), Ity_I64, 1, Ity_I64 }, // no folding yet diff --git a/none/tests/iropt-test/unary.c b/none/tests/iropt-test/unary.c index bb26138487..6d664a1b84 100644 --- a/none/tests/iropt-test/unary.c +++ b/none/tests/iropt-test/unary.c @@ -32,6 +32,7 @@ static void run_selected_tests(const irop_t *, test_data_t *); static void run_random_tests(const irop_t *, test_data_t *); static uint64_t left(uint64_t, unsigned); static uint32_t popcount(uint64_t); +static uint32_t clz(uint64_t, unsigned); void @@ -197,6 +198,9 @@ check_result(const irop_t *op, const test_data_t *data) expected = popcount(opnd); break; + case Iop_ClzNat32: expected = clz(opnd, 32); break; + case Iop_ClzNat64: expected = clz(opnd, 64); break; + default: panic("%s: operator %s not handled\n", __func__, op->name); } @@ -265,3 +269,17 @@ popcount(uint64_t value) } return count; } + + +static uint32_t +clz(uint64_t value, unsigned num_bits) +{ + unsigned last_seen_1bit = 0; + + for (int i = 1; i <= num_bits; ++i) { + if (value & 0x1) + last_seen_1bit = i; + value >>= 1; + } + return num_bits - last_seen_1bit; +} |
From: Florian K. <fk...@so...> - 2025-07-16 11:52:07
|
https://sourceware.org/cgit/valgrind/commit/?id=21bc095a32ad715a5857d11111703a34eca62b79 commit 21bc095a32ad715a5857d11111703a34eca62b79 Author: Florian Krohm <fl...@ei...> Date: Wed Jul 16 11:51:15 2025 +0000 iropt-test: Also test with random inputs; reorg the code a bit New utility functions: get_random_value and get_selected_values Add command line option -rNUM to specify the number of random tests per operator. Diff: --- none/tests/iropt-test/binary.c | 116 +++++++++++++++++--------------- none/tests/iropt-test/iropt-test.vgtest | 3 +- none/tests/iropt-test/main.c | 9 ++- none/tests/iropt-test/unary.c | 74 ++++++++++---------- none/tests/iropt-test/util.c | 55 +++++++++++++++ none/tests/iropt-test/vtest.h | 3 + 6 files changed, 163 insertions(+), 97 deletions(-) diff --git a/none/tests/iropt-test/binary.c b/none/tests/iropt-test/binary.c index c3f36c1884..ec4fa21d1c 100644 --- a/none/tests/iropt-test/binary.c +++ b/none/tests/iropt-test/binary.c @@ -27,90 +27,96 @@ #include "vtest.h" static void check_result(const irop_t *, const test_data_t *); -static void run_tests(const irop_t *, test_data_t *, unsigned, uint64_t *, - unsigned, uint64_t *); +static void run_tests(const irop_t *, test_data_t *); +static void run_shift_tests(const irop_t *, test_data_t *); static int is_shift_op(IROp); void test_binary_op(const irop_t *op, test_data_t *data) { - opnd_t *opnd_l = &data->opnds[0]; - - switch (opnd_l->type) { - case Ity_I1: { - uint64_t values[] = { 0, 1 }; - - run_tests(op, data, NUM_EL(values), values, NUM_EL(values), values); - break; - } + if (is_shift_op(op->op)) + run_shift_tests(op, data); + else + run_tests(op, data); +} - case Ity_I8: { - uint64_t values[] = { 0, 1, 2, UINT8_MAX - 1, UINT8_MAX }; - uint64_t shifts[] = { 0, 1, 2, 6, 7 }; - if (is_shift_op(op->op)) - run_tests(op, data, NUM_EL(values), values, NUM_EL(shifts), shifts); - else - run_tests(op, data, NUM_EL(values), values, NUM_EL(values), values); - break; - } +static void +run_selected_tests(const irop_t *op, test_data_t *data) +{ + opnd_t *opnd_l = &data->opnds[0]; + opnd_t *opnd_r = &data->opnds[1]; + unsigned num_val_l, num_val_r; + const uint64_t *values_l = get_selected_values(opnd_l->type, &num_val_l); + const uint64_t *values_r = get_selected_values(opnd_r->type, &num_val_r); - case Ity_I16: { - uint64_t values[] = { 0, 1, 2, UINT16_MAX - 1, UINT16_MAX }; - uint64_t shifts[] = { 0, 1, 2, 14, 15 }; + for (unsigned i = 0; i < num_val_l; ++i) { + opnd_l->value = values_l[i]; + for (unsigned j = 0; j < num_val_r; ++j) { + opnd_r->value = values_r[j]; - if (is_shift_op(op->op)) - run_tests(op, data, NUM_EL(values), values, NUM_EL(shifts), shifts); - else - run_tests(op, data, NUM_EL(values), values, NUM_EL(values), values); - break; + valgrind_execute_test(op, data); + check_result(op, data); + } } +} - case Ity_I32: { - uint64_t values[] = { 0, 1, 2, UINT32_MAX - 1, UINT32_MAX }; - uint64_t shifts[] = { 0, 1, 2, 30, 31 }; - - if (is_shift_op(op->op)) - run_tests(op, data, NUM_EL(values), values, NUM_EL(shifts), shifts); - else - run_tests(op, data, NUM_EL(values), values, NUM_EL(values), values); - break; - } - case Ity_I64: { - uint64_t values[] = { 0, 1, 2, UINT64_MAX - 1, UINT64_MAX }; - uint64_t shifts[] = { 0, 1, 2, 62, 63 }; +/* Test with pseudo-random numbers */ +static void +run_random_tests(const irop_t *op, test_data_t *data) +{ + opnd_t *opnd_l = &data->opnds[0]; + opnd_t *opnd_r = &data->opnds[1]; - if (is_shift_op(op->op)) - run_tests(op, data, NUM_EL(values), values, NUM_EL(shifts), shifts); - else - run_tests(op, data, NUM_EL(values), values, NUM_EL(values), values); - break; - } + for (unsigned i = 0; i < num_random_tests; ++i) { + opnd_l->value = get_random_value(opnd_l->type); + opnd_r->value = get_random_value(opnd_r->type); - default: - panic(__func__); + valgrind_execute_test(op, data); + check_result(op, data); } } +/* OP is a shift operator. */ static void -run_tests(const irop_t *op, test_data_t *data, unsigned num_val_l, - uint64_t *values_l, unsigned num_val_r, uint64_t *values_r) +run_shift_tests(const irop_t *op, test_data_t *data) { opnd_t *opnd_l = &data->opnds[0]; opnd_t *opnd_r = &data->opnds[1]; + unsigned num_shiftee; + const uint64_t *shiftee = get_selected_values(opnd_l->type, &num_shiftee); + unsigned max_shift_amount = bitsof_irtype(opnd_r->type) - 1; - for (unsigned i = 0; i < num_val_l; ++i) { - opnd_l->value = values_l[i]; - for (unsigned j = 0; j < num_val_r; ++j) { - opnd_r->value = values_r[j]; + /* Shift selected values with all possible shift amounts */ + for (unsigned i = 0; i < num_shiftee; ++i) { + opnd_l->value = shiftee[i]; + for (unsigned j = 0; j < max_shift_amount; ++j) { + opnd_r->value = j; valgrind_execute_test(op, data); check_result(op, data); } } + + /* Shift random values with random shift amounts */ + for (unsigned i = 0; i < num_random_tests; ++i) { + opnd_l->value = get_random_value(opnd_l->type); + opnd_r->value = get_random_value(opnd_r->type) & max_shift_amount; + + valgrind_execute_test(op, data); + check_result(op, data); + } +} + + +static void +run_tests(const irop_t *op, test_data_t *data) +{ + run_selected_tests(op, data); + run_random_tests(op, data); } diff --git a/none/tests/iropt-test/iropt-test.vgtest b/none/tests/iropt-test/iropt-test.vgtest index 8becafdf8c..de31de6046 100644 --- a/none/tests/iropt-test/iropt-test.vgtest +++ b/none/tests/iropt-test/iropt-test.vgtest @@ -1,4 +1,5 @@ prog: iropt-test -#args: -v -v +#args: -v -v -r10 +args: -r100 vgopts: -q --vex-guest-chase=no diff --git a/none/tests/iropt-test/main.c b/none/tests/iropt-test/main.c index 28b8d23e4b..2622515e55 100644 --- a/none/tests/iropt-test/main.c +++ b/none/tests/iropt-test/main.c @@ -38,18 +38,23 @@ static void check_irops_table(void); static test_data_t *new_test_data(const irop_t *); int verbose = 0; +unsigned num_random_tests; int main(int argc, char *argv[]) { assert(sizeof(long long) == 8); + assert(RAND_MAX == INT32_MAX); for (int i = 1; i < argc; ++i) { if (strcmp(argv[i], "-v") == 0) ++verbose; - else if (strcmp(argv[i], "--help") == 0) { + else if (strncmp(argv[i], "-r", 2) == 0) { + num_random_tests = atoi(argv[i] + 2); + } else if (strcmp(argv[i], "--help") == 0) { printf("\niropt-test [ -v | --help ]\n"); + printf("\n\t -rNUM number of random tests per IRop\n"); printf("\n\t -v verbose mode; shows IROps being tested\n"); printf("\n\t -v -v verbose mode, extreme edition\n\n"); return 0; @@ -72,7 +77,7 @@ main(int argc, char *argv[]) const irop_t *op = irops +i; if (verbose) - printf("\nTesting operator %s\n", op->name); + printf("Testing operator %s\n", op->name); test_data_t *data = new_test_data(op); diff --git a/none/tests/iropt-test/unary.c b/none/tests/iropt-test/unary.c index 44af3203dd..bb26138487 100644 --- a/none/tests/iropt-test/unary.c +++ b/none/tests/iropt-test/unary.c @@ -23,11 +23,13 @@ */ #include <stdio.h> // printf +#include <stdlib.h> // rand #include <stdint.h> // UINT64_MAX #include "vtest.h" static void check_result(const irop_t *, const test_data_t *); -static void run_tests(const irop_t *, test_data_t *, unsigned, uint64_t *); +static void run_selected_tests(const irop_t *, test_data_t *); +static void run_random_tests(const irop_t *, test_data_t *); static uint64_t left(uint64_t, unsigned); static uint32_t popcount(uint64_t); @@ -38,47 +40,25 @@ test_unary_op(const irop_t *op, test_data_t *data) opnd_t *opnd = &data->opnds[0]; switch (opnd->type) { - case Ity_I1: { - uint64_t values[] = { 0, 1 }; - - run_tests(op, data, NUM_EL(values), values); - break; - } - + case Ity_I1: case Ity_I8: { - uint64_t values[] = { 0, 1, 2, UINT8_MAX - 1, UINT8_MAX }; - - run_tests(op, data, NUM_EL(values), values); - break; - } - - case Ity_I16: { - uint64_t values[] = { 0, 1, 2, UINT16_MAX - 1, UINT16_MAX, - /* and for the benefit of Iop_16HIto8: */ - 1 << 8, 2 << 8, UINT8_MAX << 8 - }; - - run_tests(op, data, NUM_EL(values), values); - break; - } - - case Ity_I32: { - uint64_t values[] = { 0, 1, 2, UINT32_MAX - 1, UINT32_MAX, - /* and for the benefit of Iop_32HIto16: */ - 1 << 16, 2 << 16, (uint64_t)UINT16_MAX << 16 - }; - run_tests(op, data, NUM_EL(values), values); + /* Exhaustive */ + unsigned max = (1 << bitsof_irtype(opnd->type)) - 1; + for (unsigned i = 0; i <= max; ++i) { + opnd->value = i; + + valgrind_execute_test(op, data); + check_result(op, data); + } break; } - case Ity_I64: { - uint64_t values[] = { 0, 1, 2, UINT64_MAX - 1, UINT64_MAX, - /* and for the benefit of Iop_64HIto32: */ - (uint64_t)1 << 32, (uint64_t)2 << 32, (uint64_t)UINT32_MAX << 32 - }; - run_tests(op, data, NUM_EL(values), values); + case Ity_I16: + case Ity_I32: + case Ity_I64: + run_selected_tests(op, data); + run_random_tests(op, data); break; - } default: panic(__func__); @@ -87,10 +67,11 @@ test_unary_op(const irop_t *op, test_data_t *data) static void -run_tests(const irop_t *op, test_data_t *data, unsigned num_val, - uint64_t *values) +run_selected_tests(const irop_t *op, test_data_t *data) { opnd_t *opnd = &data->opnds[0]; + unsigned num_val; + const uint64_t *values = get_selected_values(opnd->type, &num_val); for (unsigned i = 0; i < num_val; ++i) { opnd->value = values[i]; @@ -101,6 +82,21 @@ run_tests(const irop_t *op, test_data_t *data, unsigned num_val, } +/* Test with pseudo-random numbers */ +static void +run_random_tests(const irop_t *op, test_data_t *data) +{ + opnd_t *opnd = &data->opnds[0]; + + for (unsigned i = 0; i < num_random_tests; ++i) { + opnd->value = get_random_value(opnd->type); + + valgrind_execute_test(op, data); + check_result(op, data); + } +} + + /* Check the result of a unary operation. */ static void check_result(const irop_t *op, const test_data_t *data) diff --git a/none/tests/iropt-test/util.c b/none/tests/iropt-test/util.c index 80e58570fe..072ff90c36 100644 --- a/none/tests/iropt-test/util.c +++ b/none/tests/iropt-test/util.c @@ -104,3 +104,58 @@ bitsof_irtype(IRType ty) panic(__func__); } } + + +uint64_t +get_random_value(IRType type) +{ + uint64_t val = rand(); + + switch (type) { + case Ity_I1: return val & 0x1; + case Ity_I8: return val & UINT8_MAX; + case Ity_I16: return val & UINT16_MAX; + case Ity_I32: return val & UINT32_MAX; + case Ity_I64: + /* Note, that RAND_MAX == INT32_MAX. Therefore, simply concatenating + two rand() values would never produce a value with MSB == 1 */ + val <<= (32 + 1); + val |= rand() << 1; + val |= rand() & 0x1; + return val; + + default: + panic(__func__); + } +} + + +const uint64_t * +get_selected_values(IRType type, unsigned *num_val) +{ + static const uint64_t values_1bit[] = { 0, 1 }; + static const uint64_t values_8bit[] = { 0, 1, 2, + UINT8_MAX - 1, UINT8_MAX }; + static const uint64_t values_16bit[] = { 0, 1, 2, + UINT8_MAX - 1, UINT8_MAX, UINT8_MAX + 1, + UINT16_MAX - 1, UINT16_MAX }; + static const uint64_t values_32bit[] = { 0, 1, 2, + UINT8_MAX - 1, UINT8_MAX, UINT8_MAX + 1, + UINT16_MAX - 1, UINT16_MAX, UINT16_MAX + 1, + UINT32_MAX - 1, UINT32_MAX }; + static const uint64_t values_64bit[] = { 0, 1, 2, + UINT8_MAX - 1, UINT8_MAX, UINT8_MAX + 1, + UINT16_MAX - 1, UINT16_MAX, UINT16_MAX + 1, + UINT32_MAX - 1, UINT32_MAX, UINT32_MAX + 1, + UINT64_MAX - 1, UINT64_MAX }; + + switch (type) { + case Ity_I1: *num_val = NUM_EL(values_1bit); return values_1bit; + case Ity_I8: *num_val = NUM_EL(values_8bit); return values_8bit; + case Ity_I16: *num_val = NUM_EL(values_16bit); return values_16bit; + case Ity_I32: *num_val = NUM_EL(values_32bit); return values_32bit; + case Ity_I64: *num_val = NUM_EL(values_64bit); return values_64bit; + default: + panic(__func__); + } +} diff --git a/none/tests/iropt-test/vtest.h b/none/tests/iropt-test/vtest.h index d9c1ddaae5..47b397f681 100644 --- a/none/tests/iropt-test/vtest.h +++ b/none/tests/iropt-test/vtest.h @@ -84,8 +84,11 @@ void panic(const char *, ...) __attribute__((noreturn)); void complain(const irop_t *, const test_data_t *, uint64_t expected); unsigned bitsof_irtype(IRType); +uint64_t get_random_value(IRType); +const uint64_t *get_selected_values(IRType, unsigned *); /* Exported variables */ extern int verbose; +extern unsigned num_random_tests; #endif // VTEST_H |
From: Paul F. <pa...@so...> - 2025-07-16 05:11:08
|
https://sourceware.org/cgit/valgrind/commit/?id=9000b0e5540c98f80cceb341423d24b1f5200722 commit 9000b0e5540c98f80cceb341423d24b1f5200722 Author: Paul Floyd <pj...@wa...> Date: Wed Jul 16 07:09:37 2025 +0200 Change [a]sync_sighandler to [a]sync_signalhandler in comments and in one "if (0)" VG_(printf). Diff: --- coregrind/m_signals.c | 4 ++-- coregrind/m_syswrap/syswrap-main.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/coregrind/m_signals.c b/coregrind/m_signals.c index 523f4d7fcb..a51840c0a0 100644 --- a/coregrind/m_signals.c +++ b/coregrind/m_signals.c @@ -178,7 +178,7 @@ else if thread is blocked in a syscall marked SfMayBlock - then signals may be delivered to async_sighandler, since we + then signals may be delivered to async_signalhandler, since we temporarily unblocked them for the duration of the syscall, by using the real (SCSS) mask for this thread @@ -2999,7 +2999,7 @@ void sync_signalhandler ( Int sigNo, Bool from_user; if (0) - VG_(printf)("sync_sighandler(%d, %p, %p)\n", sigNo, info, uc); + VG_(printf)("sync_signalhandler(%d, %p, %p)\n", sigNo, info, uc); vg_assert(info != NULL); vg_assert(info->si_signo == sigNo); diff --git a/coregrind/m_syswrap/syswrap-main.c b/coregrind/m_syswrap/syswrap-main.c index 1a7f038d48..5919698f0e 100644 --- a/coregrind/m_syswrap/syswrap-main.c +++ b/coregrind/m_syswrap/syswrap-main.c @@ -2512,7 +2512,7 @@ void VG_(client_syscall) ( ThreadId tid, UInt trc ) /* do_syscall_for_client may not return if the syscall was interrupted by a signal. In that case, flow of control is - first to m_signals.async_sighandler, which calls + first to m_signals.async_signalhandler, which calls VG_(fixup_guest_state_after_syscall_interrupted), which fixes up the guest state, and possibly calls VG_(post_syscall). Once that's done, control drops back @@ -2723,9 +2723,9 @@ void VG_(post_syscall) (ThreadId tid) However, the syscall may get interrupted by an async-signal. In that case do_syscall_for_client/VG_(do_syscall6) do not - return. Instead we wind up in m_signals.async_sighandler. We need + return. Instead we wind up in m_signals.async_signalhandler. We need to fix up the guest state to make it look like the syscall was - interrupted for guest. So async_sighandler calls here, and this + interrupted for guest. So async_signalhandler calls here, and this does the fixup. Note that from here we wind up calling VG_(post_syscall) too. */ |
From: Mark W. <ma...@so...> - 2025-07-15 22:02:53
|
https://sourceware.org/cgit/valgrind/commit/?id=cad20f3e7d42e6371896e2492f0fc3a081314238 commit cad20f3e7d42e6371896e2492f0fc3a081314238 Author: Mark Wielaard <ma...@kl...> Date: Tue Jul 15 23:49:36 2025 +0200 Support mmap MAP_FIXED_NOREPLACE if defined Define VKI_MAP_FIXED_NOREPLACE for amd64-linux, arm-linux, arm64-linux, mips32-linux, mips64-linux, riscv64-linux and x86-linux. If it is defined then ML_(generic_PRE_sys_mmap) will also interpret VKI_MAP_FIXED_NOREPLACE as an MFixed hint. If the aspace manager doesn't find a MAP_FIXED_NOREPLACE ok, then fail with EEXIST. If the actual kernel mmap request fails and MAP_FIXED_NOREPLACE is set also immediately fail with EEXIST without retrying. This fixes the LTP mmap17 testcase. https://bugs.kde.org/show_bug.cgi?id=418756 Diff: --- NEWS | 3 ++- coregrind/m_syswrap/syswrap-generic.c | 19 ++++++++++++++++++- include/vki/vki-amd64-linux.h | 1 + include/vki/vki-arm-linux.h | 1 + include/vki/vki-arm64-linux.h | 1 + include/vki/vki-mips32-linux.h | 1 + include/vki/vki-mips64-linux.h | 1 + include/vki/vki-riscv64-linux.h | 1 + include/vki/vki-x86-linux.h | 1 + 9 files changed, 27 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 49403da013..796d9716e5 100644 --- a/NEWS +++ b/NEWS @@ -29,8 +29,8 @@ bugzilla (https://bugs.kde.org/enter_bug.cgi?product=valgrind) rather than mailing the developers (or mailing lists) directly -- bugs that are not entered into bugzilla tend to get forgotten about or ignored. -506076 unimplemented fcntl command: 1028 (F_CREATED_QUERY) 338803 Handling of dwz debug alt files or cross-CU is broken +418756 MAP_FIXED_NOREPLACE mmap flag unsupported 493434 Add --track-fds=bad mode (no "leak" tracking) 503098 Incorrect NAN-boxing for float registers in RISC-V 503641 close_range syscalls started failing with 3.25.0 @@ -52,6 +52,7 @@ are not entered into bugzilla tend to get forgotten about or ignored. AMD64_GET_TLSBASE 505228 Wrap linux specific mseal syscall 502968 Wrap linux specific syscalls 457 (listmount) and 458 (statmount) +506076 unimplemented fcntl command: 1028 (F_CREATED_QUERY) 506499 Unhandled syscall 592 (exterrctl - FreeBSD 506795 Better report which clone flags are problematic 506930 valgrind allows SIGKILL being reset to SIG_DFL diff --git a/coregrind/m_syswrap/syswrap-generic.c b/coregrind/m_syswrap/syswrap-generic.c index 50deb1e764..50415a2faa 100644 --- a/coregrind/m_syswrap/syswrap-generic.c +++ b/coregrind/m_syswrap/syswrap-generic.c @@ -2678,7 +2678,12 @@ ML_(generic_PRE_sys_mmap) ( ThreadId tid, (fixed/hint/any), and ask aspacem what we should do. */ mreq.start = arg1; mreq.len = arg2; - if (arg4 & VKI_MAP_FIXED) { + if ((arg4 & VKI_MAP_FIXED) +#if defined(VKI_MAP_FIXED_NOREPLACE) + || (arg4 & VKI_MAP_FIXED_NOREPLACE) +#endif + ) + { mreq.rkind = MFixed; } else #if defined(VGO_solaris) && defined(VKI_MAP_ALIGN) @@ -2710,6 +2715,11 @@ ML_(generic_PRE_sys_mmap) ( ThreadId tid, advised = VG_(am_get_advisory)( &mreq, True/*client*/, &mreq_ok ); if (!mreq_ok) { /* Our request was bounced, so we'd better fail. */ +#if defined(VKI_MAP_FIXED_NOREPLACE) + if (arg4 & VKI_MAP_FIXED_NOREPLACE) { + return VG_(mk_SysRes_Error)( VKI_EEXIST ); + } +#endif return VG_(mk_SysRes_Error)( VKI_EINVAL ); } @@ -2744,6 +2754,13 @@ ML_(generic_PRE_sys_mmap) ( ThreadId tid, } # endif +# if defined(VKI_MAP_FIXED_NOREPLACE) + /* FIXED_NOREPLACE is fatal, no retries. */ + if ((arg4 & VKI_MAP_FIXED_NOREPLACE) && sr_isError(sres)) { + return VG_(mk_SysRes_Error)( VKI_EEXIST ); + } +# endif + /* A refinement: it may be that the kernel refused aspacem's choice of address. If we were originally asked for a hinted mapping, there is still a last chance: try again at any address. diff --git a/include/vki/vki-amd64-linux.h b/include/vki/vki-amd64-linux.h index 12cd65ac7c..bbcf4ab4e9 100644 --- a/include/vki/vki-amd64-linux.h +++ b/include/vki/vki-amd64-linux.h @@ -236,6 +236,7 @@ struct vki_sigcontext { #define VKI_MAP_ANONYMOUS 0x20 /* don't use a file */ #define VKI_MAP_32BIT 0x40 /* only give out 32bit addresses */ #define VKI_MAP_NORESERVE 0x4000 /* don't check for reservations */ +#define VKI_MAP_FIXED_NOREPLACE 0x100000 /* fail EEXIST if fixed map fails */ //---------------------------------------------------------------------- // From linux-2.6.9/include/asm-x86_64/fcntl.h diff --git a/include/vki/vki-arm-linux.h b/include/vki/vki-arm-linux.h index 7e0001c0cf..a72268ca43 100644 --- a/include/vki/vki-arm-linux.h +++ b/include/vki/vki-arm-linux.h @@ -233,6 +233,7 @@ struct vki_sigcontext { #define VKI_MAP_FIXED 0x10 /* Interpret addr exactly */ #define VKI_MAP_ANONYMOUS 0x20 /* don't use a file */ #define VKI_MAP_NORESERVE 0x4000 /* don't check for reservations */ +#define VKI_MAP_FIXED_NOREPLACE 0x100000 /* fail EEXIST if fixed map fails */ //---------------------------------------------------------------------- // From linux-2.6.8.1/include/asm-i386/fcntl.h diff --git a/include/vki/vki-arm64-linux.h b/include/vki/vki-arm64-linux.h index 2fc97e614f..1b005c7750 100644 --- a/include/vki/vki-arm64-linux.h +++ b/include/vki/vki-arm64-linux.h @@ -215,6 +215,7 @@ struct vki_sigcontext { #define VKI_MAP_FIXED 0x10 /* Interpret addr exactly */ #define VKI_MAP_ANONYMOUS 0x20 /* don't use a file */ #define VKI_MAP_NORESERVE 0x4000 /* don't check for reservations */ +#define VKI_MAP_FIXED_NOREPLACE 0x100000 /* fail EEXIST if fixed map fails */ //---------------------------------------------------------------------- // From linux-3.10.5/uapi/include/asm-generic/fcntl.h diff --git a/include/vki/vki-mips32-linux.h b/include/vki/vki-mips32-linux.h index 2d752e2ccb..584b5dd727 100644 --- a/include/vki/vki-mips32-linux.h +++ b/include/vki/vki-mips32-linux.h @@ -300,6 +300,7 @@ struct vki_sigcontext { #define VKI_MAP_LOCKED 0x8000 /* pages are locked */ #define VKI_MAP_POPULATE 0x10000 /* populate (prefault) pagetables */ #define VKI_MAP_NONBLOCK 0x20000 /* do not block on IO */ +#define VKI_MAP_FIXED_NOREPLACE 0x100000 /* fail EEXIST if fixed map fails */ //---------------------------------------------------------------------- diff --git a/include/vki/vki-mips64-linux.h b/include/vki/vki-mips64-linux.h index 527b0dae63..9171b6fb0e 100644 --- a/include/vki/vki-mips64-linux.h +++ b/include/vki/vki-mips64-linux.h @@ -306,6 +306,7 @@ struct vki_sigcontext { #define VKI_MAP_LOCKED 0x8000 /* pages are locked */ #define VKI_MAP_POPULATE 0x10000 /* populate (prefault) pagetables */ #define VKI_MAP_NONBLOCK 0x20000 /* do not block on IO */ +#define VKI_MAP_FIXED_NOREPLACE 0x100000 /* fail EEXIST if fixed map fails */ //---------------------------------------------------------------------- // From linux-2.6.35.9/include/asm-mips/fcntl.h diff --git a/include/vki/vki-riscv64-linux.h b/include/vki/vki-riscv64-linux.h index 5cc98b6ab1..0ad826c02f 100644 --- a/include/vki/vki-riscv64-linux.h +++ b/include/vki/vki-riscv64-linux.h @@ -186,6 +186,7 @@ typedef struct vki_sigaltstack { //---------------------------------------------------------------------- #define VKI_MAP_NORESERVE 0x4000 /* don't check for reservations */ +#define VKI_MAP_FIXED_NOREPLACE 0x100000 /* fail EEXIST if fixed map fails */ //---------------------------------------------------------------------- // From linux-6.0/include/uapi/linux/mman.h diff --git a/include/vki/vki-x86-linux.h b/include/vki/vki-x86-linux.h index 5a5f9e5d82..d00de22b41 100644 --- a/include/vki/vki-x86-linux.h +++ b/include/vki/vki-x86-linux.h @@ -271,6 +271,7 @@ struct vki_sigcontext { #define VKI_MAP_FIXED 0x10 /* Interpret addr exactly */ #define VKI_MAP_ANONYMOUS 0x20 /* don't use a file */ #define VKI_MAP_NORESERVE 0x4000 /* don't check for reservations */ +#define VKI_MAP_FIXED_NOREPLACE 0x100000 /* fail EEXIST if fixed map fails */ //---------------------------------------------------------------------- // From linux-2.6.8.1/include/asm-i386/fcntl.h |
From: Mark W. <ma...@so...> - 2025-07-14 22:26:26
|
https://sourceware.org/cgit/valgrind/commit/?id=969bccaaca7aab2614def013ac1f37de37fbce86 commit 969bccaaca7aab2614def013ac1f37de37fbce86 Author: Mark Wielaard <ma...@kl...> Date: Tue Jul 15 00:00:44 2025 +0200 Handle SIGSYS and SIGSTKFLT when defined Both signals were already partially handled. But calculate_SKSS_from_SCSS only handled SIGSYS on freebsd. default_action didn't handle SIGSTKFLT. And sync_signalhandler didn't expect to have to handle SIGSYS. This fixes LTP tests kill11 and waitpid01. https://bugs.kde.org/show_bug.cgi?id=506890 Diff: --- coregrind/m_signals.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/coregrind/m_signals.c b/coregrind/m_signals.c index cccbb56832..523f4d7fcb 100644 --- a/coregrind/m_signals.c +++ b/coregrind/m_signals.c @@ -855,7 +855,7 @@ void calculate_SKSS_from_SCSS ( SKSS* dst ) case VKI_SIGFPE: case VKI_SIGILL: case VKI_SIGTRAP: -#if defined(VGO_freebsd) +#if defined(VKI_SIGSYS) case VKI_SIGSYS: #endif /* For these, we always want to catch them and report, even @@ -1832,6 +1832,9 @@ static void default_action(const vki_siginfo_t *info, ThreadId tid) case VKI_SIGPIPE: /* term */ case VKI_SIGALRM: /* term */ case VKI_SIGTERM: /* term */ +# if defined(VKI_SIGSTKFLT) + case VKI_SIGSTKFLT: /* term */ +# endif case VKI_SIGUSR1: /* term */ case VKI_SIGUSR2: /* term */ case VKI_SIGIO: /* term */ @@ -3004,6 +3007,9 @@ void sync_signalhandler ( Int sigNo, || sigNo == VKI_SIGBUS || sigNo == VKI_SIGFPE || sigNo == VKI_SIGILL +#if defined(VKI_SIGSYS) + || sigNo == VKI_SIGSYS +#endif || sigNo == VKI_SIGTRAP); info->si_code = sanitize_si_code(info->si_code); |
From: Mark W. <ma...@so...> - 2025-07-14 21:37:02
|
https://sourceware.org/cgit/valgrind/commit/?id=806abab0557a53546d9498926f699fd679b9f0f1 commit 806abab0557a53546d9498926f699fd679b9f0f1 Author: Mark Wielaard <ma...@kl...> Date: Mon Jul 14 23:23:23 2025 +0200 Reject any attempt to set the handler for SIGKILL/STOP Even though resetting SIGKILL or SIGSTOP to SIG_DFL would be a noop it isn't allowed. Just always return EINVAL if an attempt is made to set the signal handler for SIGKILL or SIGSTOP. There is an LTP test for this signal01. https://bugs.kde.org/show_bug.cgi?id=506930 Diff: --- NEWS | 1 + coregrind/m_signals.c | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index 73488cbc17..49403da013 100644 --- a/NEWS +++ b/NEWS @@ -54,6 +54,7 @@ are not entered into bugzilla tend to get forgotten about or ignored. 502968 Wrap linux specific syscalls 457 (listmount) and 458 (statmount) 506499 Unhandled syscall 592 (exterrctl - FreeBSD 506795 Better report which clone flags are problematic +506930 valgrind allows SIGKILL being reset to SIG_DFL To see details of a given bug, visit https://bugs.kde.org/show_bug.cgi?id=XXXXXX diff --git a/coregrind/m_signals.c b/coregrind/m_signals.c index f0e6b8e7cf..cccbb56832 100644 --- a/coregrind/m_signals.c +++ b/coregrind/m_signals.c @@ -1317,10 +1317,8 @@ SysRes VG_(do_sys_sigaction) ( Int signo, || new_act->ksa_handler == VKI_SIG_IGN) ) goto bad_signo_reserved; - /* Reject attempts to set a handler (or set ignore) for SIGKILL. */ - if ( (signo == VKI_SIGKILL || signo == VKI_SIGSTOP) - && new_act - && new_act->ksa_handler != VKI_SIG_DFL) + /* Reject any attempt to set the handler for SIGKILL/STOP. */ + if ( (signo == VKI_SIGKILL || signo == VKI_SIGSTOP) && new_act ) goto bad_sigkill_or_sigstop; /* If the client supplied non-NULL old_act, copy the relevant SCSS |
From: Paul F. <pa...@so...> - 2025-07-14 18:49:13
|
https://sourceware.org/cgit/valgrind/commit/?id=2ddc8484eb7905b6badfe5288c375d38a06aae89 commit 2ddc8484eb7905b6badfe5288c375d38a06aae89 Author: Paul Floyd <pj...@wa...> Date: Mon Jul 14 20:48:34 2025 +0200 Solaris gitignore: wildcard diff files Diff: --- .gitignore | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 767b3044b7..69e182f757 100644 --- a/.gitignore +++ b/.gitignore @@ -1105,7 +1105,7 @@ /memcheck/tests/amd64-linux/Makefile.in # /memcheck/tests/amd64-solaris/ -/memcheck/tests/amd64-solaris/*.stderr.diff +/memcheck/tests/amd64-solaris/*.stderr.diff* /memcheck/tests/amd64-solaris/*.stderr.out /memcheck/tests/amd64-solaris/*.stdout.diff /memcheck/tests/amd64-solaris/*.stdout.out @@ -1274,7 +1274,7 @@ /memcheck/tests/s390x/vstrs # /memcheck/tests/solaris/ -/memcheck/tests/solaris/*.stderr.diff +/memcheck/tests/solaris/*.stderr.diff* /memcheck/tests/solaris/*.stderr.out /memcheck/tests/solaris/*.stdout.diff /memcheck/tests/solaris/*.stdout.out @@ -1392,7 +1392,7 @@ /memcheck/tests/x86-linux/shm # /memcheck/tests/x86-solaris/ -/memcheck/tests/x86-solaris/*.stderr.diff +/memcheck/tests/x86-solaris/*.stderr.diff* /memcheck/tests/x86-solaris/*.stderr.out /memcheck/tests/x86-solaris/*.stdout.diff /memcheck/tests/x86-solaris/*.stdout.out @@ -1793,11 +1793,11 @@ /none/tests/amd64-linux/map_32bits # /none/tests/amd64-solaris/ -/none/tests/amd64-solaris/*.stderr.diff +/none/tests/amd64-solaris/*.stderr.diff* /none/tests/amd64-solaris/*.stderr.out /none/tests/amd64-solaris/*.stdout.diff /none/tests/amd64-solaris/*.stdout.out -/none/tests/amd64-solaris/*.post.diff +/none/tests/amd64-solaris/*.post.diff* /none/tests/amd64-solaris/*.post.out /none/tests/amd64-solaris/.deps /none/tests/amd64-solaris/Makefile @@ -2434,11 +2434,11 @@ none/tests/freebsd/bug499212 /none/tests/x86-linux/sigcontext # /none/tests/x86-solaris/ -/none/tests/x86-solaris/*.stderr.diff +/none/tests/x86-solaris/*.stderr.diff* /none/tests/x86-solaris/*.stderr.out /none/tests/x86-solaris/*.stdout.diff /none/tests/x86-solaris/*.stdout.out -/none/tests/x86-solaris/*.post.diff +/none/tests/x86-solaris/*.post.diff* /none/tests/x86-solaris/*.post.out /none/tests/x86-solaris/.deps /none/tests/x86-solaris/Makefile |
From: Florian K. <fk...@so...> - 2025-07-14 16:33:06
|
https://sourceware.org/cgit/valgrind/commit/?id=ca10852231e27b430588c51c8d0d492e054f4f37 commit ca10852231e27b430588c51c8d0d492e054f4f37 Author: Florian Krohm <fl...@ei...> Date: Mon Jul 14 16:32:06 2025 +0000 Add folding for Iop_PopCount32/64 and Iop_CmpNEZ16 (BZ 506211) Part of fixing https://bugs.kde.org/show_bug.cgi?id=506211 Diff: --- VEX/priv/ir_opt.c | 42 +++++++++++++++++++++++++++++++++++++++++ none/tests/iropt-test/irops.tab | 6 +++--- none/tests/iropt-test/unary.c | 21 ++++++++++++++++++++- 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/VEX/priv/ir_opt.c b/VEX/priv/ir_opt.c index 52b8e09571..f0458cb285 100644 --- a/VEX/priv/ir_opt.c +++ b/VEX/priv/ir_opt.c @@ -1346,6 +1346,31 @@ static UInt fold_Clz32 ( UInt value ) return 0; } +/* Helpers for folding PopCount32/64. + https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan + As many iterations as 1-bits present. +*/ +static UInt fold_PopCount64 ( ULong value ) +{ + UInt count; + + for (count = 0; value != 0; ++count) { + value &= value - 1; // clear the least significant 1-bit + } + return count; +} + +static UInt fold_PopCount32 ( UInt value ) +{ + UInt count; + + for (count = 0; value != 0; ++count) { + value &= value - 1; // clear the least significant 1-bit + } + return count; +} + + /* V64 holds 8 summary-constant bits in V128/V256 style. Convert to the corresponding real constant. */ //XXX re-check this before use @@ -1604,6 +1629,12 @@ static IRExpr* fold_Expr_WRK ( IRExpr** env, IRExpr* e ) (0xFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U8) ))); break; + case Iop_CmpNEZ16: + e2 = IRExpr_Const(IRConst_U1(toBool( + 0 != + (0xFFFF & e->Iex.Unop.arg->Iex.Const.con->Ico.U16) + ))); + break; case Iop_CmpNEZ32: e2 = IRExpr_Const(IRConst_U1(toBool( 0 != @@ -1678,6 +1709,17 @@ static IRExpr* fold_Expr_WRK ( IRExpr** env, IRExpr* e ) break; } + case Iop_PopCount32: { + UInt u32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32; + e2 = IRExpr_Const(IRConst_U32(fold_PopCount32(u32))); + break; + } + case Iop_PopCount64: { + ULong u64 = e->Iex.Unop.arg->Iex.Const.con->Ico.U64; + e2 = IRExpr_Const(IRConst_U64(fold_PopCount64(u64))); + break; + } + /* For these vector ones, can't fold all cases, but at least do the most obvious one. Could do better here using summarise/desummarise of vector constants, but too diff --git a/none/tests/iropt-test/irops.tab b/none/tests/iropt-test/irops.tab index 45b0e728cc..e73ec46a87 100644 --- a/none/tests/iropt-test/irops.tab +++ b/none/tests/iropt-test/irops.tab @@ -80,7 +80,7 @@ // { OPNAME(128HIto64), Ity_I64, 1, Ity_I128, }, // 128 bit { OPNAME(CmpNEZ8), Ity_I1, 1, Ity_I8 }, -// { OPNAME(CmpNEZ16), Ity_I1, 1, Ity_I16 }, // no folding yet + { OPNAME(CmpNEZ16), Ity_I1, 1, Ity_I16 }, { OPNAME(CmpNEZ32), Ity_I1, 1, Ity_I32 }, { OPNAME(CmpNEZ64), Ity_I1, 1, Ity_I64 }, @@ -104,8 +104,8 @@ // { OPNAME(CtzNat32), Ity_I32, 1, Ity_I32 }, // no folding yet // { OPNAME(CtzNat64), Ity_I64, 1, Ity_I64 }, // no folding yet -// { OPNAME(PopCount32), Ity_I32, 1, Ity_I32 }, // no folding yet -// { OPNAME(PopCount64), Ity_I64, 1, Ity_I64 }, // no folding yet + { OPNAME(PopCount32), Ity_I32, 1, Ity_I32 }, + { OPNAME(PopCount64), Ity_I64, 1, Ity_I64 }, diff --git a/none/tests/iropt-test/unary.c b/none/tests/iropt-test/unary.c index 537c29a723..44af3203dd 100644 --- a/none/tests/iropt-test/unary.c +++ b/none/tests/iropt-test/unary.c @@ -29,6 +29,7 @@ static void check_result(const irop_t *, const test_data_t *); static void run_tests(const irop_t *, test_data_t *, unsigned, uint64_t *); static uint64_t left(uint64_t, unsigned); +static uint32_t popcount(uint64_t); void @@ -181,7 +182,7 @@ check_result(const irop_t *op, const test_data_t *data) case Iop_64HIto32: expected = opnd >> 32; break; case Iop_CmpNEZ8: -// case Iop_CmpNEZ16: + case Iop_CmpNEZ16: case Iop_CmpNEZ32: case Iop_CmpNEZ64: expected = opnd != 0; @@ -195,6 +196,11 @@ check_result(const irop_t *op, const test_data_t *data) case Iop_Left32: expected = left(opnd, 32); break; case Iop_Left64: expected = left(opnd, 64); break; + case Iop_PopCount32: + case Iop_PopCount64: + expected = popcount(opnd); + break; + default: panic("%s: operator %s not handled\n", __func__, op->name); } @@ -250,3 +256,16 @@ left(uint64_t val, unsigned width) panic(__func__); } } + + +/* Naive implementation of counting 1-bits */ +static uint32_t +popcount(uint64_t value) +{ + uint32_t count; + + for (count = 0; value != 0; value >>= 1) { + count += value & 1; + } + return count; +} |
From: Florian K. <fk...@so...> - 2025-07-14 13:12:14
|
https://sourceware.org/cgit/valgrind/commit/?id=1831258a9ec588dd921327d56708e93a08456f32 commit 1831258a9ec588dd921327d56708e93a08456f32 Author: Florian Krohm <fl...@ei...> Date: Mon Jul 14 13:11:01 2025 +0000 Enable folding for Iop_Left8/16 In iropt-test add independent implementation of the "Left" operator for checking purposes. Diff: --- VEX/priv/ir_opt.c | 16 ++++++++++++++ none/tests/iropt-test/irops.tab | 4 ++-- none/tests/iropt-test/unary.c | 49 ++++++++++++++++++++++++++++++----------- 3 files changed, 54 insertions(+), 15 deletions(-) diff --git a/VEX/priv/ir_opt.c b/VEX/priv/ir_opt.c index 9a3f39c2c9..52b8e09571 100644 --- a/VEX/priv/ir_opt.c +++ b/VEX/priv/ir_opt.c @@ -1633,6 +1633,22 @@ static IRExpr* fold_Expr_WRK ( IRExpr** env, IRExpr* e ) break; } + case Iop_Left8: { + UChar u8 = e->Iex.Unop.arg->Iex.Const.con->Ico.U8; + Char s8 = (Char)(u8 & 0xFF); + s8 = (s8 | (-s8)); + e2 = IRExpr_Const( IRConst_U8( (UChar)s8 )); + break; + } + + case Iop_Left16: { + UShort u16 = e->Iex.Unop.arg->Iex.Const.con->Ico.U16; + Short s16 = (Short)(u16 & 0xFFFF); + s16 = (s16 | (-s16)); + e2 = IRExpr_Const( IRConst_U16( (UShort)s16 )); + break; + } + case Iop_Left32: { UInt u32 = e->Iex.Unop.arg->Iex.Const.con->Ico.U32; Int s32 = (Int)(u32 & 0xFFFFFFFF); diff --git a/none/tests/iropt-test/irops.tab b/none/tests/iropt-test/irops.tab index b22434dab1..45b0e728cc 100644 --- a/none/tests/iropt-test/irops.tab +++ b/none/tests/iropt-test/irops.tab @@ -87,8 +87,8 @@ { OPNAME(CmpwNEZ32), Ity_I32, 1, Ity_I32 }, { OPNAME(CmpwNEZ64), Ity_I64, 1, Ity_I64 }, -// { OPNAME(Left8), Ity_I8, 1, Ity_I8 }, // no folding yet -// { OPNAME(Left16), Ity_I16, 1, Ity_I16 }, // no folding yet + { OPNAME(Left8), Ity_I8, 1, Ity_I8 }, + { OPNAME(Left16), Ity_I16, 1, Ity_I16 }, { OPNAME(Left32), Ity_I32, 1, Ity_I32 }, { OPNAME(Left64), Ity_I64, 1, Ity_I64 }, diff --git a/none/tests/iropt-test/unary.c b/none/tests/iropt-test/unary.c index 51ad51505b..537c29a723 100644 --- a/none/tests/iropt-test/unary.c +++ b/none/tests/iropt-test/unary.c @@ -28,6 +28,7 @@ static void check_result(const irop_t *, const test_data_t *); static void run_tests(const irop_t *, test_data_t *, unsigned, uint64_t *); +static uint64_t left(uint64_t, unsigned); void @@ -189,19 +190,10 @@ check_result(const irop_t *op, const test_data_t *data) case Iop_CmpwNEZ32: expected = opnd == 0 ? 0 : UINT32_MAX; break; case Iop_CmpwNEZ64: expected = opnd == 0 ? 0 : UINT64_MAX; break; -// case Iop_Left8: -// case Iop_Left16: - case Iop_Left32: { - int32_t opnd_s = (int32_t)opnd; - expected = (opnd_s | -opnd_s) & UINT32_MAX; - break; - } - - case Iop_Left64: { - int64_t opnd_s = (int64_t)opnd; - expected = (opnd_s | -opnd_s) & UINT64_MAX; - break; - } + case Iop_Left8: expected = left(opnd, 8); break; + case Iop_Left16: expected = left(opnd, 16); break; + case Iop_Left32: expected = left(opnd, 32); break; + case Iop_Left64: expected = left(opnd, 64); break; default: panic("%s: operator %s not handled\n", __func__, op->name); @@ -227,3 +219,34 @@ check_result(const irop_t *op, const test_data_t *data) if (! ok) complain(op, data, expected); } + + +/* An implementation for Iop_Left/8/16/32/64. + The semantics of those operators are defined in Section 2.5 of + https://valgrind.org/docs/memcheck2005.pdf as follows: + + Iop_Left(v) is the same as v, except that all bits to the left of the + rightmost 1-bit in v are set. */ +static uint64_t +left(uint64_t val, unsigned width) +{ + uint64_t ret = 0; + + /* Find the rightmost 1-bit, then sign-extend. */ + for (unsigned bit = 0; bit < width; ++bit) { + if (val & ((uint64_t)1 << bit)) { + ret = (int64_t)((uint64_t)val << (63 - bit)) >> (63 - bit); + break; + } + } + + /* Truncate to desired width */ + switch (width) { + case 8: return ret & UINT8_MAX; + case 16: return ret & UINT16_MAX; + case 32: return ret & UINT32_MAX; + case 64: return ret & UINT64_MAX; + default: + panic(__func__); + } +} |
From: Florian K. <fk...@so...> - 2025-07-14 10:22:18
|
https://sourceware.org/cgit/valgrind/commit/?id=e2029bca2b45470a084f2ac4c3e1e3d07cd4c99e commit e2029bca2b45470a084f2ac4c3e1e3d07cd4c99e Author: Florian Krohm <fl...@ei...> Date: Mon Jul 14 10:21:44 2025 +0000 iropt-test: Reorder IROps. Diff: --- none/tests/iropt-test/irops.tab | 58 +++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/none/tests/iropt-test/irops.tab b/none/tests/iropt-test/irops.tab index a849289cdd..b22434dab1 100644 --- a/none/tests/iropt-test/irops.tab +++ b/none/tests/iropt-test/irops.tab @@ -79,6 +79,36 @@ // { OPNAME(128to64), Ity_I64, 1, Ity_I128, }, // 128 bit // { OPNAME(128HIto64), Ity_I64, 1, Ity_I128, }, // 128 bit + { OPNAME(CmpNEZ8), Ity_I1, 1, Ity_I8 }, +// { OPNAME(CmpNEZ16), Ity_I1, 1, Ity_I16 }, // no folding yet + { OPNAME(CmpNEZ32), Ity_I1, 1, Ity_I32 }, + { OPNAME(CmpNEZ64), Ity_I1, 1, Ity_I64 }, + + { OPNAME(CmpwNEZ32), Ity_I32, 1, Ity_I32 }, + { OPNAME(CmpwNEZ64), Ity_I64, 1, Ity_I64 }, + +// { OPNAME(Left8), Ity_I8, 1, Ity_I8 }, // no folding yet +// { OPNAME(Left16), Ity_I16, 1, Ity_I16 }, // no folding yet + { OPNAME(Left32), Ity_I32, 1, Ity_I32 }, + { OPNAME(Left64), Ity_I64, 1, Ity_I64 }, + +// { OPNAME(Clz32), Ity_I32, 1, Ity_I32 }, // deprecated, undefined behaviour +// { OPNAME(Clz64), Ity_I64, 1, Ity_I64 }, // deprecated, undefined behaviour + +// { OPNAME(Ctz32), Ity_I32, 1, Ity_I32 }, // deprecated, undefined behaviour +// { OPNAME(Ctz64), Ity_I64, 1, Ity_I64 }, // deprecated, undefined behaviour + +// { OPNAME(ClzNat32), Ity_I32, 1, Ity_I32 }, // no folding yet +// { OPNAME(ClzNat64), Ity_I64, 1, Ity_I64 }, // no folding yet + +// { OPNAME(CtzNat32), Ity_I32, 1, Ity_I32 }, // no folding yet +// { OPNAME(CtzNat64), Ity_I64, 1, Ity_I64 }, // no folding yet + +// { OPNAME(PopCount32), Ity_I32, 1, Ity_I32 }, // no folding yet +// { OPNAME(PopCount64), Ity_I64, 1, Ity_I64 }, // no folding yet + + + // BINARY { OPNAME(Add8), Ity_I8, 2, Ity_I8, Ity_I8 }, // { OPNAME(Add16), Ity_I16, 2, Ity_I16, Ity_I16 }, // no folding yet @@ -210,36 +240,8 @@ { OPNAME(CmpORD32S), Ity_I32, 2, Ity_I32, Ity_I32 }, // { OPNAME(CmpORD64S), Ity_I64, 2, Ity_I64, Ity_I64 }, // no folding yet - { OPNAME(CmpNEZ8), Ity_I1, 1, Ity_I8 }, -// { OPNAME(CmpNEZ16), Ity_I1, 1, Ity_I16 }, // no folding yet - { OPNAME(CmpNEZ32), Ity_I1, 1, Ity_I32 }, - { OPNAME(CmpNEZ64), Ity_I1, 1, Ity_I64 }, - - { OPNAME(CmpwNEZ32), Ity_I32, 1, Ity_I32 }, - { OPNAME(CmpwNEZ64), Ity_I64, 1, Ity_I64 }, - -// { OPNAME(Left8), Ity_I8, 1, Ity_I8 }, // no folding yet -// { OPNAME(Left16), Ity_I16, 1, Ity_I16 }, // no folding yet - { OPNAME(Left32), Ity_I32, 1, Ity_I32 }, - { OPNAME(Left64), Ity_I64, 1, Ity_I64 }, - { OPNAME(Max32U), Ity_I32, 2, Ity_I32, Ity_I32 }, -// { OPNAME(Clz32), Ity_I32, 1, Ity_I32 }, // deprecated, undefined behaviour -// { OPNAME(Clz64), Ity_I64, 1, Ity_I64 }, // deprecated, undefined behaviour - -// { OPNAME(Ctz32), Ity_I32, 1, Ity_I32 }, // deprecated, undefined behaviour -// { OPNAME(Ctz64), Ity_I64, 1, Ity_I64 }, // deprecated, undefined behaviour - -// { OPNAME(ClzNat32), Ity_I32, 1, Ity_I32 }, // no folding yet -// { OPNAME(ClzNat64), Ity_I64, 1, Ity_I64 }, // no folding yet - -// { OPNAME(CtzNat32), Ity_I32, 1, Ity_I32 }, // no folding yet -// { OPNAME(CtzNat64), Ity_I64, 1, Ity_I64 }, // no folding yet - -// { OPNAME(PopCount32), Ity_I32, 1, Ity_I32 }, // no folding yet -// { OPNAME(PopCount64), Ity_I64, 1, Ity_I64 }, // no folding yet - // { OPNAME(8HLto16), Ity_I16, 2, Ity_I8, Ity_I8 }, // no folding yet // { OPNAME(16HLto32), Ity_I32, 2, Ity_I16, Ity_I16 }, // no folding yet { OPNAME(32HLto64), Ity_I64, 2, Ity_I32, Ity_I32 }, |
From: Paul F. <pa...@so...> - 2025-07-14 09:43:12
|
https://sourceware.org/cgit/valgrind/commit/?id=5e119bbb53d3a7f7a64d6368624594d9da4f82bb commit 5e119bbb53d3a7f7a64d6368624594d9da4f82bb Author: Paul Floyd <pj...@wa...> Date: Mon Jul 14 11:42:28 2025 +0200 Add VEX/useful/vec to gitignore Diff: --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 19c2a9300d..767b3044b7 100644 --- a/.gitignore +++ b/.gitignore @@ -2525,6 +2525,9 @@ none/tests/freebsd/bug499212 # /VEX/switchback/ /VEX/switchback/switchback +# /VEX/useful/ +/VEX/useful/vex + *.vgtest*.trs *.vgtest*.log /test-suite-overall.log |
From: Julian S. <jse...@gm...> - 2025-07-14 04:23:39
|
On 13/07/2025 22:52, Florian Krohm wrote: > What is the semantics of Iop_Left32 and friends? It and its friends are described in Section 2.5 of https://valgrind.org/docs/memcheck2005.pdf. Note that some parts of the paper are (very) out of date. J |
From: Eliot M. <mo...@cs...> - 2025-07-13 21:49:07
|
On 7/13/2025 4:52 PM, Florian Krohm wrote: > What is the semantics of Iop_Left32 and friends? > > In libvex_ir.h it says: \x -> x | -x > which is not descriptive at all. > I could simply copy that formula over and use in the constant folding checker. > But by doing so it is impossible to find any bugs - be it in VEX's fold_expr or in the checker program. So I want to > write my own implementation of that IROp. > Can't do without a spec... > > I took a guess and thought that "left" perhaps meant to left-propagate the left-most "1" bit. E.g. 00000101 --> 11111101 > But that's not it.. In fact for every odd integer the result has all bits set. This appears to take the least significant 1 bit and propagate it to the left. Seems related to x & -x, which isolates the least significant 1 bit. Regards - Eliot Moss |
From: Florian K. <fl...@ei...> - 2025-07-13 20:52:48
|
What is the semantics of Iop_Left32 and friends? In libvex_ir.h it says: \x -> x | -x which is not descriptive at all. I could simply copy that formula over and use in the constant folding checker. But by doing so it is impossible to find any bugs - be it in VEX's fold_expr or in the checker program. So I want to write my own implementation of that IROp. Can't do without a spec... I took a guess and thought that "left" perhaps meant to left-propagate the left-most "1" bit. E.g. 00000101 --> 11111101 But that's not it.. In fact for every odd integer the result has all bits set. Before I pester Julian .... Anybody knows anything? Thanks, Florian |
From: Paul F. <pa...@so...> - 2025-07-13 08:48:02
|
https://sourceware.org/cgit/valgrind/commit/?id=a223c042d48601381e8045ab13fb9ab3396a3545 commit a223c042d48601381e8045ab13fb9ab3396a3545 Author: Paul Floyd <pj...@wa...> Date: Sun Jul 13 10:47:04 2025 +0200 Reformat wcpncpy in vg_replace_strmem.c Diff: --- shared/vg_replace_strmem.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/shared/vg_replace_strmem.c b/shared/vg_replace_strmem.c index 71f15c85fb..6fed7a2f21 100644 --- a/shared/vg_replace_strmem.c +++ b/shared/vg_replace_strmem.c @@ -2386,9 +2386,9 @@ static inline void my_exit ( int x ) /*---------------------- wcpncpy ----------------------*/ - // This is a wchar_t equivalent to strncpy. We don't - // have wchar_t available here, but in the GNU C Library - // wchar_t is always 32 bits wide. + // This is a wchar_t equivalent to strncpy. We don't + // have wchar_t available here, but in the GNU C Library + // wchar_t is always 32 bits wide. #define WCPNCPY(soname, fnname) \ Int* VG_REPLACE_FUNCTION_EZU(20500,soname,fnname) \ @@ -2420,7 +2420,7 @@ static inline void my_exit ( int x ) *dst++ = 0; \ } \ \ - return dst_orig + (src - src_orig); \ + return dst_orig + (src - src_orig); \ } #if defined(VGO_linux) || defined(VGO_freebsd) || defined(VGO_solaris) |
From: Mark W. <ma...@so...> - 2025-07-12 22:33:34
|
https://sourceware.org/cgit/valgrind/commit/?id=b72dac4e4c0f52e0074794aa91464b54ddf87d77 commit b72dac4e4c0f52e0074794aa91464b54ddf87d77 Author: Mark Wielaard <ma...@kl...> Date: Sun Jul 13 00:31:26 2025 +0200 ltp-excludes.txt: Add tests that use unsupported clone flags Add clone08, close_range02 and kcmp03. Diff: --- auxprogs/ltp-excludes.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/auxprogs/ltp-excludes.txt b/auxprogs/ltp-excludes.txt index 3b52dab8c7..b03111e20d 100644 --- a/auxprogs/ltp-excludes.txt +++ b/auxprogs/ltp-excludes.txt @@ -24,3 +24,8 @@ fcntl34 fcntl34_64 fcntl36 fcntl36_64 +# Tests fail because valgrind only supports a limited number +# of clone flags. +clone08 +close_range02 +kcmp03 |
From: Paul F. <pa...@so...> - 2025-07-12 20:26:08
|
https://sourceware.org/cgit/valgrind/commit/?id=36e090c39cbacf34425e199e77691c4e9d708fc2 commit 36e090c39cbacf34425e199e77691c4e9d708fc2 Author: Paul Floyd <pj...@wa...> Date: Sat Jul 12 22:23:05 2025 +0200 Bug 506499 - Unhandled syscall 592 (exterrctl - FreeBSD) Also add wrapers for inotify_add_watch_at and inotify_rm_watch No specific tests for these yet. Diff: --- NEWS | 1 + coregrind/m_syswrap/priv_syswrap-freebsd.h | 4 ++ coregrind/m_syswrap/syswrap-freebsd.c | 56 ++++++++++++++++++++++++++-- include/vki/vki-scnums-freebsd.h | 4 ++ memcheck/tests/freebsd/scalar.c | 53 ++++++++++++++++++++++++++ memcheck/tests/freebsd/scalar.stderr.exp | 41 ++++++++++++++++++++ memcheck/tests/freebsd/scalar.stderr.exp-x86 | 41 ++++++++++++++++++++ 7 files changed, 196 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index ce162cb18c..73488cbc17 100644 --- a/NEWS +++ b/NEWS @@ -52,6 +52,7 @@ are not entered into bugzilla tend to get forgotten about or ignored. AMD64_GET_TLSBASE 505228 Wrap linux specific mseal syscall 502968 Wrap linux specific syscalls 457 (listmount) and 458 (statmount) +506499 Unhandled syscall 592 (exterrctl - FreeBSD 506795 Better report which clone flags are problematic To see details of a given bug, visit diff --git a/coregrind/m_syswrap/priv_syswrap-freebsd.h b/coregrind/m_syswrap/priv_syswrap-freebsd.h index f8d404239d..f16831933e 100644 --- a/coregrind/m_syswrap/priv_syswrap-freebsd.h +++ b/coregrind/m_syswrap/priv_syswrap-freebsd.h @@ -543,6 +543,10 @@ DECL_TEMPLATE(freebsd, sys_getrlimitusage) // 589 DECL_TEMPLATE(freebsd, sys_fchroot) // 590 DECL_TEMPLATE(freebsd, sys_setcred) // 591 +DECL_TEMPLATE(freebsd, sys_exterrctl) // 592 +DECL_TEMPLATE(freebsd, sys_inotify_add_watch_at) // 593 +DECL_TEMPLATE(freebsd, sys_inotify_rm_watch) // 594 + DECL_TEMPLATE(freebsd, sys_fake_sigreturn) #endif // PRIV_SYSWRAP_FREEBSD_H diff --git a/coregrind/m_syswrap/syswrap-freebsd.c b/coregrind/m_syswrap/syswrap-freebsd.c index 4ce860976c..79e30f7d37 100644 --- a/coregrind/m_syswrap/syswrap-freebsd.c +++ b/coregrind/m_syswrap/syswrap-freebsd.c @@ -4864,8 +4864,8 @@ PRE(sys_kmq_notify) // int kmq_unlink(const char *path); PRE(sys_kmq_unlink) { - PRINT("sys_kmq_unlink ( %#" FMT_REGWORD "x(%s) )", ARG1,(char *)ARG1); - PRE_REG_READ1(int, "mq_unlink", const char *, name); + PRINT("sys_kmq_unlink ( %#" FMT_REGWORD "x(%s) )", ARG1,(HChar *)ARG1); + PRE_REG_READ1(int, "mq_unlink", const HChar *, name); PRE_MEM_RASCIIZ( "mq_unlink(name)", ARG1 ); } @@ -7054,7 +7054,7 @@ POST(sys_getrlimitusage) // int fchroot(int fd); PRE(sys_fchroot) { - PRINT("sys_fchroot(%ld)", ARG1); + PRINT("sys_fchroot(%" FMT_REGWORD "d)", ARG1); PRE_REG_READ1(int, "fchroot", int, fd); /* Be strict. */ @@ -7066,11 +7066,55 @@ PRE(sys_fchroot) // int setcred(u_int flags, const struct setcred *wcred, size_t size); PRE(sys_setcred) { - PRINT("sys_setcred(%ld, %#" FMT_REGWORD "x, %lu)", ARG1, ARG2, ARG3); + PRINT("sys_setcred(%" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "u)", ARG1, ARG2, ARG3); PRE_REG_READ3(int, "setcred", u_int, flags, const struct setcred*, wcred, size_t, size); PRE_MEM_READ("setcred(wcred)", ARG2, sizeof(struct vki_setcred)); } +// SYS_exterrctl +// int exterrctl(u_int op, u_int flags, _In_reads_bytes_(4) void *ptr +PRE(sys_exterrctl) +{ + PRINT("sys_exterrctl(%" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x)", + ARG1, ARG2, ARG3); + PRE_REG_READ3(int, "exterrctl", u_int, op, u_int, flags, void*, ptr); + // the void* points to struct uexterror which at the time of writing has 10 fields + // but this syscall just turns this feature on and off and it's only th first 4 bytes + // for the version that gets checked + PRE_MEM_READ("exterrctl(ptr)", ARG3, 4); +} + +// SYS_inotify_add_watch_at +// int inotify_add_watch_at(int fd, int dfd, _In_z_ const char *path, uint32_t mask); +PRE(sys_inotify_add_watch_at) +{ + PRINT("sys_inotify_add_watch_at(%" FMT_REGWORD "d, %" FMT_REGWORD "d, %" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x)", SARG1, SARG2, ARG3, (HChar*)ARG3, ARG4); + PRE_REG_READ4(int, "inotify_add_watch_at", int, fd, int, dfd, const char*, path, uint32_t, mask); + PRE_MEM_RASCIIZ("inotify_add_watch_at(path)", ARG3); + if (!ML_(fd_allowed)(ARG1, "inotify_add_watch_at", tid, False)) { + SET_STATUS_Failure( VKI_EBADF ); + } + if (ARG2 != VKI_AT_FDCWD) { + if (!ML_(fd_allowed)(ARG2, "inotify_add_watch_at", tid, False)) { + SET_STATUS_Failure( VKI_EBADF ); + } + } +} + +// SYS_inotify_rm_watch +// int inotify_rm_watch(int fd, int wd); +PRE(sys_inotify_rm_watch) +{ + PRINT("sys_inotify_rm_watch(%" FMT_REGWORD "d, %" FMT_REGWORD "d)", SARG1, SARG2); + PRE_REG_READ2(int, "sys_inotify_rm_watch", int, fd, int, wd); + if (!ML_(fd_allowed)(ARG1, "inotify_rm_watch", tid, False)) { + SET_STATUS_Failure( VKI_EBADF ); + } + // PJF I don't think that this can be AT_FDCWD + if (!ML_(fd_allowed)(ARG2, "inotify_rm_watch", tid, False)) { + SET_STATUS_Failure( VKI_EBADF ); + } +} #undef PRE #undef POST @@ -7768,6 +7812,10 @@ const SyscallTableEntry ML_(syscall_table)[] = { BSDX_(__NR_fchroot, sys_fchroot), // 590 BSDX_(__NR_setcred, sys_setcred), // 591 + BSDX_(__NR_exterrctl, sys_exterrctl), // 592 + BSDX_(__NR_inotify_add_watch_at, sys_inotify_add_watch_at), // 593 + BSDX_(__NR_inotify_rm_watch, sys_inotify_rm_watch), // 593 + BSDX_(__NR_fake_sigreturn, sys_fake_sigreturn), // 1000, fake sigreturn }; diff --git a/include/vki/vki-scnums-freebsd.h b/include/vki/vki-scnums-freebsd.h index a92abb9a15..a151402855 100644 --- a/include/vki/vki-scnums-freebsd.h +++ b/include/vki/vki-scnums-freebsd.h @@ -630,6 +630,10 @@ #define __NR_fchroot 590 #define __NR_setcred 591 +#define __NR_exterrctl 592 +#define __NR_inotify_add_watch_at 593 +#define __NR_inotify_rm_watch 594 + #define __NR_fake_sigreturn 1000 #endif /* VKI_UNISTD_FREEBSD_H */ diff --git a/memcheck/tests/freebsd/scalar.c b/memcheck/tests/freebsd/scalar.c index bae3d943bc..ce76ffdb21 100644 --- a/memcheck/tests/freebsd/scalar.c +++ b/memcheck/tests/freebsd/scalar.c @@ -2479,6 +2479,59 @@ int main(void) FAKE_SY("\n"); #endif +#if defined(SYS_exterrctl) + GO(SYS_exterrctl, "3s, 1m"); + SY(SYS_exterrctl, x0, x0+1, x0+1); +#else + FAKE_GO("592: SYS_exterrctl 3s, 1m"); + FAKE_SY("Syscall param exterrctl(op) contains uninitialised byte(s)\n"); + FAKE_SY(" ...\n"); + FAKE_SY("\n"); + FAKE_SY("Syscall param exterrctl(flags) contains uninitialised byte(s)\n"); + FAKE_SY(" ...\n"); + FAKE_SY("\n"); + FAKE_SY("Syscall param exterrctl(ptr) contains uninitialised byte(s)\n"); + FAKE_SY(" ...\n"); + FAKE_SY("\n"); + FAKE_SY("Syscall param exterrctl(ptr) points to unaddressable byte(s)\n"); + FAKE_SY(" ...\n"); + FAKE_SY("\ Address 0x........ is not stack'd, malloc'd or (recently) free'd\n"); + FAKE_SY("\n"); +#endif + +#if defined(SYS_inotify_add_watch_at) + GO(SYS_inotify_add_watch_at, "3s, 1m"); + SY(SYS_inotify_add_watch_at, x0, x0+1, x0+1); +#else + FAKE_GO("593:SYS_inotify_add_watch_at 3s, 1m"); + FAKE_SY("Syscall param inotify_add_watch_at(fd) contains uninitialised byte(s)\n"); + FAKE_SY(" ...\n"); + FAKE_SY("\n"); + FAKE_SY("Syscall param inotify_add_watch_at(dfd) contains uninitialised byte(s)\n"); + FAKE_SY(" ...\n"); + FAKE_SY("\n"); + FAKE_SY("Syscall param inotify_add_watch_at(path) contains uninitialised byte(s)\n"); + FAKE_SY(" ...\n"); + FAKE_SY("\n"); + FAKE_SY("Syscall param inotify_add_watch_at(path) points to unaddressable byte(s)\n"); + FAKE_SY(" ...\n"); + FAKE_SY(" Address 0x........ is not stack'd, malloc'd or (recently) free'd\n"); + FAKE_SY("\n"); +#endif + +#if defined(SYS_inotify_rm_watch) + GO(SYS_inotify_rm_watch, "2s, 0m"); + SY(SYS_inotify_rm_watch, x0+1000, x0+1000); +#else + FAKE_GO("594: SYS_inotify_rm_watch 2s, 0m"); + FAKE_SY("Syscall param sys_inotify_rm_watch(fd) contains uninitialised byte(s)\n"); + FAKE_SY(" ...\n"); + FAKE_SY("\n"); + FAKE_SY("Syscall param sys_inotify_rm_watch(wd) contains uninitialised byte(s)\n"); + FAKE_SY(" ...\n"); + FAKE_SY("\n"); +#endif + /* SYS_exit 1 */ GO(SYS_exit, "1s 0m"); SY(SYS_exit, x0); FAIL; diff --git a/memcheck/tests/freebsd/scalar.stderr.exp b/memcheck/tests/freebsd/scalar.stderr.exp index ae8adcd1b4..dbe79c6e84 100644 --- a/memcheck/tests/freebsd/scalar.stderr.exp +++ b/memcheck/tests/freebsd/scalar.stderr.exp @@ -5746,6 +5746,47 @@ Syscall param setcred(wcred) points to unaddressable byte(s) ... Address 0x........ is not stack'd, malloc'd or (recently) free'd +--------------------------------------------------------- +592: SYS_exterrctl 3s, 1m +--------------------------------------------------------- +Syscall param exterrctl(op) contains uninitialised byte(s) + ... + +Syscall param exterrctl(flags) contains uninitialised byte(s) + ... + +Syscall param exterrctl(ptr) contains uninitialised byte(s) + ... + +Syscall param exterrctl(ptr) points to unaddressable byte(s) + ... + Address 0x........ is not stack'd, malloc'd or (recently) free'd + +--------------------------------------------------------- +593:SYS_inotify_add_watch_at 3s, 1m +--------------------------------------------------------- +Syscall param inotify_add_watch_at(fd) contains uninitialised byte(s) + ... + +Syscall param inotify_add_watch_at(dfd) contains uninitialised byte(s) + ... + +Syscall param inotify_add_watch_at(path) contains uninitialised byte(s) + ... + +Syscall param inotify_add_watch_at(path) points to unaddressable byte(s) + ... + Address 0x........ is not stack'd, malloc'd or (recently) free'd + +--------------------------------------------------------- +594: SYS_inotify_rm_watch 2s, 0m +--------------------------------------------------------- +Syscall param sys_inotify_rm_watch(fd) contains uninitialised byte(s) + ... + +Syscall param sys_inotify_rm_watch(wd) contains uninitialised byte(s) + ... + --------------------------------------------------------- 1: SYS_exit 1s 0m --------------------------------------------------------- diff --git a/memcheck/tests/freebsd/scalar.stderr.exp-x86 b/memcheck/tests/freebsd/scalar.stderr.exp-x86 index 47beb3dcec..ea5abb9c61 100644 --- a/memcheck/tests/freebsd/scalar.stderr.exp-x86 +++ b/memcheck/tests/freebsd/scalar.stderr.exp-x86 @@ -5818,6 +5818,47 @@ Syscall param setcred(wcred) points to unaddressable byte(s) ... Address 0x........ is not stack'd, malloc'd or (recently) free'd +--------------------------------------------------------- +592: SYS_exterrctl 3s, 1m +--------------------------------------------------------- +Syscall param exterrctl(op) contains uninitialised byte(s) + ... + +Syscall param exterrctl(flags) contains uninitialised byte(s) + ... + +Syscall param exterrctl(ptr) contains uninitialised byte(s) + ... + +Syscall param exterrctl(ptr) points to unaddressable byte(s) + ... + Address 0x........ is not stack'd, malloc'd or (recently) free'd + +--------------------------------------------------------- +593:SYS_inotify_add_watch_at 3s, 1m +--------------------------------------------------------- +Syscall param inotify_add_watch_at(fd) contains uninitialised byte(s) + ... + +Syscall param inotify_add_watch_at(dfd) contains uninitialised byte(s) + ... + +Syscall param inotify_add_watch_at(path) contains uninitialised byte(s) + ... + +Syscall param inotify_add_watch_at(path) points to unaddressable byte(s) + ... + Address 0x........ is not stack'd, malloc'd or (recently) free'd + +--------------------------------------------------------- +594: SYS_inotify_rm_watch 2s, 0m +--------------------------------------------------------- +Syscall param sys_inotify_rm_watch(fd) contains uninitialised byte(s) + ... + +Syscall param sys_inotify_rm_watch(wd) contains uninitialised byte(s) + ... + --------------------------------------------------------- 1: SYS_exit 1s 0m --------------------------------------------------------- |
From: Paul F. <pa...@so...> - 2025-07-12 19:46:27
|
https://sourceware.org/cgit/valgrind/commit/?id=293a6f431fb4edde5fac64ff99671a208598f8e6 commit 293a6f431fb4edde5fac64ff99671a208598f8e6 Author: Paul Floyd <pj...@wa...> Date: Sat Jul 12 21:45:10 2025 +0200 FreeBSD regtest: more kenv churn Haste makes Waste. Filter was broken (and thererfore the expected not correct either). Diff: --- memcheck/tests/freebsd/filter_kenv | 2 +- memcheck/tests/freebsd/kenv.stderr.exp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/memcheck/tests/freebsd/filter_kenv b/memcheck/tests/freebsd/filter_kenv index c6bb6837a3..029d3c73f4 100755 --- a/memcheck/tests/freebsd/filter_kenv +++ b/memcheck/tests/freebsd/filter_kenv @@ -7,4 +7,4 @@ # on the FreeBSD version, so we want to filter the size of # KENV_DUMP allocation -gsed 's/4,765 bytes allocated/XXX bytes allocated' +gsed 's/ [^ ]* bytes allocated/ XXX bytes allocated/' diff --git a/memcheck/tests/freebsd/kenv.stderr.exp b/memcheck/tests/freebsd/kenv.stderr.exp index c356c7c833..faf3ccc8ab 100644 --- a/memcheck/tests/freebsd/kenv.stderr.exp +++ b/memcheck/tests/freebsd/kenv.stderr.exp @@ -46,7 +46,7 @@ Syscall param kenv(value) points to unaddressable byte(s) HEAP SUMMARY: in use at exit: 0 bytes in 0 blocks - total heap usage: 5 allocs, 5 frees, 4,765 bytes allocated + total heap usage: 5 allocs, 5 frees, XXX bytes allocated For a detailed leak analysis, rerun with: --leak-check=full |
From: Paul F. <pa...@so...> - 2025-07-12 18:32:38
|
https://sourceware.org/cgit/valgrind/commit/?id=13f376e083f6479a0028d91d076108779e332cd9 commit 13f376e083f6479a0028d91d076108779e332cd9 Author: Paul Floyd <pj...@wa...> Date: Sat Jul 12 20:31:31 2025 +0200 FreeBSD regtst: add filter for kenv test The size of the kernel environment depends on the FreeBSD version. So add a filter for the total of all alocations. Diff: --- memcheck/tests/freebsd/Makefile.am | 2 +- memcheck/tests/freebsd/filter_kenv | 10 ++++++++++ memcheck/tests/freebsd/kenv.vgtest | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/memcheck/tests/freebsd/Makefile.am b/memcheck/tests/freebsd/Makefile.am index 5608b77d5a..d96cde1b1b 100644 --- a/memcheck/tests/freebsd/Makefile.am +++ b/memcheck/tests/freebsd/Makefile.am @@ -4,7 +4,7 @@ include $(top_srcdir)/Makefile.tool-tests.am dist_noinst_SCRIPTS = filter_stderr filter_pts dump_stdout filter_sigwait \ filter_scalar filter_realpathat filter_fstat filter_eventfd2 \ toucher1 toucher2 filter_getfsstat filter_context filter_frame \ - filter_supp + filter_supp filter_kenv EXTRA_DIST = \ access.vgtest \ diff --git a/memcheck/tests/freebsd/filter_kenv b/memcheck/tests/freebsd/filter_kenv new file mode 100755 index 0000000000..c6bb6837a3 --- /dev/null +++ b/memcheck/tests/freebsd/filter_kenv @@ -0,0 +1,10 @@ +#! /bin/sh + +../filter_stderr "$@" | + +# want to run without -q to see invalid action message +# but the size of the kernel environment depends +# on the FreeBSD version, so we want to filter the size of +# KENV_DUMP allocation + +gsed 's/4,765 bytes allocated/XXX bytes allocated' diff --git a/memcheck/tests/freebsd/kenv.vgtest b/memcheck/tests/freebsd/kenv.vgtest index 763cd16a2a..5c54fefd5d 100644 --- a/memcheck/tests/freebsd/kenv.vgtest +++ b/memcheck/tests/freebsd/kenv.vgtest @@ -1 +1,2 @@ prog: kenv +stderr_filter: filter_kenv |
From: Paul F. <pa...@so...> - 2025-07-12 18:21:28
|
https://sourceware.org/cgit/valgrind/commit/?id=1e2300f192b24f8701a4793a28a07d1ca8aff05e commit 1e2300f192b24f8701a4793a28a07d1ca8aff05e Author: Paul Floyd <pj...@wa...> Date: Sat Jul 12 20:20:06 2025 +0200 FreeBSD regtest: small cleanup of kenv test Suppress uninitialised warning Remove res variable that was copied and pasted Diff: --- memcheck/tests/freebsd/Makefile.am | 1 + memcheck/tests/freebsd/kenv.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/memcheck/tests/freebsd/Makefile.am b/memcheck/tests/freebsd/Makefile.am index db1e2aca56..5608b77d5a 100644 --- a/memcheck/tests/freebsd/Makefile.am +++ b/memcheck/tests/freebsd/Makefile.am @@ -240,6 +240,7 @@ get_set_login_CFLAGS = ${AM_CFLAGS} @FLAG_W_NO_USE_AFTER_FREE@ getfh_CFLAGS = ${AM_CFLAGS} @FLAG_W_NO_USE_AFTER_FREE@ getfsstat_CFLAGS = ${AM_CFLAGS} @FLAG_W_NO_UNINITIALIZED@ @FLAG_W_NO_USE_AFTER_FREE@ kenv_SOURCES = kenv.cpp +kenv_CXXFLAGS = ${AM_CXXFLAGS} @FLAG_W_NO_UNINITIALIZED@ linkat_CFLAGS = ${AM_CFLAGS} @FLAG_W_NO_MAYBE_UNINITIALIZED@ @FLAG_W_NO_UNINITIALIZED@ @FLAG_W_NO_USE_AFTER_FREE@ memalign_CFLAGS = ${AM_CFLAGS} @FLAG_W_NO_NON_POWER_OF_TWO_ALIGNMENT@ misc_CFLAGS = ${AM_CFLAGS} @FLAG_W_NO_USE_AFTER_FREE@ diff --git a/memcheck/tests/freebsd/kenv.cpp b/memcheck/tests/freebsd/kenv.cpp index 5f029370f7..ed82161854 100644 --- a/memcheck/tests/freebsd/kenv.cpp +++ b/memcheck/tests/freebsd/kenv.cpp @@ -117,7 +117,7 @@ int main(int argc, char** argv) char* freeBuf{new char[32]}; delete [] freeBuf; kenv(KENV_GET, name.c_str(), freeBuf, 32); - int res{kenv(KENV_GET, name.c_str(), buf.get(), 2*bufSize)}; + kenv(KENV_GET, name.c_str(), buf.get(), 2*bufSize); } } |
From: Paul F. <pa...@so...> - 2025-07-12 14:22:32
|
https://sourceware.org/cgit/valgrind/commit/?id=7cbcd30804fc5fa412ae516ea05cbdb57ea8952a commit 7cbcd30804fc5fa412ae516ea05cbdb57ea8952a Author: Paul Floyd <pj...@wa...> Date: Sat Jul 12 16:21:29 2025 +0200 FreeBSD syscall: improve kenv wrapper and add a test for it Diff: --- .gitignore | 1 + coregrind/m_syswrap/syswrap-freebsd.c | 30 +++++-- include/vki/vki-freebsd.h | 10 ++- memcheck/tests/freebsd/Makefile.am | 4 + memcheck/tests/freebsd/kenv.cpp | 130 +++++++++++++++++++++++++++ memcheck/tests/freebsd/kenv.stderr.exp | 55 ++++++++++++ memcheck/tests/freebsd/kenv.vgtest | 1 + memcheck/tests/freebsd/scalar.stderr.exp | 11 ++- memcheck/tests/freebsd/scalar.stderr.exp-x86 | 11 ++- 9 files changed, 238 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index e4ddf5dc65..19c2a9300d 100644 --- a/.gitignore +++ b/.gitignore @@ -1445,6 +1445,7 @@ /memcheck/tests/freebsd/getrlimitusage /memcheck/tests/freebsd/inlinfo /memcheck/tests/freebsd/inlinfo_nested.so +/memcheck/tests/freebsd/kenv /memcheck/tests/freebsd/kqueue /memcheck/tests/freebsd/kqueuex /memcheck/tests/freebsd/linkat diff --git a/coregrind/m_syswrap/syswrap-freebsd.c b/coregrind/m_syswrap/syswrap-freebsd.c index e6e71c78d9..4ce860976c 100644 --- a/coregrind/m_syswrap/syswrap-freebsd.c +++ b/coregrind/m_syswrap/syswrap-freebsd.c @@ -3697,19 +3697,39 @@ PRE(sys_nmount) PRE(sys_kenv) { PRINT("sys_kenv ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,ARG2,ARG3,ARG4); - PRE_REG_READ4(int, "kenv", - int, action, const char *, name, char *, value, int, len); switch (ARG1) { case VKI_KENV_GET: + // read from arg1, write to arg2 + PRE_REG_READ4(int, "kenv", + int, action, const char *, name, char *, value, int, len); + PRE_MEM_RASCIIZ("kenv(name)", ARG2); + PRE_MEM_WRITE("kenv(value)", ARG3, ARG4); + break; case VKI_KENV_SET: + PRE_REG_READ3(int, "kenv", + int, action, const char *, name, char *, value); + PRE_MEM_RASCIIZ("kenv(name)", ARG2); + PRE_MEM_RASCIIZ("kenv(value)", ARG3); + break; case VKI_KENV_UNSET: + PRE_REG_READ2(int, "kenv", int, action, const char *, name); PRE_MEM_RASCIIZ("kenv(name)", ARG2); - /* FALLTHROUGH */ + break; case VKI_KENV_DUMP: + case VKI_KENV_DUMP_LOADER: + case VKI_KENV_DUMP_STATIC: + PRRSN; + PRA1("kenv",int,action); + // ARG2 name is ignored + PRA3("kenv",char*,value); + PRA4("kenv",int,len); + if (ARG3) { + PRE_MEM_WRITE("kenv(value)", ARG3, ARG4); + } break; default: if (VG_(clo_verbosity) >= 1) { - VG_(umsg)("Warning: unimplemented kenv action: %" FMT_REGWORD "d\n", + VG_(umsg)("Warning: bad or unimplemented kenv action: %" FMT_REGWORD "d\n", ARG1); } break; @@ -3724,7 +3744,7 @@ POST(sys_kenv) POST_MEM_WRITE(ARG3, ARG4); break; case VKI_KENV_DUMP: - if (ARG3 != (Addr)NULL) { + if (ARG3) { POST_MEM_WRITE(ARG3, ARG4); } break; diff --git a/include/vki/vki-freebsd.h b/include/vki/vki-freebsd.h index 6be56c27ad..63ffbe7e5e 100644 --- a/include/vki/vki-freebsd.h +++ b/include/vki/vki-freebsd.h @@ -2228,10 +2228,12 @@ struct vki_kinfo_file { //---------------------------------------------------------------------- // From sys/kenv.h //---------------------------------------------------------------------- -#define VKI_KENV_GET 0 -#define VKI_KENV_SET 1 -#define VKI_KENV_UNSET 2 -#define VKI_KENV_DUMP 3 +#define VKI_KENV_GET 0 +#define VKI_KENV_SET 1 +#define VKI_KENV_UNSET 2 +#define VKI_KENV_DUMP 3 +#define VKI_KENV_DUMP_LOADER 4 +#define VKI_KENV_DUMP_STATIC 5 //---------------------------------------------------------------------- // From sys/sysctl.h (and related) diff --git a/memcheck/tests/freebsd/Makefile.am b/memcheck/tests/freebsd/Makefile.am index 091d056785..db1e2aca56 100644 --- a/memcheck/tests/freebsd/Makefile.am +++ b/memcheck/tests/freebsd/Makefile.am @@ -70,6 +70,8 @@ EXTRA_DIST = \ getfsstat.supp \ getfsstat.stderr.exp-x86 \ getrlimitusage.vgtest getrlimitusage.stderr.exp \ + kenv.vgtest \ + kenv.stderr.exp \ kqueue.vgtest \ kqueue.stderr.exp \ kqueue.stdout.exp \ @@ -156,6 +158,7 @@ check_PROGRAMS = \ fexecve \ file_locking_wait6 \ get_set_context get_set_login getfh \ + kenv \ kqueue linkat memalign misc \ openpty \ pdfork_pdkill getfsstat inlinfo inlinfo_nested.so \ @@ -236,6 +239,7 @@ extattr_CFLAGS = ${AM_CFLAGS} @FLAG_W_NO_UNUSED_BUT_SET_VARIABLE@ @FLAG_W_NO_U get_set_login_CFLAGS = ${AM_CFLAGS} @FLAG_W_NO_USE_AFTER_FREE@ getfh_CFLAGS = ${AM_CFLAGS} @FLAG_W_NO_USE_AFTER_FREE@ getfsstat_CFLAGS = ${AM_CFLAGS} @FLAG_W_NO_UNINITIALIZED@ @FLAG_W_NO_USE_AFTER_FREE@ +kenv_SOURCES = kenv.cpp linkat_CFLAGS = ${AM_CFLAGS} @FLAG_W_NO_MAYBE_UNINITIALIZED@ @FLAG_W_NO_UNINITIALIZED@ @FLAG_W_NO_USE_AFTER_FREE@ memalign_CFLAGS = ${AM_CFLAGS} @FLAG_W_NO_NON_POWER_OF_TWO_ALIGNMENT@ misc_CFLAGS = ${AM_CFLAGS} @FLAG_W_NO_USE_AFTER_FREE@ diff --git a/memcheck/tests/freebsd/kenv.cpp b/memcheck/tests/freebsd/kenv.cpp new file mode 100644 index 0000000000..5f029370f7 --- /dev/null +++ b/memcheck/tests/freebsd/kenv.cpp @@ -0,0 +1,130 @@ +#include <iostream> +#include <sstream> +#include <string> +#include <exception> +#include <cerrno> +#include <kenv.h> +#include <unistd.h> + +static long x0; + +int main(int argc, char** argv) +{ + long *px{static_cast<long*>(malloc(2*sizeof(long)))}; + x0 = px[0]; + try + { + const size_t bufSize{1024}; + auto buf{std::make_unique<char[]>(bufSize)}; + std::string name{"bootfile"}; + int res{kenv(KENV_GET, name.c_str(), buf.get(), bufSize)}; + + if (res == -1) + { + throw std::runtime_error("kenv get non-root"); + } + + if (argc > 1) + { + std::cout << buf << '\n'; + } + + res = kenv(42*42, name.c_str(), buf.get(), bufSize); + if (res == 0) + { + throw std::runtime_error("kenv get bogus action succeeded"); + } + if (errno != EINVAL) + { + std::stringstream ss; + ss << "kenv get bogus action wrong errno, expected " << EINVAL << " got " << errno; + throw std::runtime_error(ss.str()); + } + + res = kenv(KENV_GET, "zyxxy", buf.get(), bufSize); + if (res == 0) + { + throw std::runtime_error("kenv get bogus name succeeded"); + } + if (errno != ENOENT) + { + std::stringstream ss; + ss << "kenv get bogus name wrong errno, expected " << ENOENT << " got " << errno; + throw std::runtime_error(ss.str()); + } + + res = kenv(KENV_DUMP, "this does not matter", nullptr, -1); + if (res == -1) + { + throw std::runtime_error("kenv dump to get size non-root"); + } + if (argc > 1) + { + std::cout << "dump size " << res << '\n'; + } + auto dump_buf{std::make_unique<char[]>(res)}; + char* uninitCharStar; + res = kenv(KENV_DUMP, uninitCharStar, dump_buf.get(), res); + + if (argc > 1) + { + // the buffer contains nul separated eleements, this will just print the first + std::cout << dump_buf << '\n'; + } + + if (0 == geteuid()) + { + res = kenv(KENV_SET, "this", const_cast<char*>("that"), 5); + if (res == -1) + { + throw std::runtime_error("kenv set root"); + } + res = kenv(KENV_SET, "this", const_cast<char*>("thing"), 6); + if (res == -1) + { + throw std::runtime_error("kenv set root"); + } + res = kenv(KENV_UNSET, "this", const_cast<char*>("yes we have no bananas"), 42); + if (res == -1) + { + throw std::runtime_error("kenv set root"); + } + } + else + { + // now try some things that will fail + int uninitInt; + res = kenv(KENV_SET, "this", const_cast<char*>("that"), uninitInt); + if (res != -1) + { + throw std::runtime_error("kenv set non-root succeeded"); + } + if (errno != EPERM) + { + std::stringstream ss; + ss << "kenv get bogus action wrong errno, expected " << EPERM << " got " << errno; + throw std::runtime_error(ss.str()); + } + + // checks all the args + kenv(KENV_GET+x0, name.c_str()+x0, buf.get()+x0, 1024+x0); + + // now some memory errors + char* freeName{new char[32]}; + sprintf(freeName, "%s", "blah"); + delete [] freeName; + kenv(KENV_GET, freeName, buf.get(), 32); + char* freeBuf{new char[32]}; + delete [] freeBuf; + kenv(KENV_GET, name.c_str(), freeBuf, 32); + int res{kenv(KENV_GET, name.c_str(), buf.get(), 2*bufSize)}; + } + + } + catch (std::exception& e) + { + std::cout << "FAILED: " << e.what() << '\n'; + exit(-1); + } + free(px); +} diff --git a/memcheck/tests/freebsd/kenv.stderr.exp b/memcheck/tests/freebsd/kenv.stderr.exp new file mode 100644 index 0000000000..c356c7c833 --- /dev/null +++ b/memcheck/tests/freebsd/kenv.stderr.exp @@ -0,0 +1,55 @@ + +Warning: bad or unimplemented kenv action: 1764 +Syscall param kenv(action) contains uninitialised byte(s) + at 0x........: kenv (in /...libc...) + by 0x........: main (kenv.cpp:110) + +Syscall param kenv(name) contains uninitialised byte(s) + at 0x........: kenv (in /...libc...) + by 0x........: main (kenv.cpp:110) + +Syscall param kenv(value) contains uninitialised byte(s) + at 0x........: kenv (in /...libc...) + by 0x........: main (kenv.cpp:110) + +Syscall param kenv(len) contains uninitialised byte(s) + at 0x........: kenv (in /...libc...) + by 0x........: main (kenv.cpp:110) + +Syscall param kenv(name) points to unaddressable byte(s) + at 0x........: kenv (in /...libc...) + by 0x........: main (kenv.cpp:116) + Address 0x........ is 0 bytes inside a block of size 32 free'd + at 0x........: ...operator delete[]... (vg_replace_malloc.c:...) + by 0x........: main (kenv.cpp:115) + Block was alloc'd at + at 0x........: ...operator new[]... (vg_replace_malloc.c:...) + by 0x........: main (kenv.cpp:113) + +Syscall param kenv(value) points to unaddressable byte(s) + at 0x........: kenv (in /...libc...) + by 0x........: main (kenv.cpp:119) + Address 0x........ is 0 bytes inside a block of size 32 free'd + at 0x........: ...operator delete[]... (vg_replace_malloc.c:...) + by 0x........: main (kenv.cpp:118) + Block was alloc'd at + at 0x........: ...operator new[]... (vg_replace_malloc.c:...) + by 0x........: main (kenv.cpp:117) + +Syscall param kenv(value) points to unaddressable byte(s) + at 0x........: kenv (in /...libc...) + by 0x........: main (kenv.cpp:120) + Address 0x........ is 0 bytes after a block of size 1,024 alloc'd + at 0x........: ...operator new[]... (vg_replace_malloc.c:...) + by 0x........: main (kenv.cpp:18) + + +HEAP SUMMARY: + in use at exit: 0 bytes in 0 blocks + total heap usage: 5 allocs, 5 frees, 4,765 bytes allocated + +For a detailed leak analysis, rerun with: --leak-check=full + +Use --track-origins=yes to see where uninitialised values come from +For lists of detected and suppressed errors, rerun with: -s +ERROR SUMMARY: 7 errors from 7 contexts (suppressed: 0 from 0) diff --git a/memcheck/tests/freebsd/kenv.vgtest b/memcheck/tests/freebsd/kenv.vgtest new file mode 100644 index 0000000000..763cd16a2a --- /dev/null +++ b/memcheck/tests/freebsd/kenv.vgtest @@ -0,0 +1 @@ +prog: kenv diff --git a/memcheck/tests/freebsd/scalar.stderr.exp b/memcheck/tests/freebsd/scalar.stderr.exp index 2e6ca39b49..ae8adcd1b4 100644 --- a/memcheck/tests/freebsd/scalar.stderr.exp +++ b/memcheck/tests/freebsd/scalar.stderr.exp @@ -2968,21 +2968,26 @@ Syscall param kenv(name) points to unaddressable byte(s) ... Address 0x........ is not stack'd, malloc'd or (recently) free'd +Syscall param kenv(value) points to unaddressable byte(s) + ... + Address 0x........ is not stack'd, malloc'd or (recently) free'd + --------------------------------------------------------- 390: SYS_kenv (KENV_DUMP) 4s 0m --------------------------------------------------------- Syscall param kenv(action) contains uninitialised byte(s) ... -Syscall param kenv(name) contains uninitialised byte(s) - ... - Syscall param kenv(value) contains uninitialised byte(s) ... Syscall param kenv(len) contains uninitialised byte(s) ... +Syscall param kenv(value) points to unaddressable byte(s) + ... + Address 0x........ is not stack'd, malloc'd or (recently) free'd + --------------------------------------------------------- 391: SYS_lchflags 2s 1m --------------------------------------------------------- diff --git a/memcheck/tests/freebsd/scalar.stderr.exp-x86 b/memcheck/tests/freebsd/scalar.stderr.exp-x86 index 24c7caac04..47beb3dcec 100644 --- a/memcheck/tests/freebsd/scalar.stderr.exp-x86 +++ b/memcheck/tests/freebsd/scalar.stderr.exp-x86 @@ -2974,21 +2974,26 @@ Syscall param kenv(name) points to unaddressable byte(s) ... Address 0x........ is not stack'd, malloc'd or (recently) free'd +Syscall param kenv(value) points to unaddressable byte(s) + ... + Address 0x........ is not stack'd, malloc'd or (recently) free'd + --------------------------------------------------------- 390: SYS_kenv (KENV_DUMP) 4s 0m --------------------------------------------------------- Syscall param kenv(action) contains uninitialised byte(s) ... -Syscall param kenv(name) contains uninitialised byte(s) - ... - Syscall param kenv(value) contains uninitialised byte(s) ... Syscall param kenv(len) contains uninitialised byte(s) ... +Syscall param kenv(value) points to unaddressable byte(s) + ... + Address 0x........ is not stack'd, malloc'd or (recently) free'd + --------------------------------------------------------- 391: SYS_lchflags 2s 1m --------------------------------------------------------- |
From: Florian K. <fk...@so...> - 2025-07-12 13:34:17
|
https://sourceware.org/cgit/valgrind/commit/?id=1752297cb1d7f3e112104f377d8ee5b99d55408b commit 1752297cb1d7f3e112104f377d8ee5b99d55408b Author: Florian Krohm <fl...@ei...> Date: Sat Jul 12 13:32:14 2025 +0000 Add program to double-check VEX constant folding. BZ 506211 Using IR injection. Essentially: - prepare input values for an IROp - create an IRExpr for the IRop - constant fold the expression - make sure the result is an IRConst with the expected value Only IROps with integer operands and result are supported. No vector and floating point IROps. Maximum bit width is 64. Part of fixing https://bugs.kde.org/show_bug.cgi?id=506211 Diff: --- .gitignore | 12 + Makefile.am | 1 + VEX/priv/ir_inject.c | 75 ++++++ VEX/priv/ir_opt.c | 5 + VEX/pub/libvex.h | 15 ++ VEX/pub/libvex_ir.h | 3 + configure.ac | 1 + none/tests/iropt-test/Makefile.am | 83 +++++++ none/tests/iropt-test/binary.c | 315 ++++++++++++++++++++++++ none/tests/iropt-test/filter_stderr | 4 + none/tests/iropt-test/irops.tab | 246 ++++++++++++++++++ none/tests/iropt-test/iropt-test-sec.stderr.exp | 0 none/tests/iropt-test/iropt-test-sec.vgtest | 4 + none/tests/iropt-test/iropt-test.stderr.exp | 0 none/tests/iropt-test/iropt-test.vgtest | 4 + none/tests/iropt-test/main.c | 135 ++++++++++ none/tests/iropt-test/unary.c | 229 +++++++++++++++++ none/tests/iropt-test/util.c | 106 ++++++++ none/tests/iropt-test/valgrind.c | 92 +++++++ none/tests/iropt-test/vtest.h | 91 +++++++ 20 files changed, 1421 insertions(+) diff --git a/.gitignore b/.gitignore index 32cedb0d7c..e4ddf5dc65 100644 --- a/.gitignore +++ b/.gitignore @@ -2244,6 +2244,18 @@ /none/tests/riscv64/integer /none/tests/riscv64/muldiv +# /none/tests/iropt-test/ +/none/tests/iropt-test/*.dSYM +/none/tests/iropt-test/*.stderr.diff* +/none/tests/iropt-test/*.stderr.out +/none/tests/iropt-test/*.stdout.diff* +/none/tests/iropt-test/*.stdout.out +/none/tests/iropt-test/.deps +/none/tests/iropt-test/Makefile +/none/tests/iropt-test/Makefile.in +/none/tests/iropt-test/iropt-test +/none/tests/iropt-test/iropt-test-sec + # /none/tests/s390x/disasm-test/ /none/tests/s390x/disasm-test/*.dSYM /none/tests/s390x/disasm-test/*.stderr.diff* diff --git a/Makefile.am b/Makefile.am index e67356b5a0..a3150abb14 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,6 +34,7 @@ SUBDIRS = \ gdbserver_tests \ memcheck/tests/vbit-test \ none/tests/s390x/disasm-test \ + none/tests/iropt-test \ auxprogs \ mpi \ solaris \ diff --git a/VEX/priv/ir_inject.c b/VEX/priv/ir_inject.c index f642c834db..750bb588d3 100644 --- a/VEX/priv/ir_inject.c +++ b/VEX/priv/ir_inject.c @@ -33,6 +33,7 @@ #include "main_util.h" /* Convenience macros for readibility */ +#define mkU1(v) IRExpr_Const(IRConst_U1(v)) #define mkU8(v) IRExpr_Const(IRConst_U8(v)) #define mkU16(v) IRExpr_Const(IRConst_U16(v)) #define mkU32(v) IRExpr_Const(IRConst_U32(v)) @@ -321,6 +322,76 @@ vex_inject_ir_vbit(IRSB *irsb, IREndness endian) } } + +static void +vex_inject_ir_iropt(IRSB *irsb, IREndness endian) +{ + IRICB_iropt_payload iricb = the_iricb.iropt; + IRExpr *opnd1, *opnd2, *expr; + ULong val1, val2; + + val1 = *(ULong *)iricb.opnd1; + switch (iricb.t_opnd1) { + case Ity_I1: opnd1 = mkU1(val1); break; + case Ity_I8: opnd1 = mkU8(val1); break; + case Ity_I16: opnd1 = mkU16(val1); break; + case Ity_I32: opnd1 = mkU32(val1); break; + case Ity_I64: opnd1 = mkU64(val1); break; + default: + vpanic("unsupported type"); + } + + switch (iricb.num_operands) { + case 1: + expr = unop(iricb.op, opnd1); + break; + + case 2: + val2 = *(ULong *)iricb.opnd2; + switch (iricb.t_opnd2) { + case Ity_I1: opnd2 = mkU1(val2); break; + case Ity_I8: opnd2 = mkU8(val2); break; + case Ity_I16: opnd2 = mkU16(val2); break; + case Ity_I32: opnd2 = mkU32(val2); break; + case Ity_I64: opnd2 = mkU64(val2); break; + default: + vpanic("unsupported type"); + } + expr = binop(iricb.op, opnd1, opnd2); + break; + + default: + vpanic("unsupported operator"); + } + + /* Make sure the expression gets folded ! */ + IRExpr *env[1] = { 0 }; + IRExpr *res = foldIRExpr(env, expr); + + if (res->tag != Iex_Const) { + vex_printf("*** "); + ppIROp(iricb.op); + vex_printf(": not folded: result = "); + ppIRExpr(res); + vex_printf("\n"); + *(ULong *)iricb.result = 0; // whatever + return; + } + + /* Store the folded result in the IRICB. We're only handling integers + up to 64-bit wide. */ + switch (iricb.t_result) { + case Ity_I1: *(ULong *)iricb.result = res->Iex.Const.con->Ico.U1; break; + case Ity_I8: *(ULong *)iricb.result = res->Iex.Const.con->Ico.U8; break; + case Ity_I16: *(ULong *)iricb.result = res->Iex.Const.con->Ico.U16; break; + case Ity_I32: *(ULong *)iricb.result = res->Iex.Const.con->Ico.U32; break; + case Ity_I64: *(ULong *)iricb.result = res->Iex.Const.con->Ico.U64; break; + default: + vpanic("unsupported type"); + } +} + + void vex_inject_ir(IRSB *irsb, IREndness endian) { @@ -329,6 +400,10 @@ vex_inject_ir(IRSB *irsb, IREndness endian) vex_inject_ir_vbit(irsb, endian); break; + case IRICB_iropt: + vex_inject_ir_iropt(irsb, endian); + break; + default: vpanic("unknown IRICB kind"); } diff --git a/VEX/priv/ir_opt.c b/VEX/priv/ir_opt.c index ee2c5a4a71..9a3f39c2c9 100644 --- a/VEX/priv/ir_opt.c +++ b/VEX/priv/ir_opt.c @@ -2610,6 +2610,11 @@ static IRExpr* fold_Expr ( IRExpr** env, IRExpr* e ) return env == NULL ? e : fold_Expr_WRK(env, e); } +IRExpr* foldIRExpr ( IRExpr** env, IRExpr* e ) +{ + return fold_Expr(env, e); +} + /* Apply the subst to a simple 1-level expression -- guaranteed to be 1-level due to previous flattening pass. */ diff --git a/VEX/pub/libvex.h b/VEX/pub/libvex.h index 870747d354..de19e1ebf6 100644 --- a/VEX/pub/libvex.h +++ b/VEX/pub/libvex.h @@ -963,6 +963,7 @@ extern void LibVEX_ShowStats ( void ); typedef enum { IRICB_vbit, + IRICB_iropt, } IRICB_t; @@ -992,11 +993,25 @@ typedef } IRICB_vbit_payload; +typedef + struct { + IROp op; // the operation to perform + HWord result; // address of the result + HWord opnd1; // address of 1st operand + HWord opnd2; // address of 2nd operand + IRType t_result; // type of result + IRType t_opnd1; // type of 1st operand + IRType t_opnd2; // type of 2nd operand + UInt num_operands; + } + IRICB_iropt_payload; + typedef struct { IRICB_t kind; union { IRICB_vbit_payload vbit; + IRICB_iropt_payload iropt; }; } IRICB; diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index 803a1317ed..983cd50bca 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -2405,6 +2405,9 @@ extern IRExpr* deepCopyIRExpr ( const IRExpr* ); /* Pretty-print an IRExpr. */ extern void ppIRExpr ( const IRExpr* ); +/* Fold an IRExpr. Return folded result. */ +extern IRExpr* foldIRExpr ( IRExpr**, IRExpr* ); + /* NULL-terminated IRExpr vector constructors, suitable for use as arg lists in clean/dirty helper calls. */ extern IRExpr** mkIRExprVec_0 ( void ); diff --git a/configure.ac b/configure.ac index a235f1a424..d64782728b 100755 --- a/configure.ac +++ b/configure.ac @@ -5757,6 +5757,7 @@ AC_CONFIG_FILES([ none/tests/arm64/Makefile none/tests/s390x/Makefile none/tests/s390x/disasm-test/Makefile + none/tests/iropt-test/Makefile none/tests/mips32/Makefile none/tests/mips64/Makefile none/tests/nanomips/Makefile diff --git a/none/tests/iropt-test/Makefile.am b/none/tests/iropt-test/Makefile.am new file mode 100644 index 0000000000..f4d1e9afa7 --- /dev/null +++ b/none/tests/iropt-test/Makefile.am @@ -0,0 +1,83 @@ +include $(top_srcdir)/Makefile.all.am + +EXTRA_DIST = iropt-test.vgtest iropt-test.stderr.exp \ + iropt-test-sec.vgtest iropt-test-sec.stderr.exp \ + irops.tab + +dist_noinst_SCRIPTS = filter_stderr + +#---------------------------------------------------------------------------- +# Headers +#---------------------------------------------------------------------------- + +pkginclude_HEADERS = +noinst_HEADERS = vtest.h + +#---------------------------------------------------------------------------- +# iropt_test +#---------------------------------------------------------------------------- + +noinst_PROGRAMS = iropt-test + +if VGCONF_HAVE_PLATFORM_SEC +noinst_PROGRAMS += iropt-test-sec +endif + +if VGCONF_OS_IS_DARWIN +noinst_DSYMS = $(noinst_PROGRAMS) +endif + +SOURCES = \ + main.c \ + unary.c \ + binary.c \ + util.c \ + valgrind.c + +# The link flags for this are tricky, because we want to build it for +# both the primary and secondary platforms, and add +# "-Wl,-read_only_relocs -Wl,suppress" to whichever of those is x86-darwin, +# if any. Hence there's a double-nested conditional that adds to the +# LDFLAGS in both cases. + +iropt_test_SOURCES = $(SOURCES) +iropt_test_CPPFLAGS = $(AM_CPPFLAGS_PRI) \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/memcheck \ + -I$(top_srcdir)/VEX/pub +iropt_test_CFLAGS = $(AM_CFLAGS_PRI) -fhosted +iropt_test_DEPENDENCIES = $(top_builddir)/VEX/libvex-@VGCONF_ARCH_PRI@-@VGCONF_OS@.a +iropt_test_LDADD = $(top_builddir)/VEX/libvex-@VGCONF_ARCH_PRI@-@VGCONF_OS@.a +iropt_test_LDFLAGS = $(AM_CFLAGS_PRI) @LIB_UBSAN@ +# If there is no secondary platform, and the platforms include x86-darwin, +# then the primary platform must be x86-darwin. Hence: +if ! VGCONF_HAVE_PLATFORM_SEC +if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN +iropt_test_LDFLAGS += -Wl,-read_only_relocs -Wl,suppress +endif +endif + +if VGCONF_HAVE_PLATFORM_SEC +iropt_test_sec_SOURCES = $(SOURCES) +iropt_test_sec_CPPFLAGS = $(AM_CPPFLAGS_SEC) \ + $(AM_CPPFLAGS_@VGCONF_PLATFORM_SEC_CAPS@) \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/memcheck \ + -I$(top_srcdir)/VEX/pub +iropt_test_sec_CFLAGS = $(AM_CFLAGS_SEC) -fhosted \ + $(AM_CFLAGS_@VGCONF_PLATFORM_SEC_CAPS@) +iropt_test_sec_DEPENDENCIES = $(top_builddir)/VEX/libvex-@VGCONF_ARCH_SEC@-@VGCONF_OS@.a \ + $(TOOL_LDADD_@VGCONF_PLATFORM_SEC_CAPS@) +iropt_test_sec_LDADD = $(top_builddir)/VEX/libvex-@VGCONF_ARCH_SEC@-@VGCONF_OS@.a \ + $(TOOL_LDADD_@VGCONF_PLATFORM_SEC_CAPS@) +iropt_test_sec_LDFLAGS = $(AM_CFLAGS_SEC) @LIB_UBSAN@ \ + $(TOOL_LDFLAGS_@VGCONF_PLATFORM_SEC_CAPS@) +endif +# If there is a secondary platform, and the platforms include x86-darwin, +# then the primary platform must be amd64-darwin and the secondary platform +# must be x86-darwin. Hence: +if VGCONF_HAVE_PLATFORM_SEC +if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN +iropt_test_sec_LDFLAGS += -Wl,-read_only_relocs -Wl,suppress +endif +endif diff --git a/none/tests/iropt-test/binary.c b/none/tests/iropt-test/binary.c new file mode 100644 index 0000000000..c3f36c1884 --- /dev/null +++ b/none/tests/iropt-test/binary.c @@ -0,0 +1,315 @@ +/* -*- mode: C; c-basic-offset: 3; -*- */ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2025 Florian Krohm + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. + + The GNU General Public License is contained in the file COPYING. +*/ + +#include <stdio.h> // printf +#include <stdint.h> // UINT64_MAX +#include "vtest.h" + +static void check_result(const irop_t *, const test_data_t *); +static void run_tests(const irop_t *, test_data_t *, unsigned, uint64_t *, + unsigned, uint64_t *); +static int is_shift_op(IROp); + + +void +test_binary_op(const irop_t *op, test_data_t *data) +{ + opnd_t *opnd_l = &data->opnds[0]; + + switch (opnd_l->type) { + case Ity_I1: { + uint64_t values[] = { 0, 1 }; + + run_tests(op, data, NUM_EL(values), values, NUM_EL(values), values); + break; + } + + case Ity_I8: { + uint64_t values[] = { 0, 1, 2, UINT8_MAX - 1, UINT8_MAX }; + uint64_t shifts[] = { 0, 1, 2, 6, 7 }; + + if (is_shift_op(op->op)) + run_tests(op, data, NUM_EL(values), values, NUM_EL(shifts), shifts); + else + run_tests(op, data, NUM_EL(values), values, NUM_EL(values), values); + break; + } + + case Ity_I16: { + uint64_t values[] = { 0, 1, 2, UINT16_MAX - 1, UINT16_MAX }; + uint64_t shifts[] = { 0, 1, 2, 14, 15 }; + + if (is_shift_op(op->op)) + run_tests(op, data, NUM_EL(values), values, NUM_EL(shifts), shifts); + else + run_tests(op, data, NUM_EL(values), values, NUM_EL(values), values); + break; + } + + case Ity_I32: { + uint64_t values[] = { 0, 1, 2, UINT32_MAX - 1, UINT32_MAX }; + uint64_t shifts[] = { 0, 1, 2, 30, 31 }; + + if (is_shift_op(op->op)) + run_tests(op, data, NUM_EL(values), values, NUM_EL(shifts), shifts); + else + run_tests(op, data, NUM_EL(values), values, NUM_EL(values), values); + break; + } + + case Ity_I64: { + uint64_t values[] = { 0, 1, 2, UINT64_MAX - 1, UINT64_MAX }; + uint64_t shifts[] = { 0, 1, 2, 62, 63 }; + + if (is_shift_op(op->op)) + run_tests(op, data, NUM_EL(values), values, NUM_EL(shifts), shifts); + else + run_tests(op, data, NUM_EL(values), values, NUM_EL(values), values); + break; + } + + default: + panic(__func__); + } +} + + +static void +run_tests(const irop_t *op, test_data_t *data, unsigned num_val_l, + uint64_t *values_l, unsigned num_val_r, uint64_t *values_r) +{ + opnd_t *opnd_l = &data->opnds[0]; + opnd_t *opnd_r = &data->opnds[1]; + + for (unsigned i = 0; i < num_val_l; ++i) { + opnd_l->value = values_l[i]; + for (unsigned j = 0; j < num_val_r; ++j) { + opnd_r->value = values_r[j]; + + valgrind_execute_test(op, data); + check_result(op, data); + } + } +} + + +/* Check the result of a binary operation. */ +static void +check_result(const irop_t *op, const test_data_t *data) +{ + uint64_t result = data->result.value; + uint64_t opnd_l = data->opnds[0].value; + uint64_t opnd_r = data->opnds[1].value; + uint64_t expected; + + switch (op->op) { + case Iop_Add8: + case Iop_Add16: + case Iop_Add32: + case Iop_Add64: + expected = opnd_l + opnd_r; + break; + + case Iop_Sub8: + case Iop_Sub16: + case Iop_Sub32: + case Iop_Sub64: + expected = opnd_l - opnd_r; + break; + + case Iop_MullS32: + expected = (int64_t)(int32_t)opnd_l * (int64_t)(int32_t)opnd_r; + break; + + case Iop_Shl32: + expected = opnd_l << opnd_r; + break; + + case Iop_Shl64: + expected = opnd_l << opnd_r; + break; + + case Iop_Shr32: + expected = opnd_l >> opnd_r; + break; + + case Iop_Shr64: + expected = opnd_l >> opnd_r; + break; + + case Iop_Sar32: + expected = ((int64_t)(opnd_l << 32) >> 32) >> opnd_r; + break; + + case Iop_Sar64: + expected = (int64_t)opnd_l >> opnd_r; + break; + + case Iop_Or1: + case Iop_Or8: + case Iop_Or16: + case Iop_Or32: + case Iop_Or64: + expected = opnd_l | opnd_r; + break; + + case Iop_And1: + case Iop_And8: + case Iop_And16: + case Iop_And32: + case Iop_And64: + expected = opnd_l & opnd_r; + break; + + case Iop_Xor8: + case Iop_Xor16: + case Iop_Xor32: + case Iop_Xor64: + expected = opnd_l ^ opnd_r; + break; + + case Iop_CmpEQ8: + case Iop_CmpEQ16: + case Iop_CmpEQ32: + case Iop_CmpEQ64: +// case Iop_CasCmpEQ8: +// case Iop_CasCmpEQ16: +// case Iop_CasCmpEQ32: +// case Iop_CasCmpEQ64: + expected = opnd_l == opnd_r; + break; + + case Iop_CmpNE8: +// case Iop_CmpNE16: + case Iop_CmpNE32: + case Iop_CmpNE64: + case Iop_CasCmpNE8: +// case Iop_CasCmpNE16: + case Iop_CasCmpNE32: + case Iop_CasCmpNE64: + case Iop_ExpCmpNE8: +// case Iop_ExpCmpNE16: + case Iop_ExpCmpNE32: + case Iop_ExpCmpNE64: + expected = opnd_l != opnd_r; + break; + + case Iop_CmpLT32U: + case Iop_CmpLT64U: + expected = opnd_l < opnd_r; + break; + + case Iop_CmpLT32S: { + int32_t opnd_ls = (int32_t)(opnd_l & UINT32_MAX); + int32_t opnd_rs = (int32_t)(opnd_r & UINT32_MAX); + expected = opnd_ls < opnd_rs; + break; + } + + case Iop_CmpLT64S: + expected = (int64_t)opnd_l < (int64_t)opnd_r; + break; + + case Iop_CmpLE32U: + case Iop_CmpLE64U: + expected = opnd_l <= opnd_r; + break; + + case Iop_CmpLE32S: { + int32_t opnd_ls = (int32_t)(opnd_l & UINT32_MAX); + int32_t opnd_rs = (int32_t)(opnd_r & UINT32_MAX); + expected = opnd_ls <= opnd_rs; + break; + } + + case Iop_CmpLE64S: + expected = (int64_t)opnd_l <= (int64_t)opnd_r; + break; + + case Iop_CmpORD32S: { + int32_t opnd_ls = (int32_t)(opnd_l & UINT32_MAX); + int32_t opnd_rs = (int32_t)(opnd_r & UINT32_MAX); + expected = (opnd_ls < opnd_rs) ? 8 : (opnd_ls > opnd_rs) ? 4 : 2; + break; + } + + case Iop_Max32U: + opnd_l &= UINT32_MAX; + opnd_r &= UINT32_MAX; + expected = opnd_l > opnd_r ? opnd_l : opnd_r; + break; + + case Iop_32HLto64: + expected = (opnd_l << 32) | opnd_r; + break; + + default: + panic("%s: operator %s not handled\n", __func__, op->name); + } + + /* Truncate to width of result type */ + switch (bitsof_irtype(op->result_type)) { + case 1: expected &= 0x1; break; + case 8: expected &= UINT8_MAX; break; + case 16: expected &= UINT16_MAX; break; + case 32: expected &= UINT32_MAX; break; + case 64: expected &= UINT64_MAX; break; + default: + panic(__func__); + } + + if (verbose > 1) { + printf("expected: value = "); + print_value(stdout, expected, bitsof_irtype(data->result.type)); + printf("\n"); + } + + int ok = 1; + switch (data->result.type) { + case Ity_I1: ok = result == expected; break; + case Ity_I8: ok = result == expected; break; + case Ity_I16: ok = result == expected; break; + case Ity_I32: ok = result == expected; break; + case Ity_I64: ok = result == expected; break; + default: + panic(__func__); + } + + if (! ok) + complain(op, data, expected); +} + + +static int +is_shift_op(IROp op) +{ + switch (op) { + case Iop_Shl8: case Iop_Shl16: case Iop_Shl32: case Iop_Shl64: + case Iop_Shr8: case Iop_Shr16: case Iop_Shr32: case Iop_Shr64: + case Iop_Sar8: case Iop_Sar16: case Iop_Sar32: case Iop_Sar64: + return 1; + default: + return 0; + } +} diff --git a/none/tests/iropt-test/filter_stderr b/none/tests/iropt-test/filter_stderr new file mode 100755 index 0000000000..5337954d0f --- /dev/null +++ b/none/tests/iropt-test/filter_stderr @@ -0,0 +1,4 @@ +#!/bin/sh + +# Nothing to filter. +sed 's/BLA/BLA/' diff --git a/none/tests/iropt-test/irops.tab b/none/tests/iropt-test/irops.tab new file mode 100644 index 0000000000..a849289cdd --- /dev/null +++ b/none/tests/iropt-test/irops.tab @@ -0,0 +1,246 @@ +/* -*- mode: C; c-basic-offset: 3; -*- */ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2025 Florian Krohm + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. + + The GNU General Public License is contained in the file COPYING. +*/ + +#define OPNAME(op) #op, Iop_##op + +/* Definition of IROps: + - no IROps having floating point operands or result + - no IROPs having vector operands or results (V128, V256) + - no IROPs having integer operands or results with more than 64 bit +*/ + // UNARY + { OPNAME(Not1), Ity_I1, 1, Ity_I1, }, + { OPNAME(Not8), Ity_I8, 1, Ity_I8, }, + { OPNAME(Not16), Ity_I16, 1, Ity_I16, }, + { OPNAME(Not32), Ity_I32, 1, Ity_I32, }, + { OPNAME(Not64), Ity_I64, 1, Ity_I64, }, + + { OPNAME(1Uto8), Ity_I8, 1, Ity_I1, }, +// { OPNAME(1Uto16), Ity_I16, 1, Ity_I1, }, // missing in libvex_ir.h + { OPNAME(1Uto32), Ity_I32, 1, Ity_I1, }, + { OPNAME(1Uto64), Ity_I64, 1, Ity_I1, }, + { OPNAME(1Sto8), Ity_I8, 1, Ity_I1, }, + { OPNAME(1Sto16), Ity_I16, 1, Ity_I1, }, + { OPNAME(1Sto32), Ity_I32, 1, Ity_I1, }, + { OPNAME(1Sto64), Ity_I64, 1, Ity_I1, }, + + { OPNAME(8Uto16), Ity_I16, 1, Ity_I8, }, + { OPNAME(8Uto32), Ity_I32, 1, Ity_I8, }, + { OPNAME(8Uto64), Ity_I64, 1, Ity_I8, }, + { OPNAME(8Sto16), Ity_I16, 1, Ity_I8, }, + { OPNAME(8Sto32), Ity_I32, 1, Ity_I8, }, + { OPNAME(8Sto64), Ity_I64, 1, Ity_I8, }, + + { OPNAME(16Uto32), Ity_I32, 1, Ity_I16, }, + { OPNAME(16Uto64), Ity_I64, 1, Ity_I16, }, + { OPNAME(16Sto32), Ity_I32, 1, Ity_I16, }, + { OPNAME(16Sto64), Ity_I64, 1, Ity_I16, }, + + { OPNAME(32Uto64), Ity_I64, 1, Ity_I32, }, + { OPNAME(32Sto64), Ity_I64, 1, Ity_I32, }, + +// { OPNAME(8to1), Ity_I1, 1, Ity_I8, }, // missing in libvex_ir.h +// { OPNAME(16to1), Ity_I1, 1, Ity_I16, }, // missing in libvex_ir.h + { OPNAME(16to8), Ity_I8, 1, Ity_I16, }, + { OPNAME(16HIto8), Ity_I8, 1, Ity_I16, }, + + { OPNAME(32to1), Ity_I1, 1, Ity_I32, }, + { OPNAME(32to8), Ity_I8, 1, Ity_I32, }, + { OPNAME(32to16), Ity_I16, 1, Ity_I32, }, + { OPNAME(32HIto16), Ity_I16, 1, Ity_I32, }, + + { OPNAME(64to1), Ity_I1, 1, Ity_I64, }, + { OPNAME(64to8), Ity_I8, 1, Ity_I64, }, + { OPNAME(64to16), Ity_I16, 1, Ity_I64, }, + { OPNAME(64to32), Ity_I32, 1, Ity_I64, }, + { OPNAME(64HIto32), Ity_I32, 1, Ity_I64, }, + +// { OPNAME(128to64), Ity_I64, 1, Ity_I128, }, // 128 bit +// { OPNAME(128HIto64), Ity_I64, 1, Ity_I128, }, // 128 bit + + // BINARY + { OPNAME(Add8), Ity_I8, 2, Ity_I8, Ity_I8 }, +// { OPNAME(Add16), Ity_I16, 2, Ity_I16, Ity_I16 }, // no folding yet + { OPNAME(Add32), Ity_I32, 2, Ity_I32, Ity_I32 }, + { OPNAME(Add64), Ity_I64, 2, Ity_I64, Ity_I64 }, + + { OPNAME(Sub8), Ity_I8, 2, Ity_I8, Ity_I8 }, +// { OPNAME(Sub16), Ity_I16, 2, Ity_I16, Ity_I16 }, // no folding yet + { OPNAME(Sub32), Ity_I32, 2, Ity_I32, Ity_I32 }, + { OPNAME(Sub64), Ity_I64, 2, Ity_I64, Ity_I64 }, + +// { OPNAME(Mul8), Ity_I8, 2, Ity_I8, Ity_I8 }, +// { OPNAME(Mul16), Ity_I16, 2, Ity_I16, Ity_I16 }, +// { OPNAME(Mul32), Ity_I32, 2, Ity_I32, Ity_I32 }, +// { OPNAME(Mul64), Ity_I64, 2, Ity_I64, Ity_I64 }, + +// { OPNAME(MullU8), Ity_I16, 2, Ity_I8, Ity_I8 }, // no folding yet +// { OPNAME(MullU16), Ity_I32, 2, Ity_I16, Ity_I16 }, // no folding yet +// { OPNAME(MullU32), Ity_I64, 2, Ity_I32, Ity_I32 }, // no folding yet +// { OPNAME(MullU64), Ity_I128, 2, Ity_I64, Ity_I64 }, // 128 bit + +// { OPNAME(MullS8), Ity_I16, 2, Ity_I8, Ity_I8 }, // no folding yet +// { OPNAME(MullS16), Ity_I32, 2, Ity_I16, Ity_I16 }, // no folding yet + { OPNAME(MullS32), Ity_I64, 2, Ity_I32, Ity_I32 }, +// { OPNAME(MullS64), Ity_I128, 2, Ity_I64, Ity_I64 }, // 128 bit + +// { OPNAME(DivU32), Ity_I32, 2, Ity_I32, Ity_I32 }, // no folding yet +// { OPNAME(DivU64), Ity_I64, 2, Ity_I64, Ity_I64 }, // no folding yet +// { OPNAME(DivU128), Ity_I128, 2, Ity_I128, Ity_I128 }, // 128 bit + +// { OPNAME(DivS32), Ity_I32, 2, Ity_I32, Ity_I32 }, // no folding yet +// { OPNAME(DivS64), Ity_I64, 2, Ity_I64, Ity_I64 }, // no folding yet +// { OPNAME(DivS128), Ity_I128, 2, Ity_I128, Ity_I128 }, // 128 bit + +// { OPNAME(DivU32E), Ity_I32, 2, Ity_I32, Ity_I32 }, // semantics ? +// { OPNAME(DivU64E), Ity_I32, 2, Ity_I32, Ity_I32 }, // semantics ? +// { OPNAME(DivU128E), Ity_I128, 2, Ity_I128, Ity_I128 }, // 128 bit + +// { OPNAME(DivS32E), Ity_I32, 2, Ity_I32, Ity_I32 }, // semantics ? +// { OPNAME(DivS64E), Ity_I32, 2, Ity_I32, Ity_I32 }, // semantics ? +// { OPNAME(DivS128E), Ity_I128, 2, Ity_I128, Ity_I128 }, // 128 bit + +// { OPNAME(DivModU32to32), Ity_I64, 2, Ity_I32, Ity_I64 }, // no folding yet +// { OPNAME(DivModU64to32), Ity_I64, 2, Ity_I32, Ity_I64 }, // no folding yet +// { OPNAME(DivModU64to64), Ity_I64, 2, Ity_I64, Ity_I128 }, // 128 bit +// { OPNAME(DivModU128to64), Ity_I128, 2, Ity_I64, Ity_I128 }, // 128 bit + +// { OPNAME(DivModS32to32), Ity_I64, 2, Ity_I32, Ity_I32 }, // no folding yet +// { OPNAME(DivModS32to32), Ity_I64, 2, Ity_I32, Ity_I64 }, // no folding yet +// { OPNAME(DivModS64to64), Ity_I64, 2, Ity_I64, Ity_I128 }, // 128 bit +// { OPNAME(DivModU128to64), Ity_I128, 2, Ity_I64, Ity_I128 }, // 128 bit + +// { OPNAME(ModU128), Ity_I128, 2, Ity_I128, Ity_I128 }, // 128 bit +// { OPNAME(ModS128), Ity_I128, 2, Ity_I128, Ity_I128 }, // 128 bit + +// { OPNAME(Shl8), Ity_I8, 2, Ity_I8, Ity_I8 }, // no folding yet +// { OPNAME(Shl16), Ity_I16, 2, Ity_I16, Ity_I8 }, // no folding yet + { OPNAME(Shl32), Ity_I32, 2, Ity_I32, Ity_I8 }, + { OPNAME(Shl64), Ity_I64, 2, Ity_I64, Ity_I8 }, + +// { OPNAME(Shr8), Ity_I8, 2, Ity_I8, Ity_I8 }, // no folding yet +// { OPNAME(Shr16), Ity_I16, 2, Ity_I16, Ity_I8 }, // no folding yet + { OPNAME(Shr32), Ity_I32, 2, Ity_I32, Ity_I8 }, + { OPNAME(Shr64), Ity_I64, 2, Ity_I64, Ity_I8 }, + +// { OPNAME(Sar8), Ity_I8, 2, Ity_I8, Ity_I8 }, // no folding yet +// { OPNAME(Sar16), Ity_I16, 2, Ity_I16, Ity_I8 }, // no folding yet + { OPNAME(Sar32), Ity_I32, 2, Ity_I32, Ity_I8 }, + { OPNAME(Sar64), Ity_I64, 2, Ity_I64, Ity_I8 }, + + { OPNAME(Or1), Ity_I1, 2, Ity_I1, Ity_I1 }, + { OPNAME(Or8), Ity_I8, 2, Ity_I8, Ity_I8 }, + { OPNAME(Or16), Ity_I16, 2, Ity_I16, Ity_I16 }, + { OPNAME(Or32), Ity_I32, 2, Ity_I32, Ity_I32 }, + { OPNAME(Or64), Ity_I64, 2, Ity_I64, Ity_I64 }, + + { OPNAME(And1), Ity_I1, 2, Ity_I1, Ity_I1 }, + { OPNAME(And8), Ity_I8, 2, Ity_I8, Ity_I8 }, + { OPNAME(And16), Ity_I16, 2, Ity_I16, Ity_I16 }, + { OPNAME(And32), Ity_I32, 2, Ity_I32, Ity_I32 }, + { OPNAME(And64), Ity_I64, 2, Ity_I64, Ity_I64 }, + +// { OPNAME(Xor1), Ity_I1, 2, Ity_I1, Ity_I1 }, // missing in libvex_ir.h + { OPNAME(Xor8), Ity_I8, 2, Ity_I8, Ity_I8 }, + { OPNAME(Xor16), Ity_I16, 2, Ity_I16, Ity_I16 }, + { OPNAME(Xor32), Ity_I32, 2, Ity_I32, Ity_I32 }, + { OPNAME(Xor64), Ity_I64, 2, Ity_I64, Ity_I64 }, + +// { OPNAME(CmpEQ8), Ity_I1, 2, Ity_I8, Ity_I8 }, // no folding yet +// { OPNAME(CmpEQ16), Ity_I1, 2, Ity_I16, Ity_I16 }, // no folding yet + { OPNAME(CmpEQ32), Ity_I1, 2, Ity_I32, Ity_I32 }, + { OPNAME(CmpEQ64), Ity_I1, 2, Ity_I64, Ity_I64 }, + + { OPNAME(CmpNE8), Ity_I1, 2, Ity_I8, Ity_I8 }, +// { OPNAME(CmpNE16), Ity_I1, 2, Ity_I16, Ity_I16 }, // no folding yet + { OPNAME(CmpNE32), Ity_I1, 2, Ity_I32, Ity_I32 }, + { OPNAME(CmpNE64), Ity_I1, 2, Ity_I64, Ity_I64 }, + + { OPNAME(CmpLT32U), Ity_I1, 2, Ity_I32, Ity_I32 }, + { OPNAME(CmpLT64U), Ity_I1, 2, Ity_I64, Ity_I64 }, + + { OPNAME(CmpLT32S), Ity_I1, 2, Ity_I32, Ity_I32 }, + { OPNAME(CmpLT64S), Ity_I1, 2, Ity_I64, Ity_I64 }, + + { OPNAME(CmpLE32U), Ity_I1, 2, Ity_I32, Ity_I32 }, + { OPNAME(CmpLE64U), Ity_I1, 2, Ity_I64, Ity_I64 }, + + { OPNAME(CmpLE32S), Ity_I1, 2, Ity_I32, Ity_I32 }, + { OPNAME(CmpLE64S), Ity_I1, 2, Ity_I64, Ity_I64 }, + +// { OPNAME(CasCmpEQ8), Ity_I1, 2, Ity_I8, Ity_I8 }, // no folding yet +// { OPNAME(CasCmpEQ16), Ity_I1, 2, Ity_I16, Ity_I16 }, // no folding yet +// { OPNAME(CasCmpEQ32), Ity_I1, 2, Ity_I32, Ity_I32 }, // no folding yet +// { OPNAME(CasCmpEQ64), Ity_I1, 2, Ity_I64, Ity_I64 }, // no folding yet + + { OPNAME(CasCmpNE8), Ity_I1, 2, Ity_I8, Ity_I8 }, +// { OPNAME(CasCmpNE16), Ity_I1, 2, Ity_I16, Ity_I16 }, // no folding yet + { OPNAME(CasCmpNE32), Ity_I1, 2, Ity_I32, Ity_I32 }, + { OPNAME(CasCmpNE64), Ity_I1, 2, Ity_I64, Ity_I64 }, + + { OPNAME(ExpCmpNE8), Ity_I1, 2, Ity_I8, Ity_I8 }, +// { OPNAME(ExpCmpNE16), Ity_I1, 2, Ity_I16, Ity_I16 }, // no folding yet + { OPNAME(ExpCmpNE32), Ity_I1, 2, Ity_I32, Ity_I32 }, + { OPNAME(ExpCmpNE64), Ity_I1, 2, Ity_I64, Ity_I64 }, + +// { OPNAME(CmpORD32U), Ity_I32, 2, Ity_I32, Ity_I32 }, // no folding yet +// { OPNAME(CmpORD64U), Ity_I64, 2, Ity_I64, Ity_I64 }, // no folding yet + + { OPNAME(CmpORD32S), Ity_I32, 2, Ity_I32, Ity_I32 }, +// { OPNAME(CmpORD64S), Ity_I64, 2, Ity_I64, Ity_I64 }, // no folding yet + + { OPNAME(CmpNEZ8), Ity_I1, 1, Ity_I8 }, +// { OPNAME(CmpNEZ16), Ity_I1, 1, Ity_I16 }, // no folding yet + { OPNAME(CmpNEZ32), Ity_I1, 1, Ity_I32 }, + { OPNAME(CmpNEZ64), Ity_I1, 1, Ity_I64 }, + + { OPNAME(CmpwNEZ32), Ity_I32, 1, Ity_I32 }, + { OPNAME(CmpwNEZ64), Ity_I64, 1, Ity_I64 }, + +// { OPNAME(Left8), Ity_I8, 1, Ity_I8 }, // no folding yet +// { OPNAME(Left16), Ity_I16, 1, Ity_I16 }, // no folding yet + { OPNAME(Left32), Ity_I32, 1, Ity_I32 }, + { OPNAME(Left64), Ity_I64, 1, Ity_I64 }, + + { OPNAME(Max32U), Ity_I32, 2, Ity_I32, Ity_I32 }, + +// { OPNAME(Clz32), Ity_I32, 1, Ity_I32 }, // deprecated, undefined behaviour +// { OPNAME(Clz64), Ity_I64, 1, Ity_I64 }, // deprecated, undefined behaviour + +// { OPNAME(Ctz32), Ity_I32, 1, Ity_I32 }, // deprecated, undefined behaviour +// { OPNAME(Ctz64), Ity_I64, 1, Ity_I64 }, // deprecated, undefined behaviour + +// { OPNAME(ClzNat32), Ity_I32, 1, Ity_I32 }, // no folding yet +// { OPNAME(ClzNat64), Ity_I64, 1, Ity_I64 }, // no folding yet + +// { OPNAME(CtzNat32), Ity_I32, 1, Ity_I32 }, // no folding yet +// { OPNAME(CtzNat64), Ity_I64, 1, Ity_I64 }, // no folding yet + +// { OPNAME(PopCount32), Ity_I32, 1, Ity_I32 }, // no folding yet +// { OPNAME(PopCount64), Ity_I64, 1, Ity_I64 }, // no folding yet + +// { OPNAME(8HLto16), Ity_I16, 2, Ity_I8, Ity_I8 }, // no folding yet +// { OPNAME(16HLto32), Ity_I32, 2, Ity_I16, Ity_I16 }, // no folding yet + { OPNAME(32HLto64), Ity_I64, 2, Ity_I32, Ity_I32 }, +// { OPNAME(64HLto128), Ity_I128, 2, Ity_I64, Ity_I64 }, // 128 bit diff --git a/none/tests/iropt-test/iropt-test-sec.stderr.exp b/none/tests/iropt-test/iropt-test-sec.stderr.exp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/none/tests/iropt-test/iropt-test-sec.vgtest b/none/tests/iropt-test/iropt-test-sec.vgtest new file mode 100644 index 0000000000..e8d4cc7025 --- /dev/null +++ b/none/tests/iropt-test/iropt-test-sec.vgtest @@ -0,0 +1,4 @@ +prog: iropt-test +prereq: test -x iropt-test-sec +vgopts: -q --vex-guest-chase=no + diff --git a/none/tests/iropt-test/iropt-test.stderr.exp b/none/tests/iropt-test/iropt-test.stderr.exp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/none/tests/iropt-test/iropt-test.vgtest b/none/tests/iropt-test/iropt-test.vgtest new file mode 100644 index 0000000000..8becafdf8c --- /dev/null +++ b/none/tests/iropt-test/iropt-test.vgtest @@ -0,0 +1,4 @@ +prog: iropt-test +#args: -v -v +vgopts: -q --vex-guest-chase=no + diff --git a/none/tests/iropt-test/main.c b/none/tests/iropt-test/main.c new file mode 100644 index 0000000000..28b8d23e4b --- /dev/null +++ b/none/tests/iropt-test/main.c @@ -0,0 +1,135 @@ +/* -*- mode: C; c-basic-offset: 3; -*- */ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2025 Florian Krohm + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. + + The GNU General Public License is contained in the file COPYING. +*/ + +#include <assert.h> // assert +#include <stdio.h> // printf +#include <stdlib.h> // malloc +#include <string.h> // memset +#include "valgrind.h" // RUNNING_ON_VALGRIND +#include "vtest.h" + +/* Table of IROps. */ +static irop_t irops[] = { + #include "irops.tab" +}; + +static void check_irops_table(void); +static test_data_t *new_test_data(const irop_t *); + +int verbose = 0; + + +int +main(int argc, char *argv[]) +{ + assert(sizeof(long long) == 8); + + for (int i = 1; i < argc; ++i) { + if (strcmp(argv[i], "-v") == 0) + ++verbose; + else if (strcmp(argv[i], "--help") == 0) { + printf("\niropt-test [ -v | --help ]\n"); + printf("\n\t -v verbose mode; shows IROps being tested\n"); + printf("\n\t -v -v verbose mode, extreme edition\n\n"); + return 0; + } else { + printf("%s ? Nothing happens.\n", argv[i]); + return 1; + } + } + + if (! RUNNING_ON_VALGRIND) { + fprintf(stderr, "*** This program needs to run under valgrind.\n"); + return 1; + } + + check_irops_table(); + + setbuf(stdout, NULL); // make stdout unbuffered + + for (unsigned i = 0; i < NUM_EL(irops); ++i) { + const irop_t *op = irops +i; + + if (verbose) + printf("\nTesting operator %s\n", op->name); + + test_data_t *data = new_test_data(op); + + IRICB iricb = new_iricb(op, data); + + valgrind_vex_init_for_iri(&iricb); + + switch (op->num_opnds) { + case 1: + test_unary_op(op, data); + break; + + case 2: + test_binary_op(op, data); + break; + + default: + panic("operator %s not handled", op->name); + } + + free(data); + } + + return 0; +} + + +static void +check_irops_table(void) +{ + for (unsigned i = 0; i < sizeof irops / sizeof *irops; ++i) { + const irop_t *op = irops +i; + + IRType t_res, t_opnd1, t_opnd2, t_opnd3, t_opnd4; + + typeOfPrimop(op->op, &t_res, &t_opnd1, &t_opnd2, &t_opnd3, &t_opnd4); + + if (op->result_type != t_res || + op->opnd1_type != t_opnd1 || + (op->num_opnds == 2 && op->opnd2_type != t_opnd2)) + fprintf(stderr, "%s: type mismatch\n", op->name); + } +} + + +static test_data_t * +new_test_data(const irop_t *op) +{ + test_data_t *data = malloc(sizeof *data); + + memset(data, 0x0, sizeof *data); // initialise + + data->result.type = op->result_type; + + data->opnds[0].type = op->opnd1_type; + if (op->num_opnds > 1) + data->opnds[1].type = op->opnd2_type; + + return data; +} diff --git a/none/tests/iropt-test/unary.c b/none/tests/iropt-test/unary.c new file mode 100644 index 0000000000..51ad51505b --- /dev/null +++ b/none/tests/iropt-test/unary.c @@ -0,0 +1,229 @@ +/* -*- mode: C; c-basic-offset: 3; -*- */ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2025 Florian Krohm + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. + + The GNU General Public License is contained in the file COPYING. +*/ + +#include <stdio.h> // printf +#include <stdint.h> // UINT64_MAX +#include "vtest.h" + +static void check_result(const irop_t *, const test_data_t *); +static void run_tests(const irop_t *, test_data_t *, unsigned, uint64_t *); + + +void +test_unary_op(const irop_t *op, test_data_t *data) +{ + opnd_t *opnd = &data->opnds[0]; + + switch (opnd->type) { + case Ity_I1: { + uint64_t values[] = { 0, 1 }; + + run_tests(op, data, NUM_EL(values), values); + break; + } + + case Ity_I8: { + uint64_t values[] = { 0, 1, 2, UINT8_MAX - 1, UINT8_MAX }; + + run_tests(op, data, NUM_EL(values), values); + break; + } + + case Ity_I16: { + uint64_t values[] = { 0, 1, 2, UINT16_MAX - 1, UINT16_MAX, + /* and for the benefit of Iop_16HIto8: */ + 1 << 8, 2 << 8, UINT8_MAX << 8 + }; + + run_tests(op, data, NUM_EL(values), values); + break; + } + + case Ity_I32: { + uint64_t values[] = { 0, 1, 2, UINT32_MAX - 1, UINT32_MAX, + /* and for the benefit of Iop_32HIto16: */ + 1 << 16, 2 << 16, (uint64_t)UINT16_MAX << 16 + }; + run_tests(op, data, NUM_EL(values), values); + break; + } + + case Ity_I64: { + uint64_t values[] = { 0, 1, 2, UINT64_MAX - 1, UINT64_MAX, + /* and for the benefit of Iop_64HIto32: */ + (uint64_t)1 << 32, (uint64_t)2 << 32, (uint64_t)UINT32_MAX << 32 + }; + run_tests(op, data, NUM_EL(values), values); + break; + } + + default: + panic(__func__); + } +} + + +static void +run_tests(const irop_t *op, test_data_t *data, unsigned num_val, + uint64_t *values) +{ + opnd_t *opnd = &data->opnds[0]; + + for (unsigned i = 0; i < num_val; ++i) { + opnd->value = values[i]; + + valgrind_execute_test(op, data); + check_result(op, data); + } +} + + +/* Check the result of a unary operation. */ +static void +check_result(const irop_t *op, const test_data_t *data) +{ + uint64_t result = data->result.value; + uint64_t opnd = data->opnds[0].value; + uint64_t expected; + + switch (op->op) { + case Iop_Not1: expected = ~opnd & 0x1; break; + case Iop_Not8: expected = ~opnd & UINT8_MAX; break; + case Iop_Not16: expected = ~opnd & UINT16_MAX; break; + case Iop_Not32: expected = ~opnd & UINT32_MAX; break; + case Iop_Not64: expected = ~opnd & UINT64_MAX; break; + + case Iop_1Uto8: expected = opnd; break; +// case Iop_1Uto16: expected = opnd; break; + case Iop_1Uto32: expected = opnd; break; + case Iop_1Uto64: expected = opnd; break; + + case Iop_1Sto8: + expected = sign_extend(opnd, 1) & UINT8_MAX; + break; + case Iop_1Sto16: + expected = sign_extend(opnd, 1) & UINT16_MAX; + break; + case Iop_1Sto32: + expected = sign_extend(opnd, 1) & UINT32_MAX; + break; + case Iop_1Sto64: + expected = sign_extend(opnd, 1) & UINT64_MAX; + break; + + case Iop_8Uto16: expected = opnd; break; + case Iop_8Uto32: expected = opnd; break; + case Iop_8Uto64: expected = opnd; break; + + case Iop_8Sto16: + expected = sign_extend(opnd, 8) & UINT16_MAX; + break; + case Iop_8Sto32: + expected = sign_extend(opnd, 8) & UINT32_MAX; + break; + case Iop_8Sto64: + expected = sign_extend(opnd, 8) & UINT64_MAX; + break; + + case Iop_16Uto32: expected = opnd; break; + case Iop_16Uto64: expected = opnd; break; + + case Iop_16Sto32: + expected = sign_extend(opnd, 16) & UINT32_MAX; + break; + case Iop_16Sto64: + expected = sign_extend(opnd, 16) & UINT64_MAX; + break; + + case Iop_32Uto64: expected = opnd; break; + + case Iop_32Sto64: + expected = sign_extend(opnd, 32) & UINT64_MAX; + break; + +// case Iop_8to1: expected = opnd & 0x1; break; +// case Iop_16to1: expected = opnd & 0x1; break; + case Iop_16to8: expected = opnd & UINT8_MAX; break; + case Iop_16HIto8: expected = opnd >> 8; break; + break; + + case Iop_32to1: expected = opnd & 0x1; break; + case Iop_32to8: expected = opnd & UINT8_MAX; break; + case Iop_32to16: expected = opnd & UINT16_MAX; break; + case Iop_32HIto16: expected = opnd >> 16; break; + + case Iop_64to1: expected = opnd & 0x1; break; + case Iop_64to8: expected = opnd & UINT8_MAX; break; + case Iop_64to16: expected = opnd & UINT16_MAX; break; + case Iop_64to32: expected = opnd & UINT32_MAX; break; + case Iop_64HIto32: expected = opnd >> 32; break; + + case Iop_CmpNEZ8: +// case Iop_CmpNEZ16: + case Iop_CmpNEZ32: + case Iop_CmpNEZ64: + expected = opnd != 0; + break; + + case Iop_CmpwNEZ32: expected = opnd == 0 ? 0 : UINT32_MAX; break; + case Iop_CmpwNEZ64: expected = opnd == 0 ? 0 : UINT64_MAX; break; + +// case Iop_Left8: +// case Iop_Left16: + case Iop_Left32: { + int32_t opnd_s = (int32_t)opnd; + expected = (opnd_s | -opnd_s) & UINT32_MAX; + break; + } + + case Iop_Left64: { + int64_t opnd_s = (int64_t)opnd; + expected = (opnd_s | -opnd_s) & UINT64_MAX; + break; + } + + default: + panic("%s: operator %s not handled\n", __func__, op->name); + } + + if (verbose > 1) { + printf("expected: value = "); + print_value(stdout, expected, bitsof_irtype(data->result.type)); + printf("\n"); + } + + int ok = 1; + switch (data->result.type) { + case Ity_I1: ok = result == expected; break; + case Ity_I8: ok = result == expected; break; + case Ity_I16: ok = result == expected; break; + case Ity_I32: ok = result == expected; break; + case Ity_I64: ok = result == expected; break; + default: + panic(__func__); + } + + if (! ok) + complain(op, data, expected); +} diff --git a/none/tests/iropt-test/util.c b/none/tests/iropt-test/util.c new file mode 100644 index 0000000000..80e58570fe --- /dev/null +++ b/none/tests/iropt-test/util.c @@ -0,0 +1,106 @@ +/* -*- mode: C; c-basic-offset: 3; -*- */ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2025 Florian Krohm + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. + + The GNU General Public License is contained in the file COPYING. +*/ + +#include <stdio.h> // fprintf +#include <stdlib.h> // exit +#include <stdarg.h> // va_list +#include <inttypes.h> // PRIx... +#include "vtest.h" + + +/* Something bad happened. Cannot continue. */ +void __attribute__((noreturn)) +panic(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + fprintf(stderr, "*** OOPS: "); + vfprintf(stderr, fmt, args); + fputc('\n', stderr); + va_end(args); + exit(1); +} + + +/* Issue a complaint because the result of an operation differs from what + was expected. */ +void +complain(const irop_t *op, const test_data_t *data, uint64_t expected) +{ + fprintf(stderr, "*** Incorrect result for operator %s\n", op->name); + + for (unsigned i = 0; i < op->num_opnds; ++i) { + fprintf(stderr, " opnd %u: ", i); + print_opnd(stderr, &data->opnds[i]); + fprintf(stderr, "\n"); + } + fprintf(stderr, " result: "); + print_opnd(stderr, &data->result); + fprintf(stderr, "\n"); + fprintf(stderr, " expect: "); + print_value(stderr, expected, bitsof_irtype(op->result_type)); + fprintf(stderr, "\n"); +} + + +void +print_value(FILE *fp, uint64_t val, unsigned num_bits) +{ + switch (num_bits) { + case 1: fprintf(fp, "%01" PRIx64, val); break; + case 8: fprintf(fp, "%02" PRIx64, val); break; + case 16: fprintf(fp, "%04" PRIx64, val); break; + case 32: fprintf(fp, "%08" PRIx64, val); break; + case 64: fprintf(fp, "%016" PRIx64, val); break; + case 128: + case 256: + /* fall through */ + default: + panic("%s: num_bits = %u", __func__, num_bits); + } +} + + +void +print_opnd(FILE *fp, const opnd_t *opnd) +{ + fprintf(fp, "value = "); + print_value(fp, opnd->value, bitsof_irtype(opnd->type)); +} + + +unsigned +bitsof_irtype(IRType ty) +{ + switch (ty) { + case Ity_I1: return 1; + case Ity_I8: return 8; + case Ity_I16: return 16; + case Ity_I32: return 32; + case Ity_I64: return 64; + default: + panic(__func__); + } +} diff --git a/none/tests/iropt-test/valgrind.c b/none/tests/iropt-test/valgrind.c new file mode 100644 index 0000000000..e482909b16 --- /dev/null +++ b/none/tests/iropt-test/valgrind.c @@ -0,0 +1,92 @@ +/* -*- mode: C; c-basic-offset: 3; -*- */ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2025 Florian Krohm + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. + + The GNU General Public License is contained in the file COPYING. +*/ + +#include <string.h> // memset +#include "valgrind.h" // VALGRIND_VEX_INJECT_IR +#include "vtest.h" + + +/* Return a completely initialised control block */ +IRICB +new_iricb(const irop_t *op, test_data_t *data) +{ + IRICB_iropt_payload cb; + + memset(&cb, 0x0, sizeof cb); + + cb.op = op->op; + cb.result = (HWord)&data->result.value; + cb.opnd1 = (HWord)&data->opnds[0].value; + cb.opnd2 = (HWord)&data->opnds[1].value; + cb.t_result = data->result.type; + cb.t_opnd1 = data->opnds[0].type; + cb.t_opnd2 = data->opnds[1].type; + + cb.num_operands = op->num_opnds; + + return (IRICB) { .kind = IRICB_iropt, .iropt = cb }; +} + + +/* Insert a client request that will initialize VEX for IR injection */ +void +valgrind_vex_init_for_iri(IRICB *cb) +{ + VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__VEX_INIT_FOR_IRI, cb, 0,0,0,0); +} + + +/* Insert a special opcode that will cause VEX to inject an IR stmt based + on the information passed in the IRICB (in valgrind_vex_init_for_iri). */ +static void +valgrind_vex_inject_ir(void) +{ + VALGRIND_VEX_INJECT_IR(); +} + + +/* Execute the test under valgrind. Well, yes, we're not really executing + it here, just preparing for it... */ +void +valgrind_execute_test(const irop_t *op, test_data_t *data) +{ + if (verbose > 1) + printf("---------- Running a test\n"); + + for (unsigned i = 0; i < op->num_opnds; ++i) { + if (verbose > 1) { + printf("opnd #%u: ", i); + print_opnd(stdout, &data->opnds[i]); + printf("\n"); + } + } + + valgrind_vex_inject_ir(); + + if (verbose > 1) { + printf("result: "); + print_opnd(stdout, &data->result); + printf("\n"); + } +} diff --git a/none/tests/iropt-test/vtest.h b/none/tests/iropt-test/vtest.h new file mode 100644 index 0000000000..d9c1ddaae5 --- /dev/null +++ b/none/tests/iropt-test/vtest.h @@ -0,0 +1,91 @@ +/* -*- mode: C; c-basic-offset: 3; -*- */ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2025 Florian Krohm + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef VTEST_H +#define VTEST_H + +/* Main header file for the iropt tester */ + +#include <stdint.h> // uint64_t +#include <stdio.h> // FILE +#include "libvex.h" // IROp + +/* Everything we want to know about an IROp */ +typedef struct { + const char *name; + IROp op; + IRType result_type; + unsigned num_opnds; + IRType opnd1_type; + IRType opnd2_type; +} irop_t; + + +/* The maximum number of input operands */ +#define MAX_OPERANDS 2 + +/* An operand of an IROp (also used for the result) */ +typedef struct { + IRType type; + uint64_t value; +} opnd_t; + + +/* Carries the data needed to execute and evaluate a test. I.e. + inputs and result. */ +typedef struct { + opnd_t result; + opnd_t opnds[MAX_OPERANDS]; +} test_data_t; + + +/* Convenience macros */ +#define NUM_EL(x) (sizeof x / sizeof *(x)) + +/* Sign-extend VAL which is NUM_BITS wide to 64 bit */ +#define sign_extend(val, num_bits) \ + ((int64_t)((val) << (64 - (num_bits))) >> (64 - (num_bits))) + + +/* Function prototypes */ +void print_opnd(FILE *, const opnd_t *); +void print_value(FILE *, uint64_t, unsigned); + +void test_unary_op(const irop_t *, test_data_t *); +void test_binary_op(const irop_t *, test_data_t *); + +void valgrind_vex_init_for_iri(IRICB *); +void valgrind_execute_test(const irop_t *, test_data_t *); + +IRICB new_iricb(const irop_t *, test_data_t *); + +void panic(const char *, ...) __attribute__((noreturn)); +void complain(const irop_t *, const test_data_t *, uint64_t expected); + +unsigned bitsof_irtype(IRType); + +/* Exported variables */ +extern int verbose; + +#endif // VTEST_H |
From: Mark W. <ma...@so...> - 2025-07-11 18:03:56
|
https://sourceware.org/cgit/valgrind/commit/?id=d7743540064c58d3dcb850804fb29f742757d853 commit d7743540064c58d3dcb850804fb29f742757d853 Author: Mark Wielaard <ma...@kl...> Date: Fri Jul 11 19:58:53 2025 +0200 linux mseal PRE wrapper should First check for overflow According to https://docs.kernel.org/next/userspace-api/mseal.html mseal returns -EINVAL when Address range (addr + len) overflow. The LTP test mseal02 checks this. So do this check first before checking for valid_client_addr (which returns -ENOMEM). Diff: --- coregrind/m_syswrap/syswrap-linux.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/coregrind/m_syswrap/syswrap-linux.c b/coregrind/m_syswrap/syswrap-linux.c index 51a47a16fb..306c3a2f8b 100644 --- a/coregrind/m_syswrap/syswrap-linux.c +++ b/coregrind/m_syswrap/syswrap-linux.c @@ -4315,7 +4315,10 @@ PRE(sys_mseal) /* int mseal(void *addr, size_t len, unsigned long flags) */ PRINT("sys_mseal ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, )", ARG1, ARG2, ARG3); PRE_REG_READ3(int, "mseal", void *, addr, vki_size_t, len, int, flags); - if (!ML_(valid_client_addr)(ARG1, ARG2, tid, "mseal")) + /* First check for overflow which produces EINVAL. */ + if ((Addr)ARG1 > ((SizeT)(-1) - (SizeT)ARG2)) { + SET_STATUS_Failure(VKI_EINVAL); + } else if (!ML_(valid_client_addr)(ARG1, ARG2, tid, "mseal")) SET_STATUS_Failure(VKI_ENOMEM); } |
From: Mark W. <ma...@so...> - 2025-07-11 15:37:26
|
https://sourceware.org/cgit/valgrind/commit/?id=e113cde88cb0f588a76d8ceaef2ce2a630d3b9a9 commit e113cde88cb0f588a76d8ceaef2ce2a630d3b9a9 Author: Mark Wielaard <ma...@kl...> Date: Fri Jul 11 17:36:05 2025 +0200 Add auxprogs/filters/prctl10 The LTP prctl10 test under memcheck has a child process dumping core. Filter out the normal warning about this. Diff: --- auxprogs/filters/prctl10 | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/auxprogs/filters/prctl10 b/auxprogs/filters/prctl10 new file mode 100755 index 0000000000..abed203843 --- /dev/null +++ b/auxprogs/filters/prctl10 @@ -0,0 +1,18 @@ +#!/bin/awk -f + +# Filter out stuff like the following, since it is expected output for the +# prctl10 testcase: + +# ==298306== +# ==298306== Process terminating with default action of signal 11 (SIGSEGV): dumping core +# ==298306== General Protection Fault +# ==298306== at 0x40152B: verify_prctl (prctl10.c:75) +# ==298306== by 0x40A894: fork_testrun.isra.0 (tst_test.c:1617) +# ==298306== by 0x40CC53: tst_run_tcases (tst_test.c:1970) +# ==298306== by 0x4011BD: main (tst_test.h:729) + +skip = 0 +/==[0-9][0-9]*==/ { skip = 1 } +/Process terminating with default action of signal 11/ { skip = 1; skipblock=1 } +/by.*main.*tst_test.h/ { skip = 1; skipblock=0 } +!skip && !skipblock { print } |