aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Metin2

Metin2 Core Crash : lire les core dumps et déboguer

Si vous gérez un serveur Metin2, vous finirez tôt ou tard par rencontrer un metin2 core crash : le cœur du jeu (le processus game) s'arrête brutalement, les joueurs perdent leur connexion et un fichier core dump reste sur le disque. La plupart des gens paniquent à ce moment-là, redémarrent le processus et ignorent le problème. Pourtant, ce core dump est la ressource la plus précieuse dont vous disposez : il décrit la cause exacte du crash, ligne par ligne. Dans ce guide, je vais vous montrer pas à pas comment lire un core dump avec gdb, comment interpréter la backtrace et comment corriger durablement les causes de crash les plus fréquentes.

Qu'est-ce qu'un core dump et pourquoi est-il important ?

Quand un processus reçoit un signal fatal (généralement SIGSEGV — un accès mémoire invalide), le système d'exploitation peut écrire sur le disque l'image mémoire actuelle du processus. C'est ce qu'on appelle un core dump. Sous FreeBSD, le fichier s'appelle généralement game.core ; sous Linux, c'est core ou core.PID, créé dans le répertoire de travail du processus. Il contient la pile d'appels, les valeurs des registres et le dernier état des variables. Autrement dit, il fige l'instant du crash comme une photographie.

Un point important : la génération des core dumps doit être activée, sinon vous n'aurez rien à analyser.

# Afficher la limite actuelle
ulimit -c
# Autoriser des core dumps illimités (avant de lancer game)
ulimit -c unlimited

Sous Linux, core_pattern contrôle où le fichier core est écrit et sous quel nom. Vérifiez que le noyau ne redirige pas le core ailleurs (par ex. vers systemd-coredump) :

cat /proc/sys/kernel/core_pattern
# Pour un fichier simple nommé avec le PID dans le répertoire de travail :
echo 'core.%p' > /proc/sys/kernel/core_pattern

Ouvrir le core dump avec gdb

Le cœur de l'analyse, c'est gdb. Pour voir la cause du crash, vous devez ouvrir le fichier core avec le binaire game exactement identique à celui qui l'a produit ; si vous l'ouvrez avec une autre compilation, les adresses ne correspondront pas et la backtrace n'aura aucun sens.

# FreeBSD
gdb ./game game.core
# Linux
gdb ./game core.12345

Une fois gdb ouvert, votre première commande doit être bt (backtrace). Elle liste la chaîne d'appels au moment du crash, de la fonction la plus interne vers l'extérieur :

(gdb) bt
#0  0x081a2b3c in CHARACTER::GetLevel (this=0x0) at char.cpp:1042
#1  0x0819f0a1 in CHARACTER::ComputePoints (this=0x0) at char_battle.cpp:88
#2  ...

Dans l'exemple ci-dessus, this=0x0 est l'indice critique : GetLevel() a été appelée sur un pointeur null. Pour plus de contexte, ces commandes font le travail :

  • bt full — affiche aussi les variables locales de chaque frame de pile.
  • thread apply all bt — vide les piles de tous les threads pour les crashs multithreads.
  • frame 1 puis print *this — permet d'inspecter les variables d'une frame précise.
  • info registers — affiche l'état des registres.

Impossible de lire une backtrace sans symboles de débogage

Si la sortie de bt affiche ?? () et seulement des adresses au lieu des noms de fonctions, votre binaire a été strippé — les symboles ont été supprimés. Dans ce cas, il y a peu à faire. La solution est de compiler les sources avec le drapeau -g et de conserver les symboles.

# À ajouter à votre Makefile / vos flags de compilation
CFLAGS += -g
# Ne strippez PAS la compilation avant le déploiement ; gardez une copie de debug séparée

Une bonne habitude : conservez une copie séparée, non strippée, du binaire en production, compilée avec -g. Quand un core tombe, ouvrez-le avec cette copie. Même si vous utilisez une compilation strippée en production pour la performance, les adresses correspondront tant qu'il s'agit de la même compilation.

Causes de crash les plus fréquentes

Au fil des années, voici les causes de metin2 core crash que j'ai le plus souvent rencontrées dans le code source de Metin2 :

  • Pointeur CHARACTER null ou libéré : si un timer de quête, un groupe ou un message p2p référence encore un joueur après sa déconnexion, l'accès via le pointeur invalide provoque un crash. Un this=0x0 ou une adresse étrange dans la backtrace en est le signe.
  • Données proto corrompues : accès à un vnum inexistant dans item_proto, mob_proto ou les quêtes. Une définition d'item/mob manquante plante via un accès hors limites.
  • Erreurs de quête : une erreur de logique côté Lua passe un argument invalide à une fonction native. Les lignes SYSERR juste avant le crash dans syserr.txt nomment généralement la quête.
  • Débordement de paquet/buffer : une structure de paquet mal dimensionnée ou une entrée client non fiable provoque une lecture/écriture hors limites.
  • Double libération (double free) : le même objet est delete deux fois ; très fréquent lors des annulations d'événements/timers.

Une fois que la backtrace vous a mené à un fichier et une ligne, ajouter une garde qui vérifie la validité du pointeur sur cette ligne est souvent la correction durable la plus rapide :

// Avant : plante si ch est null
ch->ComputePoints();

// Après : vérification défensive
if (ch == NULL)
    return;
ch->ComputePoints();

Lisez les logs en parallèle du core

Un core dump n'est pas seul. Les fichiers syserr.txt et syslog.txt dans le répertoire de travail du processus game conservent les derniers événements avant le crash, avec horodatage. Méthode pratique : prenez l'horodatage du crash et cherchez cette seconde dans syserr.txt.

tail -n 100 syserr.txt
grep -n "SYSERR" syserr.txt | tail -n 20

Souvent, la backtrace vous dit « où » ça a planté, tandis que syserr.txt vous dit « après quel événement ». Combinez les deux et le « pourquoi » apparaît.

Reproduire et vérifier le crash

Après avoir appliqué un correctif, essayez toujours de déclencher à nouveau le crash : quel item, quelle quête, quelle interaction PNJ le provoquait ? Reproduisez les étapes sur un serveur de test. Vous n'avez validé le correctif que lorsque le crash ne peut plus être reproduit. Sinon, vous n'avez peut-être supprimé que le symptôme et manqué la cause racine.

Questions fréquentes

Aucun fichier core dump n'est créé — pourquoi ?

La raison la plus fréquente est que ulimit -c vaut 0 ; définissez ulimit -c unlimited dans le shell qui lance game. Sous Linux, vérifiez aussi que core_pattern ne redirige pas le core vers systemd-coredump et que le répertoire est accessible en écriture.

La backtrace n'a pas de noms de fonctions, seulement des adresses. Que faire ?

Cela signifie que votre binaire est strippé. Recompilez les sources avec le drapeau -g, conservez les symboles et ouvrez le core avec cette copie riche en symboles. On ne peut pas extraire de pile exploitable d'un binaire strippé.

Le crash est aléatoire, sans étapes fixes — comment l'attraper ?

Collectez plusieurs core dumps et comparez toutes leurs backtraces. Si la même fonction ou la même ligne se répète, c'est là la cause racine. Pour les cas non récurrents qui pointent vers une corruption mémoire, lancer une compilation de test sous valgrind ou AddressSanitizer donne des pistes.

Si votre serveur ne reste pas stable, je peux vous aider à analyser les core dumps et à corriger les crashs récurrents au niveau du code source. Contactez-moi pour le débogage du game core Metin2 et la stabilité de votre serveur — contactez-moi.

Bu kategorideki tüm yazılar →

Devamı için