Re: Heap overflow/corruption problem in an arbitrary precision class
Martin the Third wrote:
On Jun 12, 6:11 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
Martin the Third wrote:
Hi, I need some help!
I'm writing an infinite-precision floating point library called
ipfloat (I know infinite is a misnomer - but arbitrary was taken). A
quick overview: I'm storing numbers as a char* mantissa, an int
exponent and a sign. For example, the number "123.45" would have a
mantissa of 12345, an exponent of 2, and a sign of +. I'm essentially
storing it as "1.2345x10^2".
The mantissa is allocated dynamically at runtime to allow arbitrary
precision in my numbers. I'm having trouble with heap overflows; let
me explain in more detail:
[snip]
Thank you! I'll gladly post code if it will help.
Since my crystal ball is in repair, code would be highly appreciated.
Short of that, consider using std::vector< char > instead of char*. Very
likely, your problems stem from mistakes in pointer handling (allocation,
deallocation, _and_ reallocation).
Best
Kai-Uwe Bux
Here are the relevant functions. Keep in mind that I stopped my +
function halfway through, so it doesn't actually add yet. (I have
older versions that do...)
Ok. Here are some comments on the code. Since you did not post a complete
example, I test whether they address the problem you are experiencing.
ipfloat::ipfloat(char* ch)
{
int len = strlen(ch);
int i = 0, j = 0; //i keeps place in ch, j keeps
place in man
sign = (ch[0]=='-')?'-':'+'; //assign the sign
int startZeros = 0, trailZeros = 0, manLen, decPos, decOffset;
while(ch[i]!='\0' && ch[i]!='.') //loop until we find the decimal,
whether explicitly typed or not
i++;
decPos = i;
i=0;
while(ch[i]=='0' || ch[i]=='.') //count number of 0's at the
beginning of the number
{
startZeros++; //this now contains 1 more than sz
if theres a dec
i++;
}
i=0;
while(ch[len-1-i]=='0') //count the number of trailing 0's
{
trailZeros++;
i++;
}
manLen = len - startZeros - trailZeros - 1;
man = (char*)malloc(sizeof(char)*(manLen+1));
for(i=startZeros; i<(startZeros+manLen+1); i++, j++) //copy
correct data from ch to man
{
if(ch[i]!='.')
man[j] = ch[i];
else
j--;
}
man[j] = '\0';
decOffset = (startZeros>=decPos)?0:1; //combine this with
statement below? remove variable?
exp = decPos - startZeros - decOffset;
}
ipfloat::ipfloat(const ipfloat &rhs){
if(this!=&rhs)
Within a copy-constructor, this test can never yield true (unless you
explicitly invoke the copy constructor with placement new re-constructing
an element from itself, which might formally be undefined behavior anyway).
{
setMan(rhs.getMan());
It looks as though setMan frees the pointer member man, which is not yet
initialized in this constructor. You might be freeing memory that you don't
own. Try:
man=0;
setMan( rhs.getMan() );
or put "man()" in the initializer list.
You might want to run your program in valgrind to find where you use
un-initialized variables.
setExp(rhs.getExp());
setSign(rhs.getSign());
}
}
ipfloat::ipfloat(int size, char sgn)
{
man = (char*)malloc(sizeof(char)*size);
sign = sgn;
}
ipfloat::~ipfloat(){
free(man);
}
inline const char* const ipfloat::getMan() const{return man;}
inline const int ipfloat::getExp() const{return exp;}
inline const char ipfloat::getSign() const{return sign;}
inline void ipfloat::setManSize(int size)
{
free(man);
man = (char*)malloc(sizeof(char)*(size));
sizeof(char) is guaranteed to be 1 by the standard.
}
inline void ipfloat::setManChar(int pos, char ch)
{
man[pos] = ch;
}
inline void ipfloat::setMan(const char* const ch){
free(man);
man = (char*)malloc(sizeof(char)*(strlen(ch)+1));
strcpy(man, ch);
}
inline void ipfloat::setExp(int e){
exp = e;
}
inline void ipfloat::setSign(char ch){
sign = ch;
}
ipfloat &ipfloat::operator =(const ipfloat &rhs){
if(this!=&rhs)
{
setMan(rhs.getMan());
setExp(rhs.getExp());
setSign(rhs.getSign());
}
return *this;
}
ipfloat ipfloat::operator +(const ipfloat &rhs)
{
int ctr, c, d;
int thisBefore, thisAfter, rhsBefore, rhsAfter, resLen;
thisBefore = (getExp()>=0) ? getExp() + 1 : 1;
thisAfter = (strlen(getMan())<=getExp()) ? abs((int)
(strlen(getMan()) + getExp() - thisBefore)) : strlen(getMan()) -
getExp() - 1;
rhsBefore = (rhs.getExp()>=0) ? rhs.getExp() + 1 : 1;
rhsAfter = (strlen(rhs.getMan())<=rhs.getExp()) ? abs((int)
(strlen(rhs.getMan()) + rhs.getExp() - thisBefore)) :
strlen(rhs.getMan()) - rhs.getExp() - 1;
resLen = ((thisBefore>=rhsBefore)?thisBefore:rhsBefore)+
((thisAfter>=rhsAfter)?thisAfter:rhsAfter);
ipfloat result(resLen + 1, rhs.getSign());
result.setManChar(resLen, '\0');
for(int i=0; i<resLen; i++)
result.setManChar(i,'0');
cout<<result.getMan()<<endl;
if(thisBefore>rhsBefore)
{
for(ctr = 0; ctr<(thisBefore-rhsBefore); ctr++)
result.setManChar(ctr, getMan()[ctr]);
}
if(rhsBefore>thisBefore)
{
for(ctr = 0; ctr<(rhsBefore-thisBefore); ctr++)
result.setManChar(ctr, rhs.getMan()[ctr]);
}
if(thisAfter>rhsAfter)
{
c=((thisBefore>=rhsBefore)?thisBefore:rhsBefore) + rhsAfter; //
tracks result
d=strlen(getMan())-(thisAfter-
rhsAfter); //tracks this
while(getMan()[d]!='\0')
{
result.setManChar(c, getMan()[d]);
c++;
d++;
}
}
if(rhsAfter>thisAfter)
{
c=((rhsBefore>=thisBefore)?rhsBefore:thisBefore) +
thisAfter; //tracks result
d=strlen(rhs.getMan())-(rhsAfter-
thisAfter); //tracks this
while(rhs.getMan()[d]!='\0')
{
result.setManChar(c, rhs.getMan()[d]);
c++;
d++;
}
}
cout<<result.getMan()<<endl;
return result;
}
[snip]
Hope this helps
Kai-Uwe Bux