[PATCH] 6779290: Casts in SharedRuntime::f2i, f2l, d2i and d2l rely on undefined behaviour

Gary Benson gbenson at redhat.com
Wed Dec 3 03:52:05 PST 2008


Hi all,

In C++, the result of an overflowing cast to a signed integer is
undefined.  The functions used to implement f2i, f2l, d2i and d2l,
however, rely on the assumption that the result of an overflowing
cast will be the largest magnitude number with the correct sign.
The attached patch fixes.

Cheers,
Gary

-- 
http://gbenson.net/
-------------- next part --------------
diff -r dcb49b482348 -r f63a8dee04ae openjdk/hotspot/src/share/vm/runtime/sharedRuntime.cpp
--- openjdk/hotspot/src/share/vm/runtime/sharedRuntime.cpp	Mon Nov 03 14:00:57 2008 +0000
+++ openjdk/hotspot/src/share/vm/runtime/sharedRuntime.cpp	Mon Nov 03 15:56:17 2008 +0000
@@ -173,64 +173,46 @@ JRT_END
 
 
 JRT_LEAF(jint, SharedRuntime::f2i(jfloat  x))
-  if (g_isnan(x)) {return 0;}
-  jlong lltmp = (jlong)x;
-  jint ltmp   = (jint)lltmp;
-  if (ltmp == lltmp) {
-    return ltmp;
-  } else {
-    if (x < 0) {
-      return min_jint;
-    } else {
-      return max_jint;
-    }
-  }
+  if (g_isnan(x))
+    return 0;
+  if (x >= (jfloat) max_jint)
+    return max_jint;
+  if (x <= (jfloat) min_jint)
+    return min_jint;
+  return (jint) x;
 JRT_END
 
 
 JRT_LEAF(jlong, SharedRuntime::f2l(jfloat  x))  
-  if (g_isnan(x)) {return 0;}
-  jlong lltmp = (jlong)x;
-  if (lltmp != min_jlong) {
-    return lltmp;
-  } else {
-    if (x < 0) {
-      return min_jlong;
-    } else {
-      return max_jlong;
-    }
-  }
+  if (g_isnan(x))
+    return 0;
+  if (x >= (jfloat) max_jlong)
+    return max_jlong;
+  if (x <= (jfloat) min_jlong)
+    return min_jlong;
+  return (jlong) x;
 JRT_END
 
 
 JRT_LEAF(jint, SharedRuntime::d2i(jdouble x))
-  if (g_isnan(x)) {return 0;}
-  jlong lltmp = (jlong)x;
-  jint ltmp   = (jint)lltmp;
-  if (ltmp == lltmp) {
-    return ltmp;
-  } else {
-    if (x < 0) {
-      return min_jint;
-    } else {
-      return max_jint;
-    }
-  }
+  if (g_isnan(x))
+    return 0;
+  if (x >= (jdouble) max_jint)
+    return max_jint;
+  if (x <= (jdouble) min_jint)
+    return min_jint;
+  return (jint) x;
 JRT_END
 
 
 JRT_LEAF(jlong, SharedRuntime::d2l(jdouble x))
-  if (g_isnan(x)) {return 0;}
-  jlong lltmp = (jlong)x;
-  if (lltmp != min_jlong) {
-    return lltmp;
-  } else {
-    if (x < 0) {
-      return min_jlong;
-    } else {
-      return max_jlong;
-    }
-  }
+  if (g_isnan(x))
+    return 0;
+  if (x >= (jdouble) max_jlong)
+    return max_jlong;
+  if (x <= (jdouble) min_jlong)
+    return min_jlong;
+  return (jlong) x;
 JRT_END
 
 
-------------- next part --------------
/* @test
 * @bug 6779290
 * @summary Check that [fd]2[il] overflow correctly
 */

public class Test6779290 {
  public static void check_f2i(int expect) {
    float check = expect;
    check *= 2;
    int actual = (int) check;
    if (actual != expect)
      throw new RuntimeException("expecting " + expect + ", got " + actual);
  }

  public static void check_f2l(long expect) {
    float check = expect;
    check *= 2;
    long actual = (long) check;
    if (actual != expect)
      throw new RuntimeException("expecting " + expect + ", got " + actual);
  }

  public static void check_d2i(int expect) {
    double check = expect;
    check *= 2;
    int actual = (int) check;
    if (actual != expect)
      throw new RuntimeException("expecting " + expect + ", got " + actual);
  }

  public static void check_d2l(long expect) {
    double check = expect;
    check *= 2;
    long actual = (long) check;
    if (actual != expect)
      throw new RuntimeException("expecting " + expect + ", got " + actual);
  }

  public static void main(String[] args) {
    check_f2i(Integer.MAX_VALUE);
    check_f2i(Integer.MIN_VALUE);
    check_f2l(Long.MAX_VALUE);
    check_f2l(Long.MIN_VALUE);
    check_d2i(Integer.MAX_VALUE);
    check_d2i(Integer.MIN_VALUE);
    check_d2l(Long.MAX_VALUE);
    check_d2l(Long.MIN_VALUE);
  }
}


More information about the hotspot-dev mailing list