[MLton] Memory problems with latest CVS?
Matthew Fluet
fluet@cs.cornell.edu
Fri, 10 Sep 2004 09:50:29 -0400 (EDT)
> > xmlShrink1 starting
> > IntInf_mul (0x77359401, 0x276f35b9, 16)
> > fill (0x77359401, 0xbfffd350, 0xbfffd328)
> > fill (0x276f35b9, 0xbfffd340, 0xbfffd320)
>
> It would be interesting to know if this call to IntInf_mul returned.
It does not. Here's the backtrace with a runtime compiled without
-fomit-frame-pointer:
#0 0xb74ee780 in _int_realloc () from /lib/tls/libc.so.6
#1 0xb74ed136 in realloc () from /lib/tls/libc.so.6
#2 0xb74f0303 in realloc_hook_ini () from /lib/tls/libc.so.6
#3 0xb74ed06c in realloc () from /lib/tls/libc.so.6
#4 0x08e24c3b in __gmp_default_reallocate ()
#5 0x08e1cdd7 in __gmpz_realloc ()
#6 0x08e1cc18 in __gmpz_mul ()
#7 0x08e0dd8a in binary (lhs=0x77359401 "", rhs=0x2808559f "", bytes=16,
binop=0x8e1ca00 <__gmpz_mul>) at basis/IntInf.c:200
#8 0x08e0de50 in IntInf_mul (lhs=0x77359401 "", rhs=0x2808559f "", bytes=16)
at basis/IntInf.c:222
#9 0x08674f0c in Chunk197 () at mlton-stubs.197.c:9220
I added the following to runtime/basis/IntInf.c in the fill function:
if (DEBUG_INT_INF) {
char buf[2048];
char *str;
str = mpz_get_str(buf, 10, res);
assert(str == buf);
fprintf (stderr, "fill (arg == %s)\n", buf);
}
So, this prints out the base 10 representation of every bignum that we
import from ML into an __mpz_struct. Now the last call to IntInf_mull
looks like:
IntInf_mul (0x77359401, 0x2808559f, 16)
fill (0x77359401, 0xbfffc9d0, 0xbfffc9a8)
fill (arg == 1000000000)
fill (0x2808559f, 0xbfffc9c0, 0xbfffc9a0)
fill (arg == 335817423)
I'm pretty certain that the bytes is off -- 16 bytes accounts for the
counter, size, header, and sign words, and doesn't leave any room for the
actual bignum; certainly not enough for the product of those two numbers.
That would explain why __gmpz_realloc is being called -- because we didn't
provide enough space for the bignum. We should be concerned about
gmpz_realloc's right? We should always be providing enough space the
results up front, so gmp shouldn't ever need to reallocate.
Henry, can you look at basis-library/integer/int-inf.sml? Is this code
for big integer multiplication right:
(*
* bigInt multiplication.
*)
local
val carry: Word.word ref = ref 0w0
in
fun bigMul (lhs: bigInt, rhs: bigInt): bigInt =
let
val res =
if areSmall (lhs, rhs)
then let
val lhsv = stripTag lhs
val rhs0 = zeroTag rhs
val ans0 = Prim.smallMul (lhsv, rhs0, carry)
in
if (! carry) = Word.~>> (ans0, 0w31)
then SOME (Prim.fromWord (incTag ans0))
else NONE
end
else NONE
in
case res of
NONE =>
dontInline
(fn () =>
Prim.* (lhs, rhs, reserve (size lhs +? size rhs, 0)))
| SOME i => i
end
end
It seems to me that if we are in the situation described above -- two
"small" big-nums, but whose product is a "big" big-num, then we'll try the
Prim.smallMul, fail because of the carry and so try Prim.*, but the sizes
of "small" big-nums are 0, so we'll reserve only enough for the "big"
big-num header.