gcc: "double free or corruption" - Megoldva

 ( denx | 2007. január 3., szerda - 12:03 )

Sziasztok!

Csinálok egy elég egyszerű programot és ezt a hibaüzenetet kaptam:

*** glibc detected *** double free or corruption (out): 0x081370b8 ***

Ez mitől lehet?
Valahol a netetn azt találtam, hogy ha ezt használom, akkor megjavul:

export MALLOC_CHECK_=0

De nem működik. Mi lehet szerintetek a gond? Találkozott már valaki hasonlóval?

Üdv:
denx

Hozzászólás megjelenítési lehetőségek

A választott hozzászólás megjelenítési mód a „Beállítás” gombbal rögzíthető.

#include <stdlib.h>
int main()
{
void *a= malloc (8);
free(a);
free(a);
return 0;
}

Köszi, erre gondoltam én is, de már minden free-t kiszedtem a progiból és még mindig ez van!

gdb, strace, ltrace a barátod.
Milyen libeket használsz ?
Nem adsz meg valhol rosz pinter, ill. pointer - int keveredés?
Esetleg string vég '\0' hiányzik.

én is ezeket javaslom, még nagyon hasznos tud lenni a valgrind

ha ez megnyugtat a centos-t is kiadjak igy.

Nem feltétlenül a te programodból hívódik meg közvetlenül a free(), lehet, hogy valamelyik másik C függvény amit használsz az hívja meg. Sajnos ezt máshogy nem lehet kideríteni így, csak debuggolással.

továbbá: Electric Fence, illetve szorgos debuggolás: addig egyszerűsítjük a programot, amíg meg nem szűnik a hiba; az utoljára kivett rész okozta a gondot, vagy legalábbis köze volt hozzá.
Az ellenőrzés letiltása (MALLOC_CHECK) természetesen nem megoldás.

#include <stdlib.h>
int main()
{
size_t *a=(size_t*) malloc (8);
a[-1]=(size_t)a;
a=(size_t*) realloc(a,0);
return 0;
}

Másik kód ami, előidézheti.

arra meg nem gondoltal, h a[-1] eseten olyan memoriateruletre irsz ahova nagyon nem kene?

Én kérek elnézést!

KisKresz

Szerinted miért irtam :P
Talán azért, hogy példát mutassak olyan kódra ami ilyen hibát dob..

jode ez lame kod barki aki egy oranal tobbet foglalkozott programozassal nem ir ilyet

Kivéve, ha a[i]=blablabla formában teszi, ahol mondjuk i értéke hibás.

KisKresz

Csak tömb indexbe kell hibás számnak kerülnie, a sok JÁVA fan pont azért is szereti jávát, mert ott szolnak érte.
-1 meg spec. érték.

ha kicsit bonyolultabb a program/algoritmus, akkor mar annyira nem egyszeru a felszabaditas.. lama dolog ugyan, de tobbek kozt ezert terjednek annyira a garbage collector-os nyelvek (.net, java, scriptnyelvek)
az meg, hogy egy tombbol kiindexel, szinten szokasos, es sulyos hiba, es el szoktak kovetni.. eleg rakeresni a buffer overrun exploitokra.. ha raadasul stack-en van, akkor meg konnyen ki is lehet hasznalni betoresre..
---------------------
"A feny azt hiszi, gyorsabb mindennel, de teved. Mindegy, milyen sebesen szaguld a feny, mindig azt fogja talalni a vegen, hogy a sotetseg ert oda elsonek, es ra var." - Terry Pratchett

Háhááá csak a garbage collector azellennemvéd. Ha valahol véletlenül megmarad a referencia az ovjektumra, akkor a gc nem tudja kihajítani és frankó memory leakeket lehet gyártani vele. (Lásd még: "Miért zabálják a memóriát a java-s programok?") Tény, hogy talán a problémák egy részét kiszűri a gc, de messze nem csodaszer. A java profiling viszont jó kis játék... jó sok időt el lehet vele tölteni és közben jó sok hajat tépni, mire megtalálja az ember, hogy valami bonyolultabb rekurzív algoritums lekódolásának hevében melyik változót felejtette el null-ra állítani. Plusz pontért más ember által írt kódban ugyanezt. :)
---
Keep on trolling

Csak érdekesség képpen :-)
Én Knoppix leszármazott LiveCD-ről bootolva próbáltam partimage-gel backupot csinálni. kb 80%-nál a partimage pontosan ezzel a hibaüzenettel szállt el.

mennyire bonyolult/hosszu a program?
---------------------
"A feny azt hiszi, gyorsabb mindennel, de teved. Mindegy, milyen sebesen szaguld a feny, mindig azt fogja talalni a vegen, hogy a sotetseg ert oda elsonek, es ra var." - Terry Pratchett

