Skip to content

Int32 operations do not properly raise Overflow #370

Closed

Description

@Skyb0rg007

Version

110.99.8 (Latest)

Operating System

  • Any
  • Linux
  • macOS
  • Windows
  • Other Unix

OS Version

Ubuntu 25.04

Processor

  • Any
  • Arm (using Rosetta)
  • PowerPC
  • Sparc
  • x86 (32-bit)
  • x86-64 (64-bit)
  • Other

System Component

Basis Library

Severity

Minor

Description

Int32 operations that should raise Overflow in some circumstances (Int32.*, Int32.div, Int32.quot) do not raise the exception, instead returning an incorrect value.

Transcript

- Int32.* (~0x80000000, ~1);
val it = ~2147483648 : Int32.int

Expected Behavior

- Int32.* (~0x80000000, ~1);
uncaught exception Overflow [overflow]
  raised at: <file stdIn>

Steps to Reproduce

See the transcript

Additional Information

This same issue happens with other values, and can result in Int32.int values that are out-of-bounds.

- Control.CG.printit := true;
val it = () : unit
- Int32.* (~0x80000000, ~8);

[omitted...]

[after closure ...]

std v52(v53[PV],v31[PV],v44[C],v45[PV],v46[PV],v47[PV],v33[PR2]) =
   v33.0 -> v54[FN]
   v48(v59[PV],v58[PV],v57[PV],v56[PV],v55[I]) =
      {v55} -> v60
      v58.1 -> v61[PV]
      v58.0 -> v62[C]
      v62(v62,v61,v57,v56,v60)
   {RK_CONT 2,v44,v45} -> v63
   v54.0 -> v64[FN]
   v64(v64,v54,(L)v48,v63,v46,v47,(I63t)~2147483648,(I63t)~8)

Starting feedback...Finished
v52     E  4    3
v48     C  3    3
***********************************************
std v52(v53[PV],v31[PV],v44[C],v45[PV],v46[PV],v47[PV],v33[PR2]) =
   v33.0 -> v54[FN]
   {RK_CONT 2,v44,v45} -> v63
   v54.0 -> v64[FN]
   v64(v64,v54,(L)v48,v63,v46,v47,(I63t)~2147483648,(I63t)~8)
***********************************************
***********************************************
std_cont v48(v59[PV],v58[PV],v57[PV],v56[PV],v55[I]) =
   {v55} -> v60
   v58.1 -> v61[PV]
   v58.0 -> v62[C]
   v62(v62,v61,v57,v56,v60)
***********************************************
val it = 17179869184 : Int32.int
- 17179869184 : Int32.int;
stdIn:6.1-6.12 Error: literal '17179869184' is too large for type ?.int32

From this transcript you can also see that the issue is not in the cps optimizer

Email address

you know my email by now

Activity

  1. JohnReppy commented on Oct 5, 2025

    @JohnReppy
    Contributor

    This is quite strange, since the Int32 operations are wrapped with explicit overflow checks in system/smlnj/init/target64-init.sml.

            local
              fun i32chk oper args = let
                    val res = oper args
                    in
                      if InLine.int_lt(toInt res, ~2147483648)
                      orelse InLine.int_lt(2147483647, toInt res)
                        then raise Assembly.Overflow
                        else res
                    end
            in
            val op +    : int32 * int32 -> int32  = i32chk InLine.int32_add
            ...
            end
  2. Skyb0rg007 commented on Oct 6, 2025

    @Skyb0rg007
    ContributorAuthor

    I would need to check, but the toInt function is bound to InLine.int32_to_int, which may be silently masking the upper bits off the value. If that is the case, then those conditions could never be true.

  3. JohnReppy commented on Oct 6, 2025

    @JohnReppy
    Contributor

    Good suggestion. The 32->63 bit conversion assumes that 32-bit ints are not sign extended, so it does a left shift followed by an arithmetic right shift to get the sign bits right. I think that the fix is to use the COPY primop when converting smaller signed integers to bigger ones (instead of the EXTEND primop). Then, as long as smaller signed integers are always represented internally as 63-bit signed values, things should work okay. In the development branch, we will have to revert this change if we switch to using native 32-bit operations.

  4. added
    basis-libproblem with Standard ML Basis library
    fixed-in-110.99.9issues fixed in the 110.99.9 release
    on Oct 6, 2025
  5. changed the title [-]Int32 operations do not properly Overflow[/-] [+]`Int32` operations do not properly raise `Overflow`[/+] on Oct 6, 2025
  6. JohnReppy commented on Oct 6, 2025

    @JohnReppy
    Contributor

    It turns out that switching to COPY does not quite work, since it breaks some of the conversions. The problem is that EXTEND is used for both WordN.toIntX and IntN.toInt conversions and we cannot always tell the difference. Instead, I have fixed this bug by using a cast in the i32chk function (instead of the toInt conversion).

  7. added a commit that references this issue on Oct 6, 2025
  8. Skyb0rg007 commented on Oct 7, 2025

    @Skyb0rg007
    ContributorAuthor

    I built the current HEAD, and the issue is fixed on my machine. Might be worth adding a test to the regressions-tests repo to make sure it doesn't come back.

  9. Skyb0rg007 commented on Oct 7, 2025

    @Skyb0rg007
    ContributorAuthor
    - Int32.minInt;
    
    unexpected exception (bug?) in SML/NJ: Overflow [overflow]
      raised at: smlnj/init/target64-inline.sml:182.18-182.35
                 ../compiler/TopLevel/print/ppobj.sml:377.24
                 ../compiler/TopLevel/print/ppobj.sml:377.24
                 ../compiler/TopLevel/print/ppobj.sml:377.24
                 ../compiler/TopLevel/interact/evalloop.sml:45.54
    
  10. Skyb0rg007 commented on Oct 7, 2025

    @Skyb0rg007
    ContributorAuthor
    Standard ML of New Jersey [Version 110.99.9; 64-bit; October 6, 2025]
    - Word32.fromLargeInt (Int32.toLarge (Option.valOf Int32.minInt));
    [autoloading]
    [library $SMLNJ-BASIS/basis.cm is stable]
    [library $SMLNJ-BASIS/(basis.cm):basis-common.cm is stable]
    [autoloading done]
    val it = 0wx7FFFFFFF80000000 : Word32.word
    - Word32.fromLargeInt (Int32.toLarge (Option.valOf Int32.minInt - 1));
    
    uncaught exception Overflow [overflow]
      raised at: smlnj/init/target64-inline.sml:182.18-182.35
    - Word32.fromLargeInt (Int32.toLarge (Option.valOf Int32.minInt + 1));
    val it = 0wx7FFFFFFF80000001 : Word32.word
    
  11. JohnReppy commented on Oct 7, 2025

    @JohnReppy
    Contributor

    This bug is different and should have its own issue. I believe that we are seeing a problem in the string conversion code that was previously masked by the fact that Overflow was not being raised when it should have been.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    basis-libproblem with Standard ML Basis librarybugSomething isn't workingfixed-in-110.99.9issues fixed in the 110.99.9 release

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions