Erkennen bestimmter Funktionsaufrufe in Komponententests

8

Ich möchte herausfinden können, ob meine Funktion (oder irgendeine andere Funktion, die sie aufruft) am Ende einige spezifische Funktionen (z. B. malloc und free ) in meinen Unit-Tests aufruft: einige kleine Teile von Meine Software hat harte Echtzeitanforderungen, und ich möchte sicherstellen, dass niemand etwas hinzufügt, das zufällig eine Zuweisung in diesen Funktionen auslösen würde (und von meiner CI-Pipeline automatisch überprüft wird).

Ich weiß, dass ich einfach einen Haltepunkt auf gdb setzen kann, aber im Idealfall möchte ich etwas wie:

machen %Vor%

Idealerweise würde der Test auf eine nicht allzu schmutzige Art und Weise fehlschlagen (zB nicht std::abort ), wenn zu irgendeinem Zeitpunkt malloc zwischen den beiden Überprüfungen aufgerufen wird.

Idealerweise würde dies auf jedem System laufen, aber ich kann mit etwas leben, das es nur unter Linux tut. Ist das irgendwie möglich? Vielleicht durch einen LD_PRELOAD-Hack, der malloc ersetzen würde, aber ich würde das nicht für all die Funktionen tun müssen, an denen ich interessiert bin.

    
Jean-Michaël Celerier 31.12.2017, 17:56
quelle

4 Antworten

3

Unit-Tests rufen Funktionen auf, die sie testen. Sie möchten wissen, ob eine von einem Komponententest aufgerufene Funktion F schließlich malloc (oder new oder ...) aufrufen kann. Es scheint so, als ob Sie wirklich einen Call-Graph für Ihr gesamtes System erstellen möchten und dann nach den kritischen Funktionen fragen, ob F malloc usw. in der Anrufgrafik erreichen kann. Dies ist ziemlich einfach zu berechnen, sobald Sie das Anrufdiagramm haben.

Das Aufrufdiagramm ist nicht so einfach. Entdecken, dass Modul A Modul B direkt anspricht, ist "technisch einfach", wenn Sie ein echtes Sprach-Frontend haben, das die Namensauflösung unterstützt. Herauszufinden, was A indirekt anruft, ist nicht einfach; Sie benötigen eine (Funktionszeiger) -Punkte-Analyse und diese sind schwer. Und natürlich haben Sie sich entschieden, ob Sie in die Bibliothek einsteigen wollen (z. B. std: :) oder nicht.

Ihre Call-Graph-Anforderungen müssen konservativ sein (damit Sie keine potenziellen Aufrufe verpassen) und ziemlich präzise (damit Sie nicht in falschen positiven Ergebnissen ertrinken) angesichts von Funktionszeigern und Methodenaufrufen.

Diese Doxygen-Unterstützung behauptet, Aufrufgraphen zu erstellen: Ссылка Ich weiß nicht, ob es indirekte / Methoden handhabt Anrufe oder wie genau es ist; Ich bin nicht sehr vertraut damit und die Dokumentation scheint dünn. Doxygen hatte in der Vergangenheit keinen guten Ruf, um die Indirektion gut zu handhaben oder präzise zu sein, aber frühere Versionen basierten nicht auf Clang. Es gibt einige weitere Diskussionen darüber, die im kleinen Maßstab in Ссылка

angewendet wurden >

Ihre Frage ist mit c / c ++ getaggt, scheint aber C ++ zu sein. Für C, unser DMS Software Reengineering Toolkit mit seiner generischen Unterstützung für Flow-Analyse und Call-Graph-Generierung, gekoppelt mit DMS C Front End , wurde für analysieren C-Systeme von etwa 16 Millionen Zeilen / 50.000 Funktionen mit indirekten Calls , um konservativ korrekte Call-Graphen zu erstellen.

Wir haben nicht speziell versucht, C ++ - Aufrufgraphen für große Systeme zu erstellen, aber die gleiche generische DMS-Flussanalyse und Aufrufgraphengenerierung wäre "technisch unkompliziert" mit DMS C ++ Front End . Wenn Sie eine statische Analyse erstellen, die korrekt und maßstabsgetreu arbeitet, ist nichts trivial.

    
Ira Baxter 01.01.2018 08:48
quelle
1

Wenn Sie Bibliotheken verwenden, die malloc aufrufen, sollten Sie sich den Joint Strike Fighter ansehen C ++ Codierungsstandards . Es ist ein Kodierungsstil, der auf unternehmenskritische Software ausgerichtet ist. Ein Vorschlag wäre, Ihre eigenen Zuordner zu schreiben. Ein anderer Vorschlag ist, etwas wie jemalloc zu verwenden, das Statistiken hat, aber viel unberechenbarer ist, da es auf Leistung ausgerichtet ist.

Was Sie wollen, ist eine spöttische Bibliothek mit Spionagefähigkeiten. Wie das für jedes Framework funktioniert, wird variieren, aber hier ist ein Beispiel mit Google:

%Vor%

WARNUNG: Code wurde nicht von Compiler-Händen berührt. Aber Sie bekommen die Idee.

    
OwO 31.12.2017 21:21
quelle
1

Dies ist keine vollständige Antwort, aber Sie können versuchen, Valgrind zu verwenden, um Zuordnungen und Freigaben zu zählen. Der voreingestellte Valgrind-Tool-memcheck zählt standardmäßig die Anzahl der Allocs und gibt den resultierenden Bericht frei und druckt ihn in HEAP SUMMARY , hier ist eine Beispielausgabe:

%Vor%

Sie können einen weiteren Test hinzufügen, der nichts tut, um die Baseline-Zuordnungsnummer zu zählen:

%Vor%

Jetzt können Sie einen echten Test durchführen und die Anzahl der Zuweisungen mit dem Basistest vergleichen. Wenn sie nicht gleich sind, wurden in Ihrem getesteten Code einige Zuweisungen vorgenommen. Sie können diese Tatsache protokollieren oder signalisieren, was auch immer Sie wollen.

    
ks1322 05.01.2018 19:01
quelle
1

Wenn Sie die GNU C-Bibliothek verwenden, können Sie mit den Funktionen _malloc_hook () und asly eine benutzerdefinierte Funktion aufrufen, die immer dann aufgerufen wird, wenn eine der Funktionen der malloc -Familie verwendet wird.

Eine solche süchtig machende Funktion könnte den Aufruf-Trace analysieren (mit backtrace() ), um zu ermitteln, ob malloc in dieser Aufrufkette erlaubt war oder nicht, und Nachrichten über den Täter auszudrucken, falls nicht.

    
tofro 13.01.2018 20:49
quelle