* ext/bigdecimal/bigdecimal.c (VpAlloc): avoid ALLOCA_N() to avoid
segmentation fault caused by (insanely) long decimal values. [ruby-dev:37189] fix #794 * ext/bigdecimal/bigdecimal.c (BigDecimal_dump, BigDecimal_to_i, BigDecimal_to_f, BigDecimal_to_s, BigDecimal_split, BigDecimal_inspect): ditto. * ext/bigdecimal/bigdecimal.c (VpToString): small performance improvement. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@20359 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
20681e37ca
commit
a426373520
13
ChangeLog
13
ChangeLog
@ -1,3 +1,16 @@
|
|||||||
|
Wed Nov 26 03:00:59 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
|
||||||
|
|
||||||
|
* ext/bigdecimal/bigdecimal.c (VpAlloc): avoid ALLOCA_N() to avoid
|
||||||
|
segmentation fault caused by (insanely) long decimal values.
|
||||||
|
[ruby-dev:37189] fix #794
|
||||||
|
|
||||||
|
* ext/bigdecimal/bigdecimal.c (BigDecimal_dump, BigDecimal_to_i,
|
||||||
|
BigDecimal_to_f, BigDecimal_to_s, BigDecimal_split,
|
||||||
|
BigDecimal_inspect): ditto.
|
||||||
|
|
||||||
|
* ext/bigdecimal/bigdecimal.c (VpToString): small performance
|
||||||
|
improvement.
|
||||||
|
|
||||||
Wed Nov 26 00:26:30 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
|
Wed Nov 26 00:26:30 2008 Yukihiro Matsumoto <matz@ruby-lang.org>
|
||||||
|
|
||||||
* strftime.c (STRFTIME): should add padding for %[xXrR] etc.
|
* strftime.c (STRFTIME): should add padding for %[xXrR] etc.
|
||||||
|
@ -309,17 +309,19 @@ static VALUE
|
|||||||
BigDecimal_dump(int argc, VALUE *argv, VALUE self)
|
BigDecimal_dump(int argc, VALUE *argv, VALUE self)
|
||||||
{
|
{
|
||||||
ENTER(5);
|
ENTER(5);
|
||||||
char sz[50];
|
|
||||||
Real *vp;
|
Real *vp;
|
||||||
char *psz;
|
char *psz;
|
||||||
VALUE dummy;
|
VALUE dummy;
|
||||||
|
volatile VALUE dump;
|
||||||
|
|
||||||
rb_scan_args(argc, argv, "01", &dummy);
|
rb_scan_args(argc, argv, "01", &dummy);
|
||||||
GUARD_OBJ(vp,GetVpValue(self,1));
|
GUARD_OBJ(vp,GetVpValue(self,1));
|
||||||
sprintf(sz,"%lu:",VpMaxPrec(vp)*VpBaseFig());
|
dump = rb_str_new(0,VpNumOfChars(vp,"E")+50);
|
||||||
psz = ALLOCA_N(char,(unsigned int)VpNumOfChars(vp,"E")+strlen(sz));
|
psz = RSTRING_PTR(dump);
|
||||||
sprintf(psz,"%s",sz);
|
sprintf(psz,"%lu:",VpMaxPrec(vp)*VpBaseFig());
|
||||||
VpToString(vp, psz+strlen(psz), 0, 0);
|
VpToString(vp, psz+strlen(psz), 0, 0);
|
||||||
return rb_str_new2(psz);
|
rb_str_resize(dump, strlen(psz));
|
||||||
|
return dump;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -529,6 +531,7 @@ BigDecimal_to_i(VALUE self)
|
|||||||
ENTER(5);
|
ENTER(5);
|
||||||
int e,n,i,nf;
|
int e,n,i,nf;
|
||||||
U_LONG v,b,j;
|
U_LONG v,b,j;
|
||||||
|
volatile VALUE str;
|
||||||
char *psz,*pch;
|
char *psz,*pch;
|
||||||
Real *p;
|
Real *p;
|
||||||
|
|
||||||
@ -536,14 +539,14 @@ BigDecimal_to_i(VALUE self)
|
|||||||
|
|
||||||
/* Infinity or NaN not converted. */
|
/* Infinity or NaN not converted. */
|
||||||
if(VpIsNaN(p)) {
|
if(VpIsNaN(p)) {
|
||||||
VpException(VP_EXCEPTION_NaN,"Computation results to 'NaN'(Not a Number)",0);
|
VpException(VP_EXCEPTION_NaN,"Computation results to 'NaN'(Not a Number)",1);
|
||||||
return Qnil;
|
return Qnil; /* not reached */
|
||||||
} else if(VpIsPosInf(p)) {
|
} else if(VpIsPosInf(p)) {
|
||||||
VpException(VP_EXCEPTION_INFINITY,"Computation results to 'Infinity'",0);
|
VpException(VP_EXCEPTION_INFINITY,"Computation results to 'Infinity'",1);
|
||||||
return Qnil;
|
return Qnil; /* not reached */
|
||||||
} else if(VpIsNegInf(p)) {
|
} else if(VpIsNegInf(p)) {
|
||||||
VpException(VP_EXCEPTION_INFINITY,"Computation results to '-Infinity'",0);
|
VpException(VP_EXCEPTION_INFINITY,"Computation results to '-Infinity'",1);
|
||||||
return Qnil;
|
return Qnil; /* not reached */
|
||||||
}
|
}
|
||||||
|
|
||||||
e = VpExponent10(p);
|
e = VpExponent10(p);
|
||||||
@ -553,7 +556,8 @@ BigDecimal_to_i(VALUE self)
|
|||||||
e = VpGetSign(p)*p->frac[0];
|
e = VpGetSign(p)*p->frac[0];
|
||||||
return INT2FIX(e);
|
return INT2FIX(e);
|
||||||
}
|
}
|
||||||
psz = ALLOCA_N(char,(unsigned int)(e+nf+2));
|
str = rb_str_new(0, e+nf+2);
|
||||||
|
psz = RSTRING_PTR(str);
|
||||||
|
|
||||||
n = (e+nf-1)/nf;
|
n = (e+nf-1)/nf;
|
||||||
pch = psz;
|
pch = psz;
|
||||||
@ -591,10 +595,12 @@ BigDecimal_to_f(VALUE self)
|
|||||||
double d;
|
double d;
|
||||||
S_LONG e;
|
S_LONG e;
|
||||||
char *buf;
|
char *buf;
|
||||||
|
volatile VALUE str;
|
||||||
|
|
||||||
GUARD_OBJ(p,GetVpValue(self,1));
|
GUARD_OBJ(p,GetVpValue(self,1));
|
||||||
if(VpVtoD(&d, &e, p)!=1) return rb_float_new(d);
|
if(VpVtoD(&d, &e, p)!=1) return rb_float_new(d);
|
||||||
buf = ALLOCA_N(char,(unsigned int)VpNumOfChars(p,"E"));
|
str = rb_str_new(0, VpNumOfChars(p,"E"));
|
||||||
|
buf = RSTRING_PTR(str);
|
||||||
VpToString(p, buf, 0, 0);
|
VpToString(p, buf, 0, 0);
|
||||||
errno = 0;
|
errno = 0;
|
||||||
d = strtod(buf, 0);
|
d = strtod(buf, 0);
|
||||||
@ -1541,6 +1547,7 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|||||||
int fmt=0; /* 0:E format */
|
int fmt=0; /* 0:E format */
|
||||||
int fPlus=0; /* =0:default,=1: set ' ' before digits ,set '+' before digits. */
|
int fPlus=0; /* =0:default,=1: set ' ' before digits ,set '+' before digits. */
|
||||||
Real *vp;
|
Real *vp;
|
||||||
|
volatile VALUE str;
|
||||||
char *psz;
|
char *psz;
|
||||||
char ch;
|
char ch;
|
||||||
U_LONG nc;
|
U_LONG nc;
|
||||||
@ -1577,14 +1584,16 @@ BigDecimal_to_s(int argc, VALUE *argv, VALUE self)
|
|||||||
}
|
}
|
||||||
if(mc>0) nc += (nc + mc - 1) / mc + 1;
|
if(mc>0) nc += (nc + mc - 1) / mc + 1;
|
||||||
|
|
||||||
psz = ALLOCA_N(char,(unsigned int)nc);
|
str = rb_str_new(0, nc);
|
||||||
|
psz = RSTRING_PTR(str);
|
||||||
|
|
||||||
if(fmt) {
|
if(fmt) {
|
||||||
VpToFString(vp, psz, mc, fPlus);
|
VpToFString(vp, psz, mc, fPlus);
|
||||||
} else {
|
} else {
|
||||||
VpToString (vp, psz, mc, fPlus);
|
VpToString (vp, psz, mc, fPlus);
|
||||||
}
|
}
|
||||||
return rb_str_new2(psz);
|
rb_str_resize(str, strlen(psz));
|
||||||
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Splits a BigDecimal number into four parts, returned as an array of values.
|
/* Splits a BigDecimal number into four parts, returned as an array of values.
|
||||||
@ -1616,24 +1625,29 @@ BigDecimal_split(VALUE self)
|
|||||||
{
|
{
|
||||||
ENTER(5);
|
ENTER(5);
|
||||||
Real *vp;
|
Real *vp;
|
||||||
VALUE obj,obj1;
|
VALUE obj,str;
|
||||||
S_LONG e;
|
S_LONG e;
|
||||||
S_LONG s;
|
S_LONG s;
|
||||||
char *psz1;
|
char *psz1;
|
||||||
|
|
||||||
GUARD_OBJ(vp,GetVpValue(self,1));
|
GUARD_OBJ(vp,GetVpValue(self,1));
|
||||||
psz1 = ALLOCA_N(char,(unsigned int)VpNumOfChars(vp,"E"));
|
str = rb_str_new(0, VpNumOfChars(vp,"E"));
|
||||||
|
psz1 = RSTRING_PTR(str);
|
||||||
VpSzMantissa(vp,psz1);
|
VpSzMantissa(vp,psz1);
|
||||||
s = 1;
|
s = 1;
|
||||||
if(psz1[0]=='-') {
|
if(psz1[0]=='-') {
|
||||||
s = -1; ++psz1;
|
int len = strlen(psz1+1);
|
||||||
|
|
||||||
|
memmove(psz1, psz1+1, len);
|
||||||
|
psz1[len] = '\0';
|
||||||
|
s = -1;
|
||||||
}
|
}
|
||||||
if(psz1[0]=='N') s=0; /* NaN */
|
if(psz1[0]=='N') s=0; /* NaN */
|
||||||
e = VpExponent10(vp);
|
e = VpExponent10(vp);
|
||||||
obj1 = rb_str_new2(psz1);
|
|
||||||
obj = rb_ary_new2(4);
|
obj = rb_ary_new2(4);
|
||||||
rb_ary_push(obj, INT2FIX(s));
|
rb_ary_push(obj, INT2FIX(s));
|
||||||
rb_ary_push(obj, obj1);
|
rb_ary_push(obj, str);
|
||||||
|
rb_str_resize(str, strlen(psz1));
|
||||||
rb_ary_push(obj, INT2FIX(10));
|
rb_ary_push(obj, INT2FIX(10));
|
||||||
rb_ary_push(obj, INT2NUM(e));
|
rb_ary_push(obj, INT2NUM(e));
|
||||||
return obj;
|
return obj;
|
||||||
@ -1666,20 +1680,22 @@ BigDecimal_inspect(VALUE self)
|
|||||||
{
|
{
|
||||||
ENTER(5);
|
ENTER(5);
|
||||||
Real *vp;
|
Real *vp;
|
||||||
VALUE obj;
|
volatile VALUE obj;
|
||||||
unsigned int nc;
|
unsigned int nc;
|
||||||
char *psz1;
|
char *psz, *tmp;
|
||||||
char *pszAll;
|
|
||||||
|
|
||||||
GUARD_OBJ(vp,GetVpValue(self,1));
|
GUARD_OBJ(vp,GetVpValue(self,1));
|
||||||
nc = VpNumOfChars(vp,"E");
|
nc = VpNumOfChars(vp,"E");
|
||||||
nc +=(nc + 9) / 10;
|
nc +=(nc + 9) / 10;
|
||||||
|
|
||||||
psz1 = ALLOCA_N(char,nc);
|
obj = rb_str_new(0, nc+256);
|
||||||
pszAll = ALLOCA_N(char,nc+256);
|
psz = RSTRING_PTR(obj);
|
||||||
VpToString(vp, psz1, 10, 0);
|
sprintf(psz,"#<BigDecimal:%lx,'",self);
|
||||||
sprintf(pszAll,"#<BigDecimal:%lx,'%s',%lu(%lu)>",self,psz1,VpPrec(vp)*VpBaseFig(),VpMaxPrec(vp)*VpBaseFig());
|
tmp = psz + strlen(psz);
|
||||||
obj = rb_str_new2(pszAll);
|
VpToString(vp, tmp, 10, 0);
|
||||||
|
tmp += strlen(tmp);
|
||||||
|
sprintf(tmp,"',%lu(%lu)>",VpPrec(vp)*VpBaseFig(),VpMaxPrec(vp)*VpBaseFig());
|
||||||
|
rb_str_resize(obj, strlen(psz));
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2534,6 +2550,7 @@ VpAlloc(U_LONG mx, const char *szVal)
|
|||||||
int sign=1;
|
int sign=1;
|
||||||
Real *vp = NULL;
|
Real *vp = NULL;
|
||||||
U_LONG mf = VpGetPrecLimit();
|
U_LONG mf = VpGetPrecLimit();
|
||||||
|
volatile VALUE buf;
|
||||||
|
|
||||||
mx = (mx + BASE_FIG - 1) / BASE_FIG + 1; /* Determine allocation unit. */
|
mx = (mx + BASE_FIG - 1) / BASE_FIG + 1; /* Determine allocation unit. */
|
||||||
if(szVal) {
|
if(szVal) {
|
||||||
@ -2561,7 +2578,8 @@ VpAlloc(U_LONG mx, const char *szVal)
|
|||||||
|
|
||||||
/* Skip all '_' after digit: 2006-6-30 */
|
/* Skip all '_' after digit: 2006-6-30 */
|
||||||
ni = 0;
|
ni = 0;
|
||||||
psz = ALLOCA_N(char,strlen(szVal)+1);
|
buf = rb_str_new(0,strlen(szVal)+1);
|
||||||
|
psz = RSTRING_PTR(buf);
|
||||||
i = 0;
|
i = 0;
|
||||||
ipn = 0;
|
ipn = 0;
|
||||||
while((psz[i]=szVal[ipn])!=0) {
|
while((psz[i]=szVal[ipn])!=0) {
|
||||||
@ -3656,7 +3674,7 @@ VPrint(FILE *fp, char *cntl_chr, Real *a)
|
|||||||
nc += fprintf(fp, "0.");
|
nc += fprintf(fp, "0.");
|
||||||
n = a->Prec;
|
n = a->Prec;
|
||||||
for(i=0;i < n;++i) {
|
for(i=0;i < n;++i) {
|
||||||
m = BASE1;
|
m = BASE1;
|
||||||
e = a->frac[i];
|
e = a->frac[i];
|
||||||
while(m) {
|
while(m) {
|
||||||
nn = e / m;
|
nn = e / m;
|
||||||
@ -3838,7 +3856,7 @@ VpToString(Real *a,char *psz,int fFmt,int fPlus)
|
|||||||
/* fPlus =0:default, =1: set ' ' before digits , =2:set '+' before digits. */
|
/* fPlus =0:default, =1: set ' ' before digits , =2:set '+' before digits. */
|
||||||
{
|
{
|
||||||
U_LONG i, ZeroSup;
|
U_LONG i, ZeroSup;
|
||||||
U_LONG n, m, e, nn;
|
U_LONG n, e;
|
||||||
char *pszSav = psz;
|
char *pszSav = psz;
|
||||||
S_LONG ex;
|
S_LONG ex;
|
||||||
|
|
||||||
@ -3854,18 +3872,12 @@ VpToString(Real *a,char *psz,int fFmt,int fPlus)
|
|||||||
*psz++ = '.';
|
*psz++ = '.';
|
||||||
n = a->Prec;
|
n = a->Prec;
|
||||||
for(i=0;i < n;++i) {
|
for(i=0;i < n;++i) {
|
||||||
m = BASE1;
|
|
||||||
e = a->frac[i];
|
e = a->frac[i];
|
||||||
while(m) {
|
if((!ZeroSup) || e) {
|
||||||
nn = e / m;
|
sprintf(psz, "%lu", e); /* The reading zero(s) */
|
||||||
if((!ZeroSup) || nn) {
|
psz += strlen(psz);
|
||||||
sprintf(psz, "%lu", nn); /* The reading zero(s) */
|
/* as 0.00xx will be ignored. */
|
||||||
psz += strlen(psz);
|
ZeroSup = 0; /* Set to print succeeding zeros */
|
||||||
/* as 0.00xx will be ignored. */
|
|
||||||
ZeroSup = 0; /* Set to print succeeding zeros */
|
|
||||||
}
|
|
||||||
e = e - nn * m;
|
|
||||||
m /= 10;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ex =(a->exponent) * BASE_FIG;
|
ex =(a->exponent) * BASE_FIG;
|
||||||
|
@ -303,9 +303,9 @@ class TestBigDecimal < Test::Unit::TestCase
|
|||||||
x = BigDecimal.new("0")
|
x = BigDecimal.new("0")
|
||||||
assert_kind_of(Integer, x.to_i)
|
assert_kind_of(Integer, x.to_i)
|
||||||
assert_equal(0, x.to_i)
|
assert_equal(0, x.to_i)
|
||||||
assert_nil(( 1 / x).to_i)
|
assert_raise(FloatDomainError){( 1 / x).to_i}
|
||||||
assert_nil((-1 / x).to_i)
|
assert_raise(FloatDomainError){(-1 / x).to_i}
|
||||||
assert_nil(( 0 / x).to_i)
|
assert_raise(FloatDomainError){( 0 / x).to_i}
|
||||||
x = BigDecimal.new("1")
|
x = BigDecimal.new("1")
|
||||||
assert_equal(1, x.to_i)
|
assert_equal(1, x.to_i)
|
||||||
x = BigDecimal.new((2**100).to_s)
|
x = BigDecimal.new((2**100).to_s)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user