acton icon indicating copy to clipboard operation
acton copied to clipboard

Weird state for int after multiplication with 0

Open ciaran2 opened this issue 10 months ago • 6 comments

Acton Version

0.24.1.20250219.1.43.32

Steps to Reproduce and Observed Behavior

Multiplication by 0 produces a bigint 0 value that is in an odd state that prevents it from converting to u32 correctly.

foo = 6 * 0
foo32 = u32(foo)
Unhandled exception in actor: u32_bug.main[-12]:
  ValueError: u32(): value 0 out of range for type u32

The value compares equal to a literal 0 and replacing it with a literal 0 causes it to convert to u32 correctly.

foo = 6 * 0
# injecting this conditional gets rid of the exception
if foo == 0:
    foo = 0
foo32 = u32(foo)

Expected Behavior

Multiplying by 0 should produce a 0 value completely equivalent to a literal 0.

ciaran2 avatar Feb 19 '25 21:02 ciaran2

@sydow I think this is for you!

in u32 (and presumably other uX) we check size of the int, which I think is the number of limbs.


B_u32 B_u32G_new(B_atom a, B_int base) {
    B_int b = B_intG_new(a, base);
    unsigned long n = b->val.n[0];
    long sz = b->val.size;
    if (sz > 1 || sz < 0 || n > UINT_MAX) {
        char errmsg[1024];
        snprintf(errmsg, sizeof(errmsg), "u32(): value %s out of range for type u32",get_str(&b->val));
        $RAISE((B_BaseException)$NEW(B_ValueError,to$str(errmsg)));
    } 
    return toB_u32(n);
}

since we did a multiplication just before, I presume that we have allocated extra limbs in order to hold the potentially larger result. The result is in fact not multi-limb but we haven't shrunk down for some reason? not sure what the intention is...

plajjan avatar Feb 20 '25 09:02 plajjan

I cannot reproduce this (using actonc version 0.24.1.20250219.16.4.30). Extending to a complete program

foo = 6 * 0
foo32 = u32(foo)

actor main(env):
    print(foo, foo32)
    env.exit(0)

it compiles and runs correctly (printing 0 0). Moving the two assignments to the actor body doesn't change anything.

sydow avatar Feb 20 '25 10:02 sydow

I have reproduced it on my end with actonc 0.24.1.20250220.12.11.46, even after a cache purge, running actonc on the following complete source file:

actor main(env):

    foo = 6 * 0
    #if foo == 0:
    #    foo = 0
    foo32 = u32(foo)

    print(foo, foo32)

    env.exit(0)

Here is this output of ldd with the resulting executable, on the off-chance that it becomes relevant:

        linux-vdso.so.1 (0x00007ffd53ad5000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007b171c3fc000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007b171c3f7000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007b171c000000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007b171c3f2000)
        /lib64/ld-linux-x86-64.so.2 (0x00007b171c4ed000)

ciaran2 avatar Feb 20 '25 14:02 ciaran2

I added some debug information to the exception message producing the following puzzling result:

Unhandled exception in actor: u32_bug.main[-12]:
  ValueError: u32(): value 0 out of range for type u32 (size 0) (sz > 1: 0) (sz < 0: 0) (n > UINT_MAX: 1) (n: 123506963419088) (UINT_MAX: 18446744073709551615)

ciaran2 avatar Feb 20 '25 15:02 ciaran2

Interesting!

I note three things:

  • I would have expected the constant UINT_MAX to be 2^32-1, but on your system it is 2^64-1 (which I would expect to be the value of ULONG_MAX). I guess this shows that we must change to names that include bit length, i.e. UINT32_MAX and UINT64_MAX, etc. We have known that for long,...

  • It is still puzzling that n > UINT_MAX returns 1 with the given values for n and UINT_MAX. The LHS is an UINT64 and the RHS an UINT32. But it isn't on your system... Hmm; I love C.

  • There is an additional logical error in the code for C function u32: we should only check if n>UINT32_MAX if sz > 0 (or, equivalently if sz==1). If sz==0, n can have whatever value. Phuuh!

I will change this in all u64, u32, u16, i64, i32 and i16 tomorrow. I hope stdint.h gives these MAX and MIN constants on all plarforms? We should of course change int, short and long to properly sized types everywhere, but I don't promise to do that now.

And I need to understand how to do the check if n>UINT32_MAX, etc.

sydow avatar Feb 20 '25 16:02 sydow

I would like to suggest that we add assert statements to like all of these functions. I think we would catch a lot of these kind of things so much quicker. The more asserts the better. Document our assumptions using asserts

plajjan avatar Feb 20 '25 19:02 plajjan