[m-rev.] for review: avoid undefined behaviour of int.abs.

Julien Fischer jfischer at opturion.com
Mon Jan 15 03:56:35 AEDT 2018


For review by anyone.

The following is what was discussed back in Oct. 2016, except that I
haven't added a new exception type specific for overflows (yet).

I will do something similar for ther other signed integer types once
this is reviewed adn committed.

-----------------------

Avoid undefined behaviour of int.abs.

library.m:
     Make int.abs throw an exception for int.min_int.

     Add the new function unchecked_abs/1, whose behaviour is
     undefined for int.min_int.

     Add the new function nabs/1 which computes the negative
     absolute value of an int   Unlike abs, this is defined for
     all ints.

NEWS:
     Announce the above.

     Unrelated change: list int64 and uint64 as reserved type names.

Julien.

diff --git a/NEWS b/NEWS
index 05be405..2e96a9a 100644
--- a/NEWS
+++ b/NEWS
@@ -44,9 +44,9 @@ Changes that may break compatibility:
    type names are:

        int
-      int{8,16,32}
+      int{8,16,32,64}
        uint
-      uint{8,16,32}
+      uint{8,16,32,64}
        float
        character
        string
@@ -113,6 +113,10 @@ Changes that may break compatibility:
    int.legacy_left_shift/2 and int.legacy_right_shift/2.  These functions
    will be deleted in a future release.

+* We have changed the semantics of int.abs/1 so that it throws an exception
+  if its argument is equal to int.min_int.  The old behaviour of this function
+  is provided by the the new function int.unchecked_abs/1.
+
  Changes to the Mercury language:

  * We have added a new primitive type, uint, which is an unsigned integer type
@@ -386,9 +390,10 @@ Changes to the Mercury standard library:
    queue ADT.  This is a blend between a priority queue and a map.  This was
    contributed by Matthias Güdemann.

-* We have added the following predicate to the int module:
+* The following predicates and functions have been added to the int module:

    - all_true_in_range/3
+  - nabs/1

  * We have added a predicate named is_dummy_context to the term module.

diff --git a/library/int.m b/library/int.m
index 4dad325..e0b7cd6 100644
--- a/library/int.m
+++ b/library/int.m
@@ -1,7 +1,8 @@
  %---------------------------------------------------------------------------%
  % vim: ft=mercury ts=4 sw=4 et
  %---------------------------------------------------------------------------%
-% Copyright (C) 1994-2011 The University of Melbourne.
+% Copyright (C) 1994-2012 The University of Melbourne.
+% Copyright (C) 2013-2018 The Mercury team.
  % This file may only be copied under the terms of the GNU Library General
  % Public License - see the file COPYING.LIB in the Mercury distribution.
  %---------------------------------------------------------------------------%
@@ -52,11 +53,24 @@

  %---------------------------------------------------------------------------%

-    % Absolute value.
+    % abs(X) returns the absolute value of X.
+    % Throws an exception if X = int.min_int.
      %
  :- func abs(int) = int.
  :- pred abs(int::in, int::out) is det.

+    % unchecked(X) returns the absolute value of X, except that the result is
+    % undefined if X = int.min_int.
+    %
+:- func unchecked_abs(int) = int.
+
+    % nabs(X) returns the negative absolute value of X.
+    % Unlike abs/1 this function is defined for X = int.min_int.
+    %
+:- func nabs(int) = int.
+
+%---------------------------------------------------------------------------%
+
      % Maximum.
      %
  :- func max(int, int) = int.
@@ -584,12 +598,28 @@ abs(Num) = Abs :-
      abs(Num, Abs).

  abs(Num, Abs) :-
+    ( if Num = int.min_int then
+        throw(software_error("int.abs: abs(min_int) would overflow"))
+    else
+        Abs = unchecked_abs(Num)
+    ).
+
+unchecked_abs(Num) =
      ( if Num < 0 then
-        Abs = 0 - Num
+        0 - Num
      else
-        Abs = Num
+        Num
      ).

+nabs(Num) =
+    ( if Num > 0 then
+        -Num
+    else
+        Num
+    ).
+
+%---------------------------------------------------------------------------%
+
  max(X, Y) = Max :-
      max(X, Y, Max).


More information about the reviews mailing list