2015-10-01 7 views
7

ich eine Menge von String-Funktionen wie Strncpy mit, strncat, sprintf usw. in meinem Code. Ich weiß, dass es bessere Alternativen zu diesen gibt, aber ich wurde ein altes Projekt übergeben, wo diese Funktionen verwendet wurden, also muss ich bei ihnen bleiben für Kompatibilität und Konsistenz. Mein Supervisor ist sehr pingelig in Bezug auf Fehlerprüfung und Robustheit und besteht darauf, dass ich jedes Mal, wenn ich diese Funktionen nutze, nach Pufferüberlaufverletzungen suche. Dies hat eine Menge von if-else-Anweisungen in meinem Code erzeugt, die nicht hübsch aussehen. Meine Frage ist, ist es wirklich notwendig, jedes Mal, wenn ich eine dieser Funktionen anrufe, nach einem Überlauf zu suchen? Selbst wenn ich weiß, dass ein Pufferüberlauf möglicherweise nicht auftreten kann, z. wenn eine ganze Zahl in einem String-Speicherung mit der Funktion sprintfString Fehlerprüfung

sprintf(buf,"%d",someInteger);

Ich weiß, dass die maximale Länge eines unsigned integer auf einem 64-Bit-System 20 Ziffern lang sein kann. buf auf der anderen Seite ist weit über 20 Zeichen lang. Soll ich in diesem Fall noch auf Pufferüberlauf prüfen?

+0

Vielleicht bekomme ich die Frage nicht, aber haben Sie darüber nachgedacht, 'snprintf'-ähnliche Funktionen zu verwenden? Sie können die Pufferüberlaufprüfung für Sie durchführen. –

+0

Selbst mit 'snprintf' würde ich immer noch überprüfen müssen, ob die Quellzeichenfolge größer als das Ziel ist, und mit einem Fehlercode zurückkehren, wenn das wahr ist. – wahab

+0

Meiner Meinung nach können Sie wegkommen, ohne in dieser Situation nach einem Überlauf zu suchen. Ganzzahlige Überläufe sind nur dann der Fall, wenn Sie diese Ganzzahl für die Speicherzuweisung und die Offset-Ermittlung verwenden. Aber ich bin kein Experte auf diesem Gebiet! – puelo

Antwort

1

Ich denke, der Weg zu gehen ist mit Ausnahmen. Ausnahmen sind sehr nützlich, wenn Sie den normalen Steuerfluss eines Programms und Fehlerprüfung entkoppeln müssen.

Sie können einen Wrapper für jede Zeichenfolge Funktion erstellen, in der Sie die Fehlerprüfung durchführen und eine Ausnahme auslösen, wenn ein Pufferüberlauf auftreten würde.

Dann können Sie in Ihrem Client-Code einfach Ihre Wrapper innerhalb eines try Blocks aufrufen und dann nach Exceptions suchen und Fehlercodes innerhalb des catch Blocks zurücksenden.

Beispielcode (nicht getestet):

int sprintf_wrapper(char *buffer, int buffer_size, const char *format, ...) 
{ 
    if(/* check for buffer overflow */) 
     throw my_buffer_exception; 

    va_list arg_ptr; 
    va_start(arg_ptr, format); 
    int ret = sprintf(buffer, , format, arg_ptr); 
    va_end(arg_ptr); 
    return ret; 
} 

Error foo() 
{ 
    //... 
    try{ 
     sprintf_wrapper(buf1, 100, "%d", i1); 
     sprintf_wrapper(buf2, 100, "%d", i2); 
     sprintf_wrapper(buf3, 100, "%d", i3); 
    } 
    catch(my_buffer_exception&) 
    { 
     return err_code; 
    } 
} 
+0

Was passiert, wenn diese Funktionen nicht zusammen, sondern an verschiedenen Stellen im Code aufgerufen werden? – wahab

+0

@wahab In gewisser Weise können Sie denken, innerhalb des 'try' Blocks diejenigen Funktionen zu gruppieren, die einige * String-Funktionen * aufrufen. Alles hängt davon ab, auf welcher Ebene Sie die Benachrichtigung erhalten, dass ein Pufferüberlauf aufgetreten ist. –

1

Vielleicht schreiben Sie einen Testfall, den Sie aufrufen können, um einfach den Puffer zu testen, um Code-Duplikation und Hässlichkeit zu reduzieren.

Sie könnten die if/else-Anweisungen in eine Methode einer anderen Klasse abstrahieren und dann den erwarteten Puffer und die Länge übergeben.

Von Natur aus sind diese Puffer sehr anfällig für Überschreibungen, also seien Sie vorsichtig, wann immer Sie Eingaben von einem Benutzer/einer externen Quelle erhalten. Sie könnten auch versuchen, eine Zeichenfolgenlänge zu erhalten (strlen), oder selbst nach dem Zeichenkettenzeichen/0 suchen und dieses mit der Puffergröße vergleichen. Wenn Sie für das Zeichen/0 eine Schleife ausführen und es nicht vorhanden ist, gelangen Sie in eine Endlosschleife, wenn Sie die maximale Größe Ihrer Schleife nicht auf die erwartete Puffergröße beschränken. Überprüfen Sie dies auch. Eine andere Möglichkeit ist, Code zu refaktorieren, so dass jedes Mal, wenn diese Methoden verwendet werden, diese durch eine sichere Version der Länge ersetzt werden, die Sie schreiben, wo sie eine Methode mit diesen bereits vorhandenen Protokollen aufruft (aber den Puffer übergeben muss) Größe dazu). Dies ist möglicherweise bei einigen Projekten nicht möglich, da die Komplexität des Komponententests sehr schwierig sein kann.

1

Lassen Sie mich zunächst Ihren letzten Absatz Adresse: Sie Code schreiben, im Gegensatz zu einmal, wie lange wird es gepflegt und genutzt werden. Raten Sie, wie lange Sie denken, dass Ihr Code in Gebrauch ist, und multiplizieren Sie das dann mit 10-20, um herauszufinden, wie lange es tatsächlich in Verwendung sein wird. Am Ende dieses Fensters ist es sehr wahrscheinlich, dass eine Ganzzahl viel größer sein kann und einen Puffer überläuft, also müssen Sie die Pufferprüfung durchführen.

Vorausgesetzt, dass Sie ein paar Optionen:

  • Verwenden Sie die „n“ Reihe von Funktionen wie snprintf Pufferüberlauf zu verhindern, und die Benutzer zu sagen, dass es nicht definiert, was, wenn der Puffer-Überlauf passieren wird.

  • Betrachten Sie es als fatal und entweder abort() oder werfen Sie eine nicht abgefangene Ausnahme, wenn eine Längenverletzung auftritt.

  • Versuchen Sie, den Benutzer zu benachrichtigen, dass ein Problem vorliegt, und brechen Sie den Vorgang entweder ab oder versuchen Sie, dass der Benutzer Eingaben ändert und es erneut versucht.

Die ersten beiden Ansätze sind definitiv einfacher zu implementieren und warten, weil Sie müssen keine Sorgen über die richtigen Informationen an den Benutzer in einer angemessenen Art und Weise zu bekommen. In jedem Fall könnten Sie höchstwahrscheinlich in eine Funktion eingreifen, wie sie in anderen Antworten vorgeschlagen wird.

lassen Sie mich schließlich sagen, da Sie diese Frage C getaggt ++ und nicht C, denken lange und hart über langsam Ihre Codebasis C Migration ++ (weil Ihr Code-Basis ist C jetzt) ​​und nutzen Sie die C++ Einrichtungen, die dann entfernen Sie die Notwendigkeit für diese Pufferüberprüfungen völlig, da es automatisch für Sie geschieht.

Verwandte Themen