Jak programowo spowodować zrzut pamięci w C / C ++


93

Chciałbym wymusić zrzut rdzenia w określonej lokalizacji w mojej aplikacji C ++.

Wiem, że mogę to zrobić, robiąc coś takiego:

int * crash = NULL;
*crash = 1;

Ale chciałbym wiedzieć, czy istnieje czystszy sposób?

Nawiasem mówiąc, używam Linuksa.


18
Czystszy sposób na zrzut pamięci? .... dobry;)
Dz.

5
To jest śliczne. Jeszcze lepiej użyj wartości logicznej (wyliczenie w c?) ... if ( crash = TRUE) {/ OH SHI ... * /}
Ape-inago,

3
Przy okazji, ta metoda nie działa we wszystkich systemach UNIX. Na przykład HPUX pozwala na bezkarne odczytywanie i zapisywanie NULL (na szczęście jest to konfigurowalne).
paxdiablo

1
Właśnie nauczyłem się 3 lub 4 wspaniałych nowych rzeczy. Dzięki.
Trevor Boyd Smith

@pax to bardziej powód, aby znaleźć ogólny sposób;) Dzięki
hhafez

Odpowiedzi:


78

Podniesienie sygnału numer 6 ( SIGABRTw Linuksie) jest jednym ze sposobów na zrobienie tego (choć pamiętaj, że SIGABRT nie musi mieć 6 we wszystkich implementacjach POSIX, więc możesz chcieć użyć SIGABRTsamej wartości, jeśli jest to coś innego niż quick'n 'brudny kod debugowania).

#include <signal.h>
: : :
raise (SIGABRT);

Wywołanie abort()spowoduje również zrzutu pamięci, a można to zrobić nawet bez kończącego proces poprzez wywołanie fork()następuje abort()w dziecku tylko - zobacz tę odpowiedź szczegóły.


7
SIGABRT nie musi być sygnałem numer 6 (chociaż często jest - i jest szczególnie w systemie Linux).
Jonathan Leffler

4
Nie, masz rację, nie jest, ale nie przejmuję się zbytnio poprawnością kodu debugowania. Jeśli to ucieknie na wolność, czystość mojego kodu jest najmniejszym z moich zmartwień :-)
paxdiablo

2
Wywołanie abort () może być bezużyteczne na niektórych architekturach z niektórymi kompilatorami i niektórymi bibliotekami C (np. Gcc i glibc lub uClibc na ARM), ponieważ funkcja abort () jest zadeklarowana z atrybutem noreturn, a kompilator całkowicie optymalizuje wszystkie zwracane informacje, co sprawia, że ​​plik core jest bezużyteczny. Nie możesz prześledzić tego poza samym wywołaniem funkcji raise () lub abort (). Więc znacznie lepiej jest wywołać podbicie (SIGABRT) bezpośrednio lub zabić (getpid (), SIGABRT), co jest praktycznie tym samym.
Alexander Amelkin,

3
Przepraszamy, na ARM to samo dzieje się nawet z podbiciem (SIGABRT). Tak więc jedynym sposobem na stworzenie identyfikowalnego pliku core jest kill (getpid (), SIGABRT)
Alexander Amelkin

Wskazówka ulimit -c unlimitedudzielona przez Suvesh Pratapa, bardzo mi pomogła w uzyskaniu tej odpowiedzi.
Boris Däppen

75

Kilka lat temu firma Google udostępniła bibliotekę coredumper .

Przegląd

Bibliotekę coredumper można skompilować do aplikacji w celu tworzenia zrzutów jądra uruchomionego programu - bez przerywania pracy. Obsługuje zarówno jedno-, jak i wielowątkowe zrzuty rdzenia, nawet jeśli jądro nie obsługuje natywnie wielowątkowych plików rdzenia.

Coredumper jest rozpowszechniany na warunkach Licencji BSD.

Przykład

Nie jest to bynajmniej pełny przykład; po prostu daje ci poczucie, jak wygląda API coredumper.

#include <google/coredumper.h>
...
WriteCoreDump('core.myprogram');
/* Keep going, we generated a core file,
 * but we didn't crash.
 */

Nie o to prosiłeś, ale może jest jeszcze lepiej :)


3
Początkowo byłem bardzo podekscytowany, gdy natknąłem się na tę odpowiedź. Ale obecnie wywrotka wygląda na dość starą i zgniłą. Jest nawet wskazanie, że nie działa już na współczesnych jądrach Linuksa: stackoverflow.com/questions/38314020/ ...
jefe2000

37

Jak podano na stronie podręcznika sygnału , każdy sygnał z akcją wymienioną jako „rdzeń” wymusi zrzut rdzenia. Oto kilka przykładów:

SIGQUIT       3       Core    Quit from keyboard
SIGILL        4       Core    Illegal Instruction
SIGABRT       6       Core    Abort signal from abort(3)
SIGFPE        8       Core    Floating point exception
SIGSEGV      11       Core    Invalid memory reference

Upewnij się, że włączyłeś zrzuty podstawowe:

ulimit -c unlimited

Dziękuję, twoja uwaga na temat włączania zrzutów pamięci z pomocą ulimit -c unlimited.

Jak ustawić ulimit z poziomu kodu? @ ks1322
Karan Joisher,

@KaranJoisher To prawdopodobnie warte innego pytania samo w sobie, ale w skrócie możesz skorzystać z setrlimit(RLIMIT_CORE, &core_limits);dostępnych przez #include <sys/resource.h>. Tworzysz strukturę typu, rlimita następnie ustawiasz elementy członkowskie rlim_curi rlim_max.
Brent pisze kod



6

Inny sposób generowania zrzutu pamięci:

$ bash
$ kill -s SIGSEGV $$

Po prostu utwórz nową instancję basha i zabij ją określonym sygnałem. To $$jest PID powłoki. W przeciwnym razie zabijesz swój obecny bash i zostaniesz wylogowany, terminal zamknięty lub odłączony.

$ bash 
$ kill -s SIGABRT $$
$ bash
$ kill -s SIGFPE $$

Bardzo proste i przydatne!
firo

1
Też mi się podoba. Można to nawet uprościć do bash -c 'kill -SIGSEGV $$'.
Christian Krause,


2

Czasami warto zrobić coś takiego:

int st = 0;
pid_t p = fork();

if (!p) {
    signal(SIGABRT, SIG_DFL);
    abort(); // having the coredump of the exact copy of the calling thread
} else {
    waitpid(p, &st, 0); // rip the zombie
}

// here the original process continues to live

Jednym z problemów związanych z tym prostym podejściem jest to, że tylko jeden wątek zostanie poddany rdzeniu.


1
 #include <stdio.h>
 #include <stdlib.h>
 int main()
 {
   printf("\n");
   printf("Process is aborting\n");
   abort();
   printf("Control not reaching here\n");
   return 0;
 }

zastosuj to podejście gdziekolwiek chcesz :)


0
#include <assert.h>
.
.
.
     assert(!"this should not happen");

Prawdopodobnie trzeba się przespać z NDEBUG, więc ta konkretna asercja jest aktywna nawet wtedy, gdy inne potwierdzenia nie są.
Rhys Ulerich
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.