Most kezd bonyolódni. Amúgy elég egyszerű a dolog és látszólag értelmetlen helyen akad ki. Sőt! Ha egy másik értelmetlen helyen feltöltöm a frissen allokált memóriát speciális értékekkel (-1) akkor kezd csak kiakadni!

Tanácstalan vagyok. Nem sok kedvemn van az egészet átnézni, de félek tőle, csak az marad!

Biztos elegendő memóriát foglalsz? Nem felejtetted el megszorozni pl. egy sizeof(int) -el, 0 tol indexeled?.(Ne vedd sértésnek)

Nagyon valószínű, hogy valhol rosszul indexelsz pl. tömböt, és olyan helyre írsz ahhol malloc a memoria allokációs adatait tárolja.

Ha nem túl nagy a kód és nem túl bizalmas, akkor be is postolhatnád.
vagy pl. http://pastebin.com/ -en elhelyezhetnéd.

Ez buffer over-, v. underflow. Valamelyik tomb cimzesed cseszed el.

---
pontscho / fresh!mindworkz

Nemrég nekem is hasonlókat üzengetett (talán a 3.3-as fölötti gcc-vel, azt hiszem)
A g_free()-k helyett g_object_unref()-el szabadítottam fel a glib függvényei által foglalt területeket...

Jah! Lehet nem írtam, de sima C nyelvű a probléma.

foditsd debug modban, -g, valgrind (, gdb, strace).

ultra egy fos amit kikopnek, de erdemes atnezni es okulni belole. ha nem vilagos, akkor olvasni mig az nem lesz .... vagy atterni C# v. java-ra.

Mindenkinek köszönöm a segítséget! Valgrind volt a megoldás!

Az eset nem volt annyira egyszerű, de megoldottam. Mindenki okulására itt a lényeg:

#define T_SIZE 20

typedef struct t2{
    char c;
    int i;
} t2_t;

typedef t2_t t1_t[T_SIZE];

/*...*/

t1_t *func(){
    t1_t *res = calloc(sizeof(t1_t),1);
    int j;
    for(j=0;j<T_SIZE;j++){
        res[j]->c='\1';
        res[j]->i=-1;
    }
    return res;
}

Kijavítva:

/*...*/

t1_t *func(){
    t1_t res;
    int j;
    for(j=0;j<T_SIZE;j++){
        res[j].c='\1';
        res[j].i=-1;
    }
    return &res;
}

Üdv:
denx

UI: Lehet a fenti kódban van hiba, de igyekeztem csak a lényeget kicserélni

nem vok guru, de ez hibas... egy lokalos valtozot (res) adsz vissza fuggveny eredmenynek?
amugy szerintem
t1_t *res = calloc(sizeof(t2_t),T_SIZE);
--
A vegtelen ciklus is vegeter egyszer, csak kelloen eros hardver kell hozza!

ansi c permits mixed code and declarations, vagy hogy is mondja. illendő betartani

t1_t *res=NULL
...

res=calloc(sizeof(t1_t),1);
...
return res;

SZVSZ így mennie kéne. első glancra. vagy az indexelés (de azt most este meg sem próbáltam felfogni. egész nap fizikáztam.)

static t1_t res; //esetleg

szerk: nem ide kellett volna válaszolnom
------
gentóhuszár

ja, static megoldás lhet, de csak akkor ha csak 1-re van szükség ebból. vagy mindig memcpy-zni? na nemá'

Nem hagytál edittálni:

t1_t *func(){
        t2_t *res = calloc(sizeof(t1_t),1);
        int j;
        for(j=0;j<T_SIZE;j++){
                res[j].c='\1';
                res[j].i=-1;
        }
        return (t1_t*)res;
}

Ha nem rontottam el.

szerk: Elbandi callockja lehet, hogy szebb , de ide malloc is jó mivel úgy is a ciklusban kap értéket.

szerk2: Ha nem suliba készül,ezt az ősi szabvány-t nem fontos betartani, nem ismerek olyan fordítót ami nem támogatná.
------
gentóhuszár

Ha [code] [/code] közé teszed, emberibben néz ki...

--
trey @ gépház

Kösz, relációs jelek is megmaradnak így, nagyon zsíír.
------
gentóhuszár

nekem valami nem tetszik ebben:

typedef t2_t t1_t[T_SIZE];

/*...*/

ennek nem

typedef t2_t[T_SIZE] t1_t;

nek kéne lennie?

ha a fentvel fordítod le (amit beírtál) nem csodálom ha hibás, és kiindexelsz.

Nem.
------
gentóhuszár

??? ennyre este van?

nem így műxik?

typedef bla bla bla qqriq;

akkor:

qqriq foo;
ugyanaz mint
bla bla bla foo;

Könyen öszezavar engem is :)
A fordító nem így eszi meg.
typedef struct/enum nál a végére kerül a név, a de a tömb (/függvény) fura állat.

------
gentóhuszár

való igaz. akkor ennyire este van.

egyébként logikus.

int a[4];
a helyes és nem

int[4] a;

mind1. zsibbad az agyam, és utálom a csatolt rezgéseket.

Gyerekek ti mind nagyon fáradtak vagytok. :)

denx, te kijavítottál egy hibát, és beraktál egy másikat. :)

A calloc kell (vagy inkább malloc) mert különben a lokális változót turkálod, ami visszatéréskor "eltűnik". Persze ez akkor tűnik fel, mikor egy következő fv hívás felülírja a vermet.

Viszont ügyesen észrevetted, hogy "res[j]->c" helyett "res[j].c" kell.
(Perverzeknek "(res+j)->c").

(Egyébként a struct mögé nem kell a t2.)

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o

még perverzebeknek (és még fáradtabbaknak):

(*(res+j)).c

de lehet a külső () fölösleges. :)

Ezt majdnem odaírtam én is, de aztán mégse, elvégre a "->"-at kb így szokták bevezetni a könyvekben. :)

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o

mostmár jól szét lett offolva téma, de vajon megoldás született-e már?

Persze. Ő írta be, igaz 2 részletben. :)
Látom fáradtak vagytok, pedig csak most kezdődik az éjszaka.

/*...*/

t1_t* func(){
    t1_t *res;
    int j;
    res=(t1_t*) calloc(sizeof(t1_t),1);

    for(j=0;j<T_SIZE;j++){
        res[j].c='\1';
        res[j].i=-1;
    }
    return res;
}

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o

In function 'func':
error: request for member 'c' in something not a structure or union
error: request for member 'i' in something not a structure or union

Nem figyelsz, faradt vagy!
Mondom tipus!

t1_t* func(){
        t1_t *res;
        int j;
        res=(t1_t*) calloc(sizeof(t1_t),1);

        for(j=0;j<T_SIZE;j++){
                (*res)[j].c='\1';
                (*res)[j].i=-1;
        }
        return res;
}

------
gentóhuszár

Oh my God!

Mentségemre legyen mondva 4-5 éve nem írtam C-ben semmit.
Ilyen kódot meg soha... Ezek a typedefek brrrr.

Akkor legyen inkább:

t2_t* func(){
    t2_t *res;
    int j;
    res=(t2_t*) calloc(sizeof(t2_t),T_SIZE);

    for(j=0;j<T_SIZE;j++){
        res[j].c='\1';
        res[j].i=-1;
    }
    return res;
}

Ez így talán a legkevésbé undorító leginkább C-s.

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o

Akkor is enyim lesz az utolso szo ! :D
Igy gyorsabb, kb egy memset -el.

    res=(t2_t*) malloc(sizeof(t2_t)*T_SIZE);

typedefelet (constans meretu) struktura tomb valoban eleg attekintehetetlen tud lenni.
------
gentóhuszár

Szorakozzatok!,
HF:
mi let volna ha nem valtok tipust? :))
Legalabb 3 fele varacio eri a max pontot :-D
Felesleges tobbet kitalalni. :P
szerk:
Na meg harmat :)
------
gentóhuszár

a callocos castingra gondolsz? semmi. megadtad a típust, és calloc void* -ot ad vissza, azt bele lehet tölteni warning nélkül. erre tatlálták ki a char* helyet...

majd olnap megnézem/meggondolom mire gondoltál, ha nem erre. jóéjt

Gyors javítás:

t1_t *func (void)
{
    t1_t *res = calloc(sizeof(t1_t),1);
    int j;
    for(j=0;j<T_SIZE;j++){
        (*res)[j].c='\1';
        (*res)[j].i=-1;
    }
    return res;
}

Igényes javítás:

typedef struct telem {
    char c;
    int i;
} telem;

typedef struct tstruct {
    telem v[T_SIZE];
} tstruct;

tstruct *func (void)
{
    tstruct *res = calloc (sizeof (tstruct), 1);
    int j;

    for (j=0; j<T_SIZE; j++) {
        res->v[j].c='\1';
        res->v[j].i=-1;
    }
    return res;
}

Magyarul: lehetőleg ne használjunk összetett típusnak egy puszta tömböt, hanem ágyazzuk be egy struktúrába, például azért, hogy a fordító észrevegye az ilyesfajta hibákat.