Neden bir C malloc onaylama hatası alıyorum?


86

Böl ve fethet polinom algoritması uyguluyorum, böylece onu bir OpenCL uygulamasıyla karşılaştırabiliyorum, ancak mallocişe koyamıyorum. Programı çalıştırdığımda, bir sürü şey ayırıyor, bazı şeyleri kontrol ediyor size/2ve ardından algoritmaya gönderiyor . Sonra malloctekrar çizgiye bastığımda şunu söylüyor:

malloc.c:3096: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed.
Aborted

Söz konusu satır şudur:

Boyutu a ile kontrol ettim fprintfve pozitif bir tamsayı (bu noktada genellikle 50). mallocDüz bir numara ile de aramayı denedim ve hala hatayı alıyorum. Sadece neler olup bittiğine şaşırdım ve şu ana kadar Google'dan bulduğum hiçbir şey yardımcı olmadı.

Neler olduğu hakkında bir fikrin var mı? Bir derleyici hatası olması durumunda daha yeni bir GCC'yi nasıl derleyeceğimi anlamaya çalışıyorum, ama gerçekten şüpheliyim.


Sorunun aslında ondan önceki bir satır olduğundan şüpheleniyorum. Belki bir çift bedava?
Mitch Wheat

Programdaki 3. satır: int * mult (int size, int * a, int * b) {int * out, i, j, * tmp1, * tmp2, * tmp3, * tmpa1, * tmpa2, * tmpb1, * tmpb2 , d, * res1, * res2; fprintf (stdout, "boyut:% d \ n", boyut); out = (int *) malloc (sizeof (int) * boyut * 2);
Chris

Yanıtlar:


100

Belleği bozma olasılığınız% 99,9'dur (bir arabelleği aşırı veya az akıtmış, serbest bırakıldıktan sonra bir işaretçiye yazmış, aynı işaretçide iki kez ücretsiz olarak çağırma vb.)

Programınızın yanlış bir şeyi nerede yaptığını görmek için kodunuzu Valgrind altında çalıştırın .


1
sabit. Valgrind kesinlikle yardımcı oldu. Eski matlab kodumu yanlış yazdım ve j üzerinde yinelenen bir for döngüsüne sahiptim, sonra içinde yazdığım dizinin çoğunun üzerine yazan ve bir şekilde malloc'un başarısız olmasına neden olan j ++ yaptı. yardım için teşekkürler!
Chris

Valgrind, bu hatayı aldığımda neler olduğunu anlamak için ihtiyacım olan araçtı. Bahsettiğin için teşekkürler.
alexwells

78

Bunun neden olduğunu size daha iyi anlamak için @ r-samuel-klatchko'nun cevabını biraz genişletmek istiyorum.

Aradığınızda malloc, gerçekte olan şey size oynamanız için bir yığın bellek vermekten biraz daha karmaşıktır. Kaputun altında, mallocsize verdiği hafıza hakkında bazı temizlik bilgilerini de tutar (en önemlisi, boyutu), böylece aradığınızda free, ne kadar hafıza boşaltılacağını bilir. Bu bilgiler genellikle bellek konumu tarafından size dönmeden hemen önce saklanır malloc. İnternet ™ 'te daha ayrıntılı bilgi bulunabilir , ancak (çok) temel fikir şuna benzer:

Bunu temel alarak (ve işleri büyük ölçüde basitleştirerek), aradığınızda malloc, kullanılabilir olan belleğin bir sonraki bölümüne bir işaretçi alması gerekir. Bunu yapmanın çok basit bir yolu, verdiği önceki bellek bitine bakmak ve sizebaytları bellekte daha da aşağıya (veya yukarıya) taşımaktır . Bu uygulama sayesinde, tahsis sonra böyle bir şey görünümlü bellek ile sona p1, p2ve p3:

Peki, hatanıza ne sebep oluyor?

Öyleyse, kodunuzun yanlışlıkla ayırdığınız bellek miktarının ötesine yazdığını hayal edin (ya probleminizdeki gibi ihtiyaç duyduğunuzdan daha azını ayırdığınız için ya da kodunuzun herhangi bir yerinde yanlış sınır koşullarını kullandığınız için). Kodunuzu için bu kadar veriyi yazar Say p2bunun içinde ne üzerine yazarak başladığı p3'ın sizealanda. Şimdi bir sonraki aramanızda malloc, geri döndüğü son bellek konumuna bakacak, boyut alanına bakacak, p3 + sizeoraya gidecek ve oradan bellek ayırmaya başlayacaktır. sizeBununla birlikte, kodunuzun üzerine yazıldığı için , bu bellek konumu artık önceden ayrılmış bellekten sonra değildir.

Söylemeye gerek yok, bu durumu mahvedebilir! Bu mallocnedenle uygulayıcılar, eğer gerçekleşeceklerse, bunu (ve diğer sorunları) yakalamak için bir dizi akıl sağlığı kontrolü yapmaya çalışan bir dizi "iddia" veya kontrol koydu. Sizin özel durumunuzda, bu iddialar ihlal edilir ve dolayısıyla mallociptal edilir, size kodunuzun gerçekten yapmaması gereken bir şeyi yapmak üzere olduğunu söyler.

Daha önce belirtildiği gibi, bu büyük bir aşırı basitleştirmedir, ancak konuyu açıklamak için yeterlidir. Glibc uygulaması malloc5k satırdan fazladır ve iyi dinamik bellek ayırma mekanizmalarının nasıl oluşturulacağına dair önemli miktarda araştırma yapılmıştır, bu nedenle hepsini bir SO yanıtında kaplamak mümkün değildir. Umarım bu size soruna gerçekte neyin neden olduğuna dair bir fikir vermiştir!


17

Valgrind kullanmaya alternatif çözümüm:

Çok mutluyum çünkü arkadaşımın bir programda hata ayıklamasına yardım ettim. Onun programında malloc()GDB'den gelen aynı hata mesajıyla birlikte tam olarak bu sorun vardı ( iptale neden oldu).

Ben kullanarak kendi programını derlenmiş Adres Temizleyici ile

Ve sonra koştu gdb new. Program daha SIGABRTsonraki sebeplerden dolayı sonlandırıldığında malloc(), pek çok yararlı bilgi yazdırılır:

Çıktıya, özellikle de yığın izine bir göz atalım:

İlk bölüm, adresinde geçersiz bir yazma işlemi olduğunu söylüyor new.c:59. Bu satır okur

İkinci bölüm, kötü yazmanın meydana geldiği hafızanın saatinde yaratıldığını söylüyor new.c:55. Bu satır okur

Bu kadar. Arkadaşımın kafasını birkaç saat karıştıran hatayı bulmam sadece yarım dakikadan az sürdü. Başarısızlığı bulmayı başardı, ancak malloc()bu hatayı önceki kodda tespit edemeden başarısız olan sonraki bir çağrı.

Özetle: -fsanitize=addressGCC veya Clang'ı deneyin . Bellek sorunlarını ayıklarken çok yardımcı olabilir.


1
Az önce hayatımı kurtardın.
Nate Symer


2

Size benzer bir mesaj aldım:

    program: malloc.c: 2372: sysmalloc: Assertion `(old_top == (((mbinptr) (((char *) & ((av) -> bins [((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size)> = (unsigned long) ((((__ builtin_offsetof (struct malloc_chunk, fd_nextsize)) + ((2 * (sizeof (size_t))) - 1)) & ~ ((2 * (sizeof (size_t))) - 1))) && ((old_top) -> size & 0x1) && ((unsigned long) old_end & pagemask) == 0) 'başarısız oldu.

Malloc kullanırken daha önce bazı yöntem çağrılarında hata yaptım. Sizeof () - operatöründen sonra işaretsiz karakter dizisine bir alan eklerken çarpanını güncellerken '*' çarpma işaretinin üzerine hatalı olarak '+' yazdı

Benim durumumdaki hatadan sorumlu olan kod:

    UCHAR * b = (UCHAR *) malloc (sizeof (UCHAR) +5);
    b [INTBITS] = (bazı hesaplamalar);
    b [BUFSPC] = (bazı hesaplamalar);
    b [BUFOVR] = (bazı hesaplamalar);
    b [BUFMEM] = (bazı hesaplamalar);
    b [MATCHBITS] = (bazı hesaplamalar);

Daha sonra başka bir yöntemde yine malloc kullandım ve yukarıda gösterilen hata mesajını üretti. Çağrı (yeterince basit):

    UCHAR * b = (UCHAR *) malloc (sizeof (UCHAR) * 50);

İlk çağrıda '+' - işaretini kullanmayı düşünün, bu da dizinin hemen başlatılmasıyla birlikte yanlış hesaplamaya yol açar (diziye ayrılmamış belleğin üzerine yazma), malloc'un bellek haritasına biraz kafa karışıklığı getirdi. Bu nedenle 2. arama yanlış gitti.


0

Bu hatayı aldık çünkü sizeof (int) ile çarpmayı unuttuk. Malloc (..) argümanının bir bayt sayısı olduğuna dikkat edin, makine kelimelerinin sayısı veya her neyse değil.


0

aynı sorunu yaşadım, yeni char * string verisi eklemek için bir döngüde malloc over n'yi tekrar kullandım. aynı sorunla karşılaştım, ancak ayrılan bellek void free()sorunu çözüldükten sonra


-2

Linux üzerinden Visual C'den gcc'ye bir uygulama aktarıyordum ve aynı sorunu yaşadım

malloc.c: 3096: sYSMALLOc: UBUNTU 11 üzerinde gcc kullanarak onaylama.

Aynı kodu bir Suse dağıtımına (başka bir bilgisayarda) taşıdım ve herhangi bir sorunum yok.

Sorunların programlarımızda değil kendi libc'de olduğundan şüpheleniyorum.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.