J'ai un processus sous Linux qui obtient un défaut de segmentation. Comment puis-je lui dire de générer un vidage de mémoire en cas d'échec?
J'ai un processus sous Linux qui obtient un défaut de segmentation. Comment puis-je lui dire de générer un vidage de mémoire en cas d'échec?
Réponses:
Cela dépend du shell que vous utilisez. Si vous utilisez bash, la commande ulimit contrôle plusieurs paramètres relatifs à l'exécution du programme, par exemple si vous devez vider le core. Si vous tapez
ulimit -c unlimited
alors cela indiquera à bash que ses programmes peuvent vider des cœurs de n'importe quelle taille. Vous pouvez spécifier une taille telle que 52M au lieu d'un nombre illimité si vous le souhaitez, mais en pratique cela ne devrait pas être nécessaire car la taille des fichiers de base ne sera probablement jamais un problème pour vous.
Dans tcsh, vous taperiez
limit coredumpsize unlimited
Comme expliqué ci-dessus, la vraie question posée ici est de savoir comment activer les vidages mémoire sur un système où ils ne sont pas activés. On répond ici à cette question.
Si vous êtes venu ici dans l'espoir d'apprendre à générer un vidage de mémoire pour un processus bloqué, la réponse est
gcore <pid>
si gcore n'est pas disponible sur votre système,
kill -ABRT <pid>
N'utilisez pas kill -SEGV car cela invoquera souvent un gestionnaire de signal, ce qui rendra plus difficile le diagnostic du processus bloqué
-ABRT
cela invoque un gestionnaire de signaux -SEGV
, car un abandon est plus susceptible d'être récupéré qu'un défaut de segmentation. (Si vous gérez un défaut de segmentation, il se déclenchera normalement à nouveau dès que votre gestionnaire se terminera.) Un meilleur choix de signal pour générer un vidage de mémoire est -QUIT
.
Pour vérifier où les vidages mémoire sont générés, exécutez:
sysctl kernel.core_pattern
ou:
cat /proc/sys/kernel/core_pattern
où %e
est le nom du processus et %t
l'heure du système. Vous pouvez le changer /etc/sysctl.conf
et recharger par sysctl -p
.
Si les fichiers de base ne sont pas générés (test par: sleep 10 &
et killall -SIGSEGV sleep
), vérifier les limites par: ulimit -a
.
Si la taille de votre fichier principal est limitée, exécutez:
ulimit -c unlimited
pour le rendre illimité.
Ensuite, testez à nouveau, si le vidage du cœur est réussi, vous verrez «(cœur vidé)» après l'indication de défaut de segmentation comme ci-dessous:
Erreur de segmentation: 11 (core dumped)
Voir aussi: core dumped - mais le fichier core n'est pas dans le répertoire courant?
Dans Ubuntu, les vidages mémoire sont gérés par Apport et peuvent être localisés dans /var/crash/
. Cependant, il est désactivé par défaut dans les versions stables.
Pour plus de détails, veuillez vérifier: Où puis-je trouver le vidage de mémoire dans Ubuntu? .
Pour macOS, voir: Comment générer des vidages mémoire sous Mac OS X?
Ce que j'ai fait à la fin était d'attacher gdb au processus avant qu'il ne plante, puis quand il a eu le défaut de segmentation, j'ai exécuté la generate-core-file
commande. Cette génération forcée d'un vidage de mémoire.
ge
)
ulimit -c
sur unlimited
, mais le fichier core n'est toujours pas créé, le generate-core-file
fichier dans la session gdb crée le fichier core, merci.
Peut-être que vous pourriez le faire de cette façon, ce programme est une démonstration de la façon de piéger une erreur de segmentation et de la décoder vers un débogueur (c'est le code d'origine utilisé ci-dessous AIX
) et imprime la trace de la pile jusqu'au point d'une erreur de segmentation. Vous devrez changer la sprintf
variable à utiliser gdb
dans le cas de Linux.
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <stdarg.h>
static void signal_handler(int);
static void dumpstack(void);
static void cleanup(void);
void init_signals(void);
void panic(const char *, ...);
struct sigaction sigact;
char *progname;
int main(int argc, char **argv) {
char *s;
progname = *(argv);
atexit(cleanup);
init_signals();
printf("About to seg fault by assigning zero to *s\n");
*s = 0;
sigemptyset(&sigact.sa_mask);
return 0;
}
void init_signals(void) {
sigact.sa_handler = signal_handler;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigaction(SIGINT, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGSEGV);
sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGBUS);
sigaction(SIGBUS, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGQUIT);
sigaction(SIGQUIT, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGHUP);
sigaction(SIGHUP, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGKILL);
sigaction(SIGKILL, &sigact, (struct sigaction *)NULL);
}
static void signal_handler(int sig) {
if (sig == SIGHUP) panic("FATAL: Program hanged up\n");
if (sig == SIGSEGV || sig == SIGBUS){
dumpstack();
panic("FATAL: %s Fault. Logged StackTrace\n", (sig == SIGSEGV) ? "Segmentation" : ((sig == SIGBUS) ? "Bus" : "Unknown"));
}
if (sig == SIGQUIT) panic("QUIT signal ended program\n");
if (sig == SIGKILL) panic("KILL signal ended program\n");
if (sig == SIGINT) ;
}
void panic(const char *fmt, ...) {
char buf[50];
va_list argptr;
va_start(argptr, fmt);
vsprintf(buf, fmt, argptr);
va_end(argptr);
fprintf(stderr, buf);
exit(-1);
}
static void dumpstack(void) {
/* Got this routine from http://www.whitefang.com/unix/faq_toc.html
** Section 6.5. Modified to redirect to file to prevent clutter
*/
/* This needs to be changed... */
char dbx[160];
sprintf(dbx, "echo 'where\ndetach' | dbx -a %d > %s.dump", getpid(), progname);
/* Change the dbx to gdb */
system(dbx);
return;
}
void cleanup(void) {
sigemptyset(&sigact.sa_mask);
/* Do any cleaning up chores here */
}
Vous devrez peut-être ajouter en plus un paramètre pour que gdb vide le noyau comme indiqué ici dans ce blog ici .
D'autres éléments peuvent influencer la génération d'un vidage de mémoire. Je les ai rencontrés:
/proc/sys/kernel/core_pattern
. /proc/sys/fs/suid_dumpable
peut empêcher la génération du noyau.D'autres situations peuvent empêcher la génération décrites dans la page de manuel - essayez man core
.
Pour activer le vidage de mémoire, procédez comme suit:
En /etc/profile
commentaire la ligne:
# ulimit -S -c 0 > /dev/null 2>&1
En /etc/security/limits.conf
commentaire sur la ligne:
* soft core 0
exécutez le cmd limit coredumpsize unlimited
et vérifiez-le avec cmd limit
:
# limit coredumpsize unlimited
# limit
cputime unlimited
filesize unlimited
datasize unlimited
stacksize 10240 kbytes
coredumpsize unlimited
memoryuse unlimited
vmemoryuse unlimited
descriptors 1024
memorylocked 32 kbytes
maxproc 528383
#
pour vérifier si le fichier core est écrit, vous pouvez tuer le processus correspondant avec cmd kill -s SEGV <PID>
(ne devrait pas être nécessaire, juste au cas où aucun fichier core ne serait écrit, cela peut être utilisé comme vérification):
# kill -s SEGV <PID>
Une fois le corefile écrit, assurez-vous de désactiver à nouveau les paramètres du coredump dans les fichiers associés (1./2./3.)!
Pour Ubuntu 14.04
Vérifier le vidage de mémoire activé:
ulimit -a
L'une des lignes devrait être:
core file size (blocks, -c) unlimited
Si non :
gedit ~/.bashrc
et ajouter ulimit -c unlimited
à la fin du fichier et enregistrer, réexécuter le terminal.
Créez votre application avec des informations de débogage:
Dans Makefile -O0 -g
Exécutez l'application qui crée le vidage de mémoire (le fichier de vidage de mémoire avec le nom 'core' doit être créé près du fichier nom_application):
./application_name
Exécutez sous gdb:
gdb application_name core
ulimit -c unlimited
terminal pour une solution temporaire, car seule l'édition ~/.bashrc
nécessite un redémarrage du terminal pour que les modifications prennent effet.
Par défaut, vous obtiendrez un fichier core. Vérifiez que le répertoire actuel du processus est accessible en écriture, sinon aucun fichier principal ne sera créé.
Mieux vaut activer le vidage de mémoire par programmation à l'aide d'un appel système setrlimit
.
exemple:
#include <sys/resource.h>
bool enable_core_dump(){
struct rlimit corelim;
corelim.rlim_cur = RLIM_INFINITY;
corelim.rlim_max = RLIM_INFINITY;
return (0 == setrlimit(RLIMIT_CORE, &corelim));
}
ulimit -c unlimited
dans l'environnement de ligne de commande, puis réexécutez l'application.
ulimit -c unlimited
. Vous pouvez également compiler avec la définition marco, l'application n'inclura pas de enable_core_dump
symbole si elle ne définit pas cette macro lors de la publication, et vous obtiendrez un remplacement de vidage de mémoire par une version de débogage.
Il convient de mentionner que si vous avez configuré un système , les choses sont un peu différentes. La configuration aurait généralement les fichiers de base être canalisés, au moyen de la core_pattern
valeur sysctl, à travers systemd-coredump(8)
. La taille de fichier de base rlimit serait généralement déjà configurée comme "illimitée".
Il est alors possible de récupérer les vidages mémoire à l'aide de coredumpctl(1)
.
Le stockage des vidages mémoire, etc. est configuré par coredump.conf(5)
. Il y a des exemples de comment obtenir les fichiers principaux dans la page de manuel de coredumpctl, mais en bref, cela ressemblerait à ceci:
Trouvez le fichier principal:
[vps@phoenix]~$ coredumpctl list test_me | tail -1
Sun 2019-01-20 11:17:33 CET 16163 1224 1224 11 present /home/vps/test_me
Obtenez le fichier principal:
[vps@phoenix]~$ coredumpctl -o test_me.core dump 16163
Ubuntu 19.04
Toutes les autres réponses elles-mêmes ne m'ont pas aidé. Mais le résumé suivant a fait le travail
Créez ~/.config/apport/settings
avec le contenu suivant:
[main]
unpackaged=true
(Cela indique à répart d'écrire également les vidages de mémoire pour les applications personnalisées)
vérifier: ulimit -c
. S'il sort 0, corrigez-le avec
ulimit -c unlimited
Juste au cas où le redémarrage serait réparti:
sudo systemctl restart apport
Les fichiers de plantage sont maintenant écrits /var/crash/
. Mais vous ne pouvez pas les utiliser avec gdb. Pour les utiliser avec gdb, utilisez
apport-unpack <location_of_report> <target_directory>
Plus d'informations:
core_pattern
. Sachez que ce fichier peut être écrasé par le service d'allocation au redémarrage.ulimit -c
valeur peut être modifiée automatiquement lorsque vous essayez d'autres réponses sur le Web. Assurez-vous de le vérifier régulièrement lors de la configuration de votre création de vidage de mémoire.Références: