When targeting 32-bit Windows (I have not tried 64-bit Windows, sorry), I get an assertion error when running ./bin/test.exe udiv_bitvec
.
To diagnose this failure, I modified test/testbv.c
as follows (the print of bv1
and bv2
is superfluous, given the print of a1
and a2
, but that shouldn't change anything):
- assert (ares == bres);
+ if (ares != bres)
+ {
+ printf("***\n");
+ printf("bv1 = %" PRIu64 "\n", btor_bv_to_uint64(bv1));
+ printf("bv2 = %" PRIu64 "\n", btor_bv_to_uint64(bv2));
+ printf("a1 = %" PRIu64 "\n", a1);
+ printf("a2 = %" PRIu64 "\n", a2);
+ printf("ares = %" PRIu64 "\n", ares);
+ printf("bres = %" PRIu64 "\n", bres);
+ printf("***\n");
+ }
+ // assert (ares == bres);
and I get the following output:
***
bv1 = 4294978274
bv2 = 0
a1 = 4294978274
a2 = 0
ares = 4294967295
bres = 8589934591
***
***
bv1 = 12315
bv2 = 0
a1 = 12315
a2 = 0
ares = 4294967295
bres = 8589934591
***
***
bv1 = 19733
bv2 = 0
a1 = 19733
a2 = 0
ares = 4294967295
bres = 8589934591
***
So, of the 100000
tests that get run, we only see assert
ion failures when a2
is 0
.
This particular test does this:
binary_bitvec (udiv, btor_bv_udiv, BTOR_TEST_BITVEC_TESTS, 33);
where the last argument is the bit-width (33
in this case). Furthermore the function udiv
looks like this:
udiv (uint64_t x, uint64_t y, uint32_t bw)
{
if (y == 0) return UINT32_MAX % (uint64_t) pow (2, bw);
return (x / y) % (uint64_t) pow (2, bw);
}
So, for udiv
, if the second argument (== bv2
) is 0
, then it returns something based off of UINT32_MAX
, while I imagine (and I haven't checked) that btor_bv_udiv
is "width agnostic". Furthermore, all of the variables inside of the function binary_bitvec
(the callee of udiv
) are uint64_t
s.
Interestingly, when I run this test (with these prints) on 32-bit Linux, then the lowest value I get for bv1
/a1
is 48121
and the lowest for bv2
/a2
is 96199
(i.e., I never seem to get 0
for bv2
).
If I create a hand-written test on any Linux architecture (both 32-bit and 64-bit) that does something like this:
void udiv_zero_test(void)
{
BtorBitVector *bv1, *bv2, *res;
uint64_t a1, a2, ares, bres;
uint32_t bit_width = 33;
// 12315 and 0 come from the failing Windows tests
bv1 = btor_bv_uint64_to_bv (g_mm, 12315, bit_width);
bv2 = btor_bv_uint64_to_bv (g_mm, 0, bit_width);
res = btor_bv_udiv(g_mm, bv1, bv2);
a1 = btor_bv_to_uint64 (bv1);
a2 = btor_bv_to_uint64 (bv2);
ares = udiv(a1, a2, bit_width);
bres = btor_bv_to_uint64 (res);
if (ares != bres)
{
printf("***\n");
printf("bv1 = %" PRIu64 "\n", btor_bv_to_uint64(bv1));
printf("bv2 = %" PRIu64 "\n", btor_bv_to_uint64(bv2));
printf("a1 = %" PRIu64 "\n", a1);
printf("a2 = %" PRIu64 "\n", a2);
printf("ares = %" PRIu64 "\n", ares);
printf("bres = %" PRIu64 "\n", bres);
printf("***\n");
}
// assert (ares == bres);
btor_bv_free (g_mm, res);
btor_bv_free (g_mm, bv1);
btor_bv_free (g_mm, bv2);
}
(rather than the call to random_bv
) then I do see this failure (again, on any Linux architecture).
Importantly: if I change the function udiv
to do its modulo calculation based up on UINT64_MAX
then the tests no longer fail!
Some questions:
- Is it correct that
random_bv
can return 0?
- What does it mean that
random_bv
never returns 0 on Linux, but does on Windows (maybe rand()
is just "less random" on Windows)?
- Is there an issue that Boolector has no tests that explicitly check
bv2
being 0?
- Is it correct that
udiv
does its modulo calculations based off UINT32_MAX
when working on 64-bit operands?
If you are happy, I would suggest that we:
- Create a new bit-vector test-suite that does the same as
udiv_bitvec
, but where bv2
is always hard-coded to be 0
(maybe something like: udiv_bitvec_zero
)
- Modify the
udiv
function to base its calculations off of UINT64_MAX
I am more than happy to do this work.