dylan-lang / opendylan

Open Dylan compiler and IDE
http://opendylan.org/
Other
458 stars 69 forks source link

generic-arithmetic and big-integers on OS X #863

Open kibook opened 9 years ago

kibook commented 9 years ago

library.dylan

module: dylan-user

define library test
  use common-dylan;
  use generic-arithmetic;
  use big-integers;
  use io;
end library test;

define module test
  use generic-arithmetic-common-dylan;
  use format-out;
end module test;

test.dylan

module: test

let x :: <integer> = 1000000000;
let y :: <integer> = 5;

format-out("%s\n", x < y);
format-out("%s\n", number-to-string(x));

on Windows (32-bit):

#f
1000000000

on Linux (32-bit)

#f
1000000000

on OS X (32-bit)

#t
-419496729600
waywardmonkeys commented 9 years ago

This is awesome... a simple test case for this bug is very useful. I will see about taking a look ...

waywardmonkeys commented 9 years ago

This is interesting in the generated C:

static _KLdouble_integerGVKe K3 = {
  &KLdouble_integerGVKeW /* wrapper */,
  0x3B9ACA00L,
  0xFFFFFFF6L
};

/* Code */

dylan_value Ktest_bugVbugI () {
  dylan_value T0;
  dylan_value T1;
  _KLsimple_object_vectorGVKd_1 T2 = {&KLsimple_object_vectorGVKdW, (dylan_value) 5};
  _KLsimple_object_vectorGVKd_1 T3 = {&KLsimple_object_vectorGVKdW, (dylan_value) 5};

  T2.vector_element_[0] = &KPtrueVKi;
  Kformat_outYformat_outVioMM0I(&K2, &T2);
  CONGRUENT_CALL_PROLOG(&Knumber_to_stringYcommon_extensionsVcommon_dylan, 1);
  T0 = CONGRUENT_CALL1(&K3);
  T3.vector_element_[0] = T0;
  T1 = Kformat_outYformat_outVioMM0I(&K2, &T3);
  MV_SET_COUNT(0);
  return(T1);
}
waywardmonkeys commented 9 years ago

The code looks the same in a 64 bit OS X build ... but it segfaults there.

The working builds are from HARP, so I suspect this is a bug involving the C backend somehow. Seems like it'll be fun.

waywardmonkeys commented 9 years ago

The segfault in 64 bit is stack overflow from infinite recursion:

    frame #174586: 0x0000000100311e99 libbig-integers.dylib`Kprocess_integerF275I(buffer_=0x000000010112e460, arg_=<unavailable>) + 169 at double-integer.c:14403
    frame #174587: 0x0000000100311e99 libbig-integers.dylib`Kprocess_integerF275I(buffer_=0x000000010112e460, arg_=<unavailable>) + 169 at double-integer.c:14403
    frame #174588: 0x0000000100311e99 libbig-integers.dylib`Kprocess_integerF275I(buffer_=0x000000010112e460, arg_=<unavailable>) + 169 at double-integer.c:14403
    frame #174589: 0x0000000100311e99 libbig-integers.dylib`Kprocess_integerF275I(buffer_=0x000000010112e460, arg_=<unavailable>) + 169 at double-integer.c:14403
    frame #174590: 0x0000000100311e99 libbig-integers.dylib`Kprocess_integerF275I(buffer_=0x000000010112e460, arg_=<unavailable>) + 169 at double-integer.c:14403
    frame #174591: 0x0000000100311e99 libbig-integers.dylib`Kprocess_integerF275I(buffer_=0x000000010112e460, arg_=<unavailable>) + 169 at double-integer.c:14403
    frame #174592: 0x0000000100311e99 libbig-integers.dylib`Kprocess_integerF275I(buffer_=0x000000010112e460, arg_=<unavailable>) + 169 at double-integer.c:14403
    frame #174593: 0x0000000100311e99 libbig-integers.dylib`Kprocess_integerF275I(buffer_=0x000000010112e460, arg_=<unavailable>) + 169 at double-integer.c:14403
    frame #174594: 0x0000000100311e99 libbig-integers.dylib`Kprocess_integerF275I(buffer_=0x000000010112e460, arg_=<unavailable>) + 169 at double-integer.c:14403
    frame #174595: 0x0000000100311e99 libbig-integers.dylib`Kprocess_integerF275I(buffer_=0x000000010112e460, arg_=<unavailable>) + 169 at double-integer.c:14403
    frame #174596: 0x0000000100311e99 libbig-integers.dylib`Kprocess_integerF275I(buffer_=0x000000010112e460, arg_=<unavailable>) + 169 at double-integer.c:14403
    frame #174597: 0x0000000100311b17 libbig-integers.dylib`Knumber_to_stringYcommon_extensionsVcommon_dylanMbig_integersM0I(n_=0x0000000100004268) + 599 at double-integer.c:14361

The corresponding code is:

static dylan_value Kprocess_integerF275I (dylan_value buffer_, dylan_value arg_) {
  dylan_value T2_0;
  dylan_value T2_1;
  dylan_value quotient_;
  dylan_value remainder_;
  dylan_value T5;
  dylan_value T6;
  dylan_value T7;

  // /opt/deft/sources/lib/big-integers/double-integer.dylan:963
  // /opt/deft/sources/lib/big-integers/double-integer.dylan:964
  CONGRUENT_CALL_PROLOG(&KtruncateSVgeneric_arithmetic, 2);
  T2_0 = CONGRUENT_CALL2(arg_, (dylan_value) 41);
  T2_1 = MV_GET_ELT(1);
  // /opt/deft/sources/lib/big-integers/double-integer.dylan:964
  quotient_ = T2_0;
  // /opt/deft/sources/lib/big-integers/double-integer.dylan:964
  remainder_ = T2_1;
  // /opt/deft/sources/lib/big-integers/double-integer.dylan:965
  CONGRUENT_CALL_PROLOG(&KzeroQVKd, 1);
  T5 = CONGRUENT_CALL1(quotient_);
  // /opt/deft/sources/lib/big-integers/double-integer.dylan:965
  if (T5 == &KPfalseVKi) {
    // /opt/deft/sources/lib/big-integers/double-integer.dylan:966
    Kprocess_integerF275I(buffer_, quotient_);     // <---- INFINITE RECURSION HERE
  }
  // /opt/deft/sources/lib/big-integers/double-integer.dylan:965
  // /opt/deft/sources/lib/big-integers/double-integer.dylan:968
  CONGRUENT_CALL_PROLOG(&KelementVKd, 3);
  T6 = CONGRUENT_CALL3(Dnumber_charactersYbig_integers_internalVbig_integers, remainder_, &KPempty_vectorVKi);
  // /opt/deft/sources/lib/big-integers/double-integer.dylan:968
  KaddXVKdMM3I(buffer_, T6);
  // /opt/deft/sources/lib/big-integers/double-integer.dylan:963
  T7 = &KPfalseVKi;
  // /opt/deft/sources/lib/big-integers/double-integer.dylan:963
  MV_SET_COUNT(0);
  return(T7);
}
waywardmonkeys commented 9 years ago

The corresponding Dylan code to that is:

  local method process-integer (arg :: <integer>) => ()
          let (quotient, remainder) = truncate/(arg, 10);
          unless (zero?(quotient))
            process-integer(quotient)
          end;
          add!(buffer, $number-characters[remainder])
        end method process-integer;
waywardmonkeys commented 9 years ago

Should have mentioned earlier... It is gas imaging that the C shows that the comparison was constant folded to the true value. That makes the source of this error more interesting!

waywardmonkeys commented 9 years ago

Of interest, K3 is the <double-integer> that is created for storing the larger value:

(dylan_value) $0 = 0x00005150 {<double-integer>: 4294967286}
(lldb) print K3
(_KLdouble_integerGVKe) $1 = {
  wrapper = 0x0012971c {<mm-wrapper>}
  PPdouble_integer_low_ = 1000000000
  PPdouble_integer_high_ = -10
}

So, why is the high part -10?

waywardmonkeys commented 9 years ago

Also, small correction to the bug report ... the value printed on OS X is:

#t
-41949672960

Which corresponds to (-10 << 32) + 1000000000

(The initial report had an extra 0 at the end.)