2009-03-04 10 views
0

Vergleichen Sie diese beiden weitgehend identischen Funktionen. In der ersten wird der Speicher für buff zugewiesen mit _alloca. Das funktioniert gut. In der zweiten werden Calloc und Free anstelle von _alloca verwendet. Dies stürzt ab.Warum würde der Aufruf von Calloc'ed Memory mein VC6-Projekt zum Absturz bringen?

Das komische Ding ist, dass ich die calloc/freie Technik in fast jeder anderen GMP-Verpackungsfunktion verwende, die ich habe und sie alle arbeiten. Hier tun sie nicht. Irgendwelche Ideen?

1:

#define Z(x) mpz_t (x); mpz_init((x)); 
#define BUFF_SIZE (1024 * 32) 

BSTR __stdcall IBIGDIV(BSTR p1, BSTR p2) { 
    USES_CONVERSION; 

    Z(n1); 
    Z(n2); 
    Z(res); 

    char * buff = (char *) _alloca(mpz_sizeinbase(res, 10) + 2); 

    LPSTR sNum1 = W2A(p1); 
    LPSTR sNum2 = W2A(p2); 

    mpz_set_str(n1, sNum1, 10); 
    mpz_set_str(n2, sNum2, 10); 

    if (mpz_sgn(n2) != 0) { 
     mpz_div(res, n1, n2); 
     mpz_get_str(buff, 10, res); 
    } else { 
     strcpy(buff, "-0"); 
    } 

    BSTR bResult = _com_util::ConvertStringToBSTR(buff); 
    return bResult; 
} 

2:

#define Z(x) mpz_t (x); mpz_init((x)); 
#define BUFF_SIZE (1024 * 32) 

BSTR __stdcall IBIGDIV(BSTR p1, BSTR p2) { 
    USES_CONVERSION; 

    Z(n1); 
    Z(n2); 
    Z(res); 

    char * buff = (char *) calloc(mpz_sizeinbase(res, 10) + 2, sizeof(char)); 

    LPSTR sNum1 = W2A(p1); 
    LPSTR sNum2 = W2A(p2); 

    mpz_set_str(n1, sNum1, 10); 
    mpz_set_str(n2, sNum2, 10); 

    if (mpz_sgn(n2) != 0) { 
     mpz_div(res, n1, n2); 
     mpz_get_str(buff, 10, res); 
    } else { 
     strcpy(buff, "-0"); 
    } 

    BSTR bResult = _com_util::ConvertStringToBSTR(buff); 
    free(buff); 
    return bResult; 
} 
+0

Was sagt der Kernspeicherauszug? oder bekommst du nicht eins? – hhafez

+0

BTW, _alloca ist veraltet, verwenden _malloca stattdessen –

+0

Ich würde vermuten, dass mpz_sizeinbase() auf einer neu initialisierten Struktur verwendet 0. 0. Mit alloca, ist Ihr Puffer auf dem Stapel und wird die verschiedenen Strukturen bereits dort abstürzen (und möglicherweise nicht abstürzen). – johnny

Antwort

1

Fügen Sie Protokollierung hinzu und löschen Sie alles auf dem Weg, um herauszufinden, was schief läuft. Dies ist normalerweise effizienter als zu versuchen, zu erraten.

1

Es keinem Zusammenhang sein können, aber diese Art von „arbeitet eine Möglichkeit, aber nicht die anderen“ gibt oft ein Fehler, der durch quietschen gerade passiert in einer Situation, verursacht aber in einem anderen einen schwerwiegenden Fehler.

Wenn Sie vermuten, dass ein Speicherüberschreiben auftritt, können Sie versuchen, zusätzliche 8 Bytes in den Puffer zu schreiben und 4-Byte-Start- und Ende-Sentinels zu schreiben, die Sie dann vor der Freigabe überprüfen.

1

Ich verbrachte einmal eine Woche damit, eine ähnliche Sache herauszufinden. Es war eine Pufferüberschreitung, die den Zeiger zerstörte, so dass er frei in den Wald ging. Rational purify hat das Problem in einer Minute gefunden.

1

calloc könnte möglicherweise NULL zurückgeben, wenn ein Fehler auftritt (z. B. fehlender Speicher). Ich würde empfehlen, das Ergebnis jeder Speicherzuordnungsfunktion gegen NULL zu überprüfen. Wenn es NULL ist, drucken Sie eine Nachricht und beenden Sie dann (1).

+0

Auch wenn es langweilig ist, müssen Sie immer überprüfen Sie den Rückgabewert von Sachen wie Calloc ... – Johan

+0

Wenn Calloc Null zurückgegeben würde der Absturz viel früher auftreten. –

0

_alloca zurück Stack-Speicher, so stampfen über das Ende davon möglicherweise nicht unbedingt etwas Wichtiges zu überschreiben. Das Schreiben über das Ende einer Heapspeicherzuweisung hinaus überschreibt wahrscheinlich etwas Wichtiges.

Ihr Code tut nichts, um sicherzustellen, dass der Puffer mindestens so groß ist, wie res formatiert werden würde nach dem Teilen von n1 durch n2 (oder umgekehrt, da ich nicht weiß, was die eigentliche Funktion tut); es stellt nur sicher, dass es genug Speicher für eine initialisierte res hat, die wahrscheinlich 1 ist. Wenn n1/n2 mehr Ziffern als das hat, willkommen bei criserville.

0

@johnny wies auf etwas eher peinlich, was eine Neuschreibung des Codes erforderlich machte. (Hier ist, wo ein Kommentar in der Lage zu kreuzen wäre nützlich.)

BSTR __stdcall IBIGDIV(BSTR p1, BSTR p2) { 
    USES_CONVERSION; 

    Z(n1); 
    Z(n2); 
    Z(res); 

    char * buff; 

    LPSTR sNum1 = W2A(p1); 
    LPSTR sNum2 = W2A(p2); 

    mpz_set_str(n1, sNum1, 10); 
    mpz_set_str(n2, sNum2, 10); 

    if (mpz_sgn(n2) != 0) { 
     mpz_div(res, n1, n2); 
     buff = (char *) calloc(mpz_sizeinbase(res, 10) + 2, sizeof(char)); 
     mpz_get_str(buff, 10, res); 
    } else { 
     buff = (char *) calloc(3, sizeof(char)); 
     strcpy(buff, "-0"); 
    } 

    BSTR bResult = _com_util::ConvertStringToBSTR(buff); 
    free(buff); 
    return bResult; 
} 

In den vorherigen Inkarnationen wurde der Speicher nach in dem Code an dem Punkt, auf den Wert von res zugeordnet ist, wo es Null enthalten. Also habe ich versucht, null Bytes zu nennen und kostenlos hat es nicht gefallen. In dem obigen Code enthält res tatsächlich etwas, das mit mpz_sizeinbase arbeiten kann.