2013-04-15 31 views
10

Parçalanma hatasına neden olan bir kodum var. Ben zamanında yazdırmak nasılbölümleme hatası neden yazdırılıyor

char * ptr = NULL; 
*ptr = "hello"; /* this will cause a segmentation fault */ 

, segmentasyon hatası meydana geldiğini bellekte adresi ve parçalama arızası sebebi (yasak hafıza bölgesine veya başka bir şeye erişim).

Çekirdek dökümü dosyaları hakkında okudum, ancak doğru çözüm olup olmadığından emin değilim.

Bunu nasıl yapabilirim?

P.S., ben gdb veya bir başka hata ayıklayıcı kullanarak elde edebilirsiniz gerçeğini yapmaya farkındayım ama amaç kodunu ve sadece kodu kullanarak bu yapmaktır.

+3

['backtrace'] (http://linux.die.net/man/3/backtrace) işlevini kullanabilirsiniz. Fakat programınızı bir hata ayıklayıcısında çalıştırmanızı öneririm, yalnızca backtrace'i görmenize izin vermez, aynı zamanda çağrı yığınına çıkıp değişkenleri incelemenize izin verir. –

+2

"çekirdek döküm dosyaları hakkında bilgi" - Onları kesinlikle öneriyorum. Her şeyi belleğe döküyorlar ve daha sonra bunları gdb ve doğru çalıştırılabilir ile açabilirsiniz. Bu size tam olarak ne olduğunu görme şansı verecektir (bellek dağınık olmadıkça, ama bu oldukça nadir durumdur) - herhangi bir değişkenin değerlerini, backtrace, konularını, vb. (Elbette, maksimum hata ayıklığına sahip olmak güzel olurdu) Bu tür bir soruşturma için seviye ve optimizasyon yok) –

+0

hmm .. '' ptr' tür 'char'' dır, ancak '' merhaba ''türü' char *' dır. Muhtemelen bir karakter atamalısınız ('* ptr = 'h';') veya bir 'memmove() 'kullanın veya doğru olması için örnek için benzer.olduğu gibi, dizge sabitinin adresini alır, onu tamsayıya çevirir, 1 bayta indirir ve daha sonra '* ptr' – SingleNegationElimination

cevap

4

Nedeni bilmek isterseniz, nal işleyicisi, gibi bir şey: Eğer kayıt olmak gerekiyor yere sonra

void handler(int signum, siginfo_t *info, void *context) 
{ 
    struct sigaction action = { 
    .sa_handler = SIG_DFL, 
    .sa_sigaction = NULL, 
    .sa_mask = 0, 
    .sa_flags = 0, 
    .sa_restorer = NULL 
    }; 

    fprintf(stderr, "Fault address: %p\n", info->si_addr); 
    switch (info->si_code) { 
    case SEGV_MAPERR: 
    fprintf(stderr, "Address not mapped.\n"); 
    break; 

    case SEGV_ACCERR: 
    fprintf(stderr, "Access to this address is not allowed.\n"); 
    break; 

    default: 
    fprintf(stderr, "Unknown reason.\n"); 
    break; 
    } 

    /* unregister and let the default action occur */ 
    sigaction(SIGSEGV, &action, NULL); 
} 

Ve:

struct sigaction action = { 
    .sa_handler = NULL, 
    .sa_sigaction = handler, 
    .sa_mask = 0, 
    .sa_flags = SA_SIGINFO, 
    .sa_restorer = NULL 
    }; 


    if (sigaction(SIGSEGV, &action, NULL) < 0) { 
    perror("sigaction"); 
    } 

Temel olarak SIGSEGV teslim edildiğinde yangınlar ve bazı ek bilgi almak yönünde bir işaret kayıt, alıntı adam sayfa:

The following values can be placed in si_code for a SIGSEGV signal: 

     SEGV_MAPERR address not mapped to object 

     SEGV_ACCERR invalid permissions for mapped object 

f iki temel nedenlerle bu harita veya bir seg hatası aldınız - ya eriştiğiniz sayfa hiç eşlenmedi, ya da o sayfaya ne tür bir girişimde bulunmuş olursanız olun.

Sinyal işleyici tetiklendikten sonra, kayıtların kaydını kaldırır ve varsayılan eylemi değiştirir. Bu, normal yoldan yakalanabilmesi için tekrar gerçekleştirilemeyen işlemlere neden olur. Bu, bir sayfa hatasının normal bir davranışıdır (önceliğin bir seg hatası alması), böylece talep çağrıları gibi şeyler çalışır.

2

Daha önce cevabı burada: How to generate a stacktrace when my gcc C++ app crashes

Sen (Linux/BSD ile GCC durumunda en az) oldukça kolay yapabilirsiniz:

örnek kod:

#include <stdio.h> 
#include <execinfo.h> 
#include <signal.h> 
#include <stdlib.h> 


void handler(int sig) { 
    void *array[10]; 
    size_t size; 

    // get void*'s for all entries on the stack 
    size = backtrace(array, 10); 

    // print out all the frames to stderr 
    fprintf(stderr, "Error: signal %d:\n", sig); 
    backtrace_symbols_fd(array, size, 2); 
    exit(1); 
} 

int main(int argc, char **argv) { 
    signal(SIGSEGV, handler); // install our handler 

    char * ptr = NULL; 
    *ptr = "hello"; /* this will cause a segmentation fault */ 
} 

Örnek çıktı :

# gcc -g -rdynamic -o test test.c 
# ./test 
Error: signal 11: 
0 test        0x000000010e99dcfa handler + 42 
1 libsystem_c.dylib     0x00007fff95c1194a _sigtramp + 26 
2 ???         0x0000000000000000 0x0 + 0 
3 libdyld.dylib      0x00007fff8fa177e1 start + 0 
4 ???         0x0000000000000001 0x0 + 1 
+0

Bu, artık en az orijinal hata nedeni olan bir çekirdek dökümü üretmeyecektir. Tamam, bir çeşit stacktrace var, ama daha az değeri var. Suç yok, biz sadece OP'lerin sorusunu cevaplıyoruz, ancak uyarılar zaten geçerlidir ;-). Ayrıca, bir sinyal işleyicide (yani en azından asenkron sinyaller için) zor olabilecek fprintf'den kaçınmak için 'sprintf' ve 'write (2, buf, ...)' kombinasyonunu kullanmayı düşünün. Ayrıca, 'exit()' den değil, sadece '_exit()' ya da 'abort()' diyemem. Ama YMMV. –

+0

Sana katılıyorum Christian, eğer bir çekirdek çöplük göndermek istemiyorsan, bunu bazı yapılarda mümkün kılabilirsin. Ama şahsen ben sadece bir komut dosyasında (eğer mevcutsa) gdb'nin oluşturulmuş çekirdek dökümünden istiflemesini göstermesine izin veren bir betik içerisine koyardım… Çok daha mantıklı bir çözüm gibi görünüyor. – Wolph

İlgili konular