[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

const * loses highest order byte.



>Submitter-Id:	net
>Originator:	Marek Baczynski
>Organization:	
>Confidential:	no
>Synopsis:	const * loses highest order byte.
>Severity:	serious
>Priority:      medium
>Category:	c++
>Class:		wrong-code
>Release:	3.3.2 (Debian) (Debian testing/unstable)
>Environment:
System: Linux imbaczek 2.4.24-1-686 #1 Tue Jan 6 21:29:44 EST 2004 i686 GNU/Linux
Architecture: i686

	
host: i486-pc-linux-gnu
build: i486-pc-linux-gnu
target: i486-pc-linux-gnu
configured with: ../src/configure -v --enable-languages=c,c++,java,f77,pascal,objc,ada,treelang --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-gxx-include-dir=/usr/include/c++/3.3 --enable-shared --with-system-zlib --enable-nls --without-included-gettext --enable-__cxa_atexit --enable-clocale=gnu --enable-debug --enable-java-gc=boehm --enable-java-awt=xlib --enable-objc-gc i486-linux
>Description:
Breakpoint 1, operator*(Liczba const&, Liczba const&) (a=@0xbffff960, 
    b=@0xbffff8f0) at duze.cc:183
183         for (i = l2->start; i<LEN; ++i) {
(gdb) p l1
$1 = (const Liczba *) 0xbffff8f0
(gdb) p l2
$2 = (const Liczba *) 0xbffff960
(gdb) watch l1
Hardware watchpoint 2: l1
(gdb) continue
Continuing.
Hardware watchpoint 2: l1

Old value = (const Liczba *) 0xbffff8f0
New value = (const Liczba *) 0xfff8f0
operator*(Liczba const&, Liczba const&) (a=@0xbffff960, b=@0xbffff8f0)
    at duze.cc:184
184             for (j = LEN-1; j>=l1->start; --j) {
(gdb) continue 
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x08048f0e in operator*(Liczba const&, Liczba const&) (a=@0xbffff960, 
    b=@0xbffff8f0) at duze.cc:184
184             for (j = LEN-1; j>=l1->start; --j) {
(gdb) 
>How-To-Repeat:
Complete source:

// bignums.cc
#include <iostream>
#include <cstring>

using namespace std;

#define LEN 100
#define BASE 10

class Liczba {
    signed char liczba[LEN];
    int len;
    int start;
    inline void from_string(const char *);
public:
    Liczba(const char * s) { this->from_string(s); }
    Liczba(int i) { char s[LEN]; snprintf(s, LEN, "%d", i); this->from_string(s); }
    Liczba(const Liczba& l) { int i; for (i = 0; i<LEN; ++i) this->liczba[i] = l.liczba[i]; this->len = l.len; this->start =  l.start; }
    
    friend ostream& operator<<(ostream&, const Liczba&);
    friend istream& operator>>(istream&, Liczba&);
    
    friend bool operator<(const Liczba&, const Liczba&);
    friend bool operator==(const Liczba&, const Liczba&);
    
    friend Liczba& operator<<=(Liczba&, int);
    
    friend Liczba& operator+=(Liczba&, const Liczba&);
    friend Liczba& operator-=(Liczba&, const Liczba&);
    friend Liczba& operator*=(Liczba&, const Liczba&);
    friend Liczba& operator/=(Liczba&, const Liczba&);

    friend Liczba operator+(const Liczba&, const Liczba&);
    friend Liczba operator-(const Liczba&, const Liczba&);
    friend Liczba operator*(const Liczba&, const Liczba&);
};

void Liczba::from_string(const char *s)
{
    int i;

    len = strlen(s);
    start = LEN-len;
    for (i = 0; i<start; ++i)
        liczba[i] = 0;
    for (i = start; i<LEN; ++i)
        liczba[i] = s[i-start]-'0';
}

ostream& operator<<(ostream& o, const Liczba& l)
{
    char s[LEN+1];
    int i;

    for (i=l.start; i<LEN; ++i)
        s[i-l.start] = l.liczba[i]+'0';
    s[i-l.start] = 0;
    o << s;
    return o;
}

istream& operator>>(istream& is, Liczba& l)
{
    char s[LEN+1];

    is >> s;
    l.from_string(s);
    return is;
}

// --------------------------------------------------------------------------
// porownania

bool operator<(const Liczba& a, const Liczba& b)
{
    int i;
    
    if (a.start > b.start)
        return true;
    else if (a.start < b.start)
        return false;
    i = a.start;
    while (a.liczba[i] == b.liczba[i])
        ++i;
    if (a.liczba[i] < b.liczba[i])
        return true;
    else
        return false;
}

// --------------------------------------------------------------------------
// przesuniecia

Liczba& operator<<=(Liczba& a, int s)
{
    int i;
    
    memmove(a.liczba+a.start-s, a.liczba+a.start, LEN-a.start);
    for (i = LEN-s; i < LEN; ++i)
        a.liczba[i] = 0;
    a.start -= s;
    return a;
}

// --------------------------------------------------------------------------
// dodawanie

Liczba& operator+=(Liczba& a, const Liczba& b)
{
    int i, c=0;

    for (i = LEN-1; i>=b.start; --i) {
        a.liczba[i] += b.liczba[i];
        c = a.liczba[i]/BASE;
        a.liczba[i] %= BASE;
        a.liczba[i-1] += c;
    }
    if (b.start <= a.start) {
        a.start = b.start - c;
        a.len = b.len + c;
    }

    return a;
}

Liczba operator+(const Liczba& a, const Liczba& b)
{
    Liczba r(a);

    r += b;
    return r;
}

// -------------------------------------------------------------------------
// odejmowanie

Liczba& operator-=(Liczba& a, const Liczba& b)
{
    int i, c=0;

    for (i = LEN-1; i>=b.start; --i) {
        a.liczba[i] -= b.liczba[i];
        cout << (int)a.liczba[i] << ' ';
        c = -(a.liczba[i]<0);
        a.liczba[i] = (a.liczba[i]+BASE)%BASE;
        cout << c << ' ' << (int)a.liczba[i] << ' ';
        a.liczba[i-1] += c;
        cout << (int)a.liczba[i-1] << endl;
    }
    if (a.liczba[a.start] == 0) {
        ++a.start;
        --a.len;
    }

    return a;
}


Liczba operator-(const Liczba& a, const Liczba& b)
{
    Liczba r(a);
    r -= b;
    return r;
}

// --------------------------------------------------------------------------
// mnozenie

Liczba operator*(const Liczba& a, const Liczba& b)
{
    Liczba tmp(0), r(0);
    const Liczba *l1=NULL, *l2=NULL;
    int i, j, tmp1;

    if (a<b) {
        l1 = &b;
        l2 = &a;
    } else {
        l1 = &a;
        l2 = &b;
    }
    //l2 = (const Liczba*)(0xbf000000|(int)l2);
    //l1 = (const Liczba*)(0xbf000000|(int)l1);
    for (i = l2->start; i<LEN; ++i) {
        for (j = LEN-1; j>=l1->start; --j) {
            tmp1 = tmp.liczba[j-i] + l1->liczba[j] * l2->liczba[LEN-i-1];
            tmp.liczba[j-i] = tmp1%10;
            tmp.liczba[j-i-1] = tmp1/10;
        }
        r += tmp;
        tmp = Liczba(0);
    }
    return r;
}

// --------------------------------------------------------------------------

void test()
{
    char ch;
    Liczba a(0), b(0);
    
    // bug here, left as is
    while (cin) {
        cin >> ch >> a >> b;
        cout << a << ch << b << " = ";
        switch (ch) {
        case '+':
            cout << (a+b);
            break;
        case '-':
            cout << (a-b);
            break;
        case '<':
            cout << (a<b);
            break;
        case '*':
            cout << (a*b);
            break;
        default:
            break;
        }
        cout << endl;
    }
}

int main()
{
    test();

    return 0;
}

// EOF

A test suite:

+ 9 1
+ 99 11
+ 20 1000000000000
+ 900000000000 100000000000
- 10 9
- 9 5
- 5 9
- 99999 88888
- 88888 9999
< 5 9
< 100 101
< 99999 99998
* 10 251

Compile and run:
$ g++ bignums.cc -Wall -g -o bignums
$ ./bignums <testsuite

Tested with gcc-3.2 and gcc-3.3, segfaults on both. Didn't test in C.
>Fix:
Compile with any -O. Didn't test assigment to temporary variables.



Reply to: