[GiNaC-devel] [PATCH 1/2] [bugfix] fsolve: check if evalf() return value is actually a number.
Alexei Sheplyakov
alexei.sheplyakov at gmail.com
Wed Aug 18 23:07:13 CEST 2010
Fixes the segfault triggered by
fsolve((1/(sqrt(2*Pi)))*integral(t,0,x,exp(-1/2*t^2))==0.5,x,0,100)
In general, ex_to is unsafe, and should be used only after proper checks.
evalf() may return non-numeric expression for various reasons (bad
convergence, floating point over- or underflow, out of memory, etc).
So let's add missing checks.
Thanks to Ernst Moritz Hahn for a bug report.
---
ginac/inifcns.cpp | 29 ++++++++++++++++++++++++-----
1 files changed, 24 insertions(+), 5 deletions(-)
diff --git a/ginac/inifcns.cpp b/ginac/inifcns.cpp
index 981e7b2..f366e77 100644
--- a/ginac/inifcns.cpp
+++ b/ginac/inifcns.cpp
@@ -1007,8 +1007,16 @@ fsolve(const ex& f_in, const symbol& x, const numeric& x1, const numeric& x2)
do {
xxprev = xx[side];
fxprev = fx[side];
- xx[side] += ex_to<numeric>(ff.subs(x==xx[side]).evalf());
- fx[side] = ex_to<numeric>(f.subs(x==xx[side]).evalf());
+ ex dx_ = ff.subs(x == xx[side]).evalf();
+ if (!is_a<numeric>(dx_))
+ throw std::runtime_error("fsolve(): function derivative does not evaluate numerically");
+ xx[side] += ex_to<numeric>(dx_);
+
+ ex f_x = f.subs(x == xx[side]).evalf();
+ if (!is_a<numeric>(f_x))
+ throw std::runtime_error("fsolve(): function does not evaluate numerically");
+ fx[side] = ex_to<numeric>(f_x);
+
if ((side==0 && xx[0]<xxprev) || (side==1 && xx[1]>xxprev) || xx[0]>xx[1]) {
// Oops, Newton-Raphson method shot out of the interval.
// Restore, and try again with the other side instead!
@@ -1017,8 +1025,16 @@ fsolve(const ex& f_in, const symbol& x, const numeric& x1, const numeric& x2)
side = !side;
xxprev = xx[side];
fxprev = fx[side];
- xx[side] += ex_to<numeric>(ff.subs(x==xx[side]).evalf());
- fx[side] = ex_to<numeric>(f.subs(x==xx[side]).evalf());
+
+ ex dx_ = ff.subs(x == xx[side]).evalf();
+ if (!is_a<numeric>(dx_))
+ throw std::runtime_error("fsolve(): function derivative does not evaluate numerically [2]");
+ xx[side] += ex_to<numeric>(dx_);
+
+ ex f_x = f.subs(x==xx[side]).evalf();
+ if (!is_a<numeric>(f_x))
+ throw std::runtime_error("fsolve(): function does not evaluate numerically [2]");
+ fx[side] = ex_to<numeric>(f_x);
}
if ((fx[side]<0 && fx[!side]<0) || (fx[side]>0 && fx[!side]>0)) {
// Oops, the root isn't bracketed any more.
@@ -1042,7 +1058,10 @@ fsolve(const ex& f_in, const symbol& x, const numeric& x1, const numeric& x2)
static const double secant_weight = 0.984375; // == 63/64 < 1
numeric xxmid = (1-secant_weight)*0.5*(xx[0]+xx[1])
+ secant_weight*(xx[0]+fx[0]*(xx[0]-xx[1])/(fx[1]-fx[0]));
- numeric fxmid = ex_to<numeric>(f.subs(x==xxmid).evalf());
+ ex fxmid_ = f.subs(x == xxmid).evalf();
+ if (!is_a<numeric>(fxmid_))
+ throw std::runtime_error("fsolve(): function does not evaluate numerically [3]");
+ numeric fxmid = ex_to<numeric>(fxmid_);
if (fxmid.is_zero()) {
// Luck strikes...
return xxmid;
--
1.7.1
More information about the GiNaC-devel
mailing list