dimanche 12 février 2012

Debug

Je viens de passer une semaine à débugger. Dans une codebase de 1.5 millions de lignes, un serveur qui corrompt les données, au bout d'un moment, lorsque deux clients y sont connectés et font suffisamment de requêtes.

Ce cas de figure est le pire qui se présente: mes tests unitaires passent, mes tests simples passent, mais mes tests pour stresser le système foirent en beauté, mais de manière suffisamment aléatoire pour que je ne puisse pas arrêter le débuggeur au moment où le problème surgit. Je ne peux qu'ajouter de plus en plus de lignes de logs au moment où le problème survient, en espérant enfin comprendre pourquoi.

De jour en jour, j'ai réussi à cerner le problème: en détectant la corruption de plus en plus près de sa cause, j'ai réussi à m'approcher suffisamment pour voir exactement le cheminement de l'exécution, et trouver le coupable.

Comme beaucoup de bugs de ce genre, c'était tout bête, planqué dans une vieille partie de code.

En voici le pseudocode:


template<typename T>
size_t hash(T input)
{
static int buffer[4];
calculate_hash((char *)&input, sizeof(input), buffer);
return *((size_t *)buffer);
}

L'on créé un buffer de travail, l'on appelle la fonction calculate_hash en lui passant l'entrée et le buffer de travail, et l'on retourne le début du buffer.

Dans le principe, cela marche très bien. Sauf que regardez d'un peu plus près le mot-clé "static". Le développeur était un peu endormi ce jour là, et l'a mis par erreur. Dans un programme non concurrent, comme par exemple un test unitaire, ça n'a pas beaucoup de conséquences. Peut-être rend-il le code un peu moins efficace, puisque sinon l'on travaillerait sur la pile, laquelle a de fortes chances d'être dans les caches du processeur. Par contre, dans un programme concurrent, c'est la catastrophe: si deux threads appellent la fonction au même moment, le buffer sera partagé, et les résultats imprédictibles. En l’occurrence, mes tables de hachage se retrouvaient à me renvoyer, une fois de temps en temps, une valeur incorrecte, quand le programme était très occupé.

Mot-clé retiré. Tout fonctionne.

Aucun commentaire: