Was war der gefährlichste Programmierfehler, den du in C gemacht hast?

8

Ich bin ein intermediärer C-Programmierer. Wenn Sie einen Codierungsfehler gemacht haben, von dem Sie später erfahren haben, dass dies der gefährlichste / schädlichste für die gesamte Anwendung war, teilen Sie diesen Code oder die Beschreibung bitte mit. Ich möchte das wissen, weil ich in Zukunft auf solche Situationen stoßen kann und ich möchte Ihren Rat haben, solche Fehler zu vermeiden.

    
Manoj Doubts 12.11.2008, 06:56
quelle

26 Antworten

12

Vor ein paar Jahren habe ich einen Anruf von meinem Ex-Kollegen bekommen, der mir von dem Problem erzählt hat, das er mit meinem Code beheben musste, der ein Router für Kreditkartentransaktionen war.

Das Kartennummernpräfix besteht aus einer 6-stelligen BIN (Bank Identification Number) und zusätzlichen wenigen Ziffern, die die Banken nach eigenem Ermessen verwenden, z. Bank hat BIN für Visa Classic-Karte 456789, und 2 zusätzliche Ziffern reservieren, um Unterprodukt anzuzeigen, wie 01 für Schülerkarte, 02 für Co-Branding-Karte mit lokalen Kaufhaus und so weiter. In diesem Fall wird das Kartenpräfix, das im Grunde eine Produktkennung ist, 8 Ziffern lang. Als ich diesen Teil kodierte, entschied ich, dass 9 Ziffern "für alle genug sein sollten". Ich lief 2 Jahre in Ordnung, bis eines Tages eine Bank neue Produkte mit 10-stelligem Präfix herstellte (habe keine Ahnung, warum sie es brauchten). Nicht zu schwer vorzustellen, was passiert ist - Router segufoled, das ganze System angehalten, weil es ohne Transaktion Router nicht funktionieren kann, alle Geldautomaten dieser Bank (eine der größten im Land) wurde für einige Stunden funktionsunfähig, bis das Problem gefunden wurde und behoben.

Ich kann den Code hier nicht zuerst posten, weil ich ihn nicht habe und zweitens ist er vom Unternehmen urheberrechtlich geschützt, aber es ist nicht schwer, sich die strcpy() ohne Überprüfung der Größe des Zielpuffers vorzustellen.

Genau wie man strcpy sagt:

  

Wenn die Zielzeichenfolge von a   strcpy () ist nicht groß genug (das   ist, wenn der Programmierer dumm war   oder faul und konnte die Größe nicht überprüfen   vor dem Kopieren) dann könnte alles Mögliche   geschehen. Überlauf feste Länge   Strings ist ein beliebter Cracker   Technik.

Ich war sehr beschämt. Es war ein guter Zeitpunkt, seppuku zu übernehmen:)

Aber ich habe die Lektion gut gelernt und vergesse nicht (normalerweise :)) die Größe des Zielpuffers zu überprüfen. Ich würde dir nicht empfehlen, es auf die harte Tour zu lernen - entwickle einfach die Gewohnheit, den Zielpuffer vor strcpy() und strcat() zu überprüfen.

Bearbeiten: guter Vorschlag von Healthcarel - benutzen Sie strncpy() anstatt strcpy() . Es fügt keine nachgestellte 0 hinzu, aber ich verwende normalerweise folgendes Makro, um es zu umgehen:

#define STRNCPY(A,B,C) do {strncpy(A,B,C); A[C] = 0; } while (0)

    
qrdl 12.11.2008, 07:31
quelle
24
%Vor%     
Daniel Kreiseder 12.11.2008 07:02
quelle
20
%Vor%

Bearbeiten : Eine weitere Variante desselben Fehlers.

%Vor%     
Fernando Miguélez 12.11.2008 08:16
quelle
12

Es ist eine lange Zeit, aber einige Dinge, die Sie nie vergessen; -).

  • vergiss %code% am Ende eines Strings.
  • Ordnen Sie n Zeichen für eine Zeichenfolge mit n Zeichen zu.
  • Vergessen Sie den Bruch in einer switch-Anweisung.
  • "Creative" -Makro verwenden.
Toon Krijthe 12.11.2008 07:45
quelle
6
%Vor%

Beachten Sie, dass der später hinzugefügte Code nicht in der for-Schleife enthalten ist.

    
Healthcarel 12.11.2008 07:04
quelle
5

Nicht initialisierte Daten.

    
Walter Bright 12.11.2008 13:55
quelle
4

Das gefährlichste, was ich jemals in C gemacht habe, war Code zu schreiben, der mein eigenes Gedächtnis verwaltet. Effektiv bedeutet dies, dass die gefährlichste Sache, die ich jemals in C gemacht habe, C-Code schreiben ist. (Ich habe gehört, dass Sie sich in diesen Tagen umdrehen können. Hüfte Hüfte für geistige Gesundheit. Verwenden Sie diese Ansätze, wann immer es angebracht ist!)

  • Ich schreibe keine Paging-Algorithmen - OS-Geeks tun das für mich.
  • Ich schreibe keine Datenbank-Caching-Schemata - Datenbank-Geeks machen das für mich.
  • Ich baue keine L2-Prozessor-Caches - Hardware-Geeks machen das für mich.

Und ich nicht Speicher verwalten.

Jemand anderes verwaltet meine Erinnerung für mich - jemand, der besser als ich kann, besser testen kann und besser programmiert als ich kann und patch, wenn er kritische Sicherheits-kompromittierende Fehler macht, die nur bemerkt werden 10 Jahre später, weil absolut jeder , der versucht Speicher zuzuweisen, einige Zeit versagt.

    
Patrick McKenzie 12.11.2008 08:26
quelle
4

system () mit einer vom Benutzer angegebenen Zeichenfolge im Argument. Das Gleiche gilt für popen ().

Verwenden Sie stattdessen exec * ().

Natürlich ist das nicht einzigartig für C.

    
Mitch Haile 12.11.2008 14:01
quelle
3

Sie sollten sich mehr Sorgen um kleine Fehler machen. Große / spektakuläre Fehler werden meist in Büchern dokumentiert (mit Gründen, warum sie schlecht sind, alternative Ansätze etc.).

Es sind die kleinen Design / Coding-Fehler, die zu Ihnen kommen, weil sie dazu neigen, sich zu addieren.

Mein Rat ist also, die Bücher zu lesen, die Kernighan geschrieben oder mitverfasst hat ("Die C-Programmiersprache", "Praxis der Programmierung" usw.), weil sie voller Vernunft sind (üblich für erfahrene C-Programmierer) Ratschläge und Listen, die sehr nützlich sind, um sowohl kleine als auch große Fehler zu vermeiden.

Sie listen auch viele potentielle große Fehler auf, damit sie Ihre erste Frage beantworten.

    
Miron Brezuleanu 12.11.2008 08:15
quelle
3

Ich nehme die Definition von gefährlich als "wir können mit diesem Bug versenden und entdecken nur Jahre später, wenn es zu spät ist":

%Vor%

oder

%Vor%

Aber wenn Sie Multiplattform schreiben (nicht auf x86 / x64 beschränkt), ist das auch großartig:

%Vor%

Und wenn Ihr Puffer von einer nicht vertrauenswürdigen Quelle stammt ... im Grunde ist der meiste Code gefährlich.

Aber trotzdem, in C ist es so einfach, sich in den Fuß zu schießen, dass ein Thema über Schussfüße um die Tausende von Seiten gehen könnte.

    
Marco M. 12.11.2008 09:07
quelle
3

Ich stimme Pat Mac hier zu (trotz seiner Ablehnung). Die gefährlichste Sache, die Sie in C tun können, ist einfach, es für etwas Wichtiges zu verwenden.

Zum Beispiel würde eine vernünftige Sprache standardmäßig Array-Grenzen prüfen und Ihr Programm sofort stoppen (eine Exception oder etwas auslösen), wenn Sie versuchen, außerhalb davon zu wandern. Ada macht das. Java macht das. Tonnen anderer Sprachen tun dies. Nicht C. Es gibt ganze Hacking-Industrien, die in der Sprache um diesen Fehler herum gebaut wurden.

Eine persönliche Erfahrung damit. Ich arbeitete mit einer Firma zusammen, die ein Netzwerk von Flugsimulatoren betrieb, die mit reflektierender (geteilter) Speicherhardware verbunden waren. Sie hatten einen ekligen Crash-Bug, den sie nicht aufspüren konnten, also wurden unsere beiden besten Ingenieure dorthin geschickt, um sie aufzuspüren. Es hat zwei Monate gedauert.

Es stellte sich heraus, dass es in einer C-Schleife auf einer der Maschinen einen Fehler nach dem anderen gab. Eine kompetente Sprache hätte die Dinge dort natürlich gestoppt, aber C ließ es los und schrieb ein Stück Daten an der nächsten Stelle über das Ende des Arrays hinaus. Dieser Speicherort wurde zufällig von einem anderen Computer im Netzwerk verwendet, der ihn an einen dritten Computer weitergab, der den (Müll-) Wert als Array-Index verwendete. Da dieses System auch in C codiert war, war es auch egal, dass es weit außerhalb seines Arrays lag und halb zufällige Speicherplätze in seinem Programm platzierte.

Da also die Überprüfung der Array-Grenzen fehlte, verursachte ein einfacher Bug-by-One-Fehler zufällige Abstürze in einem Computer, zwei ganze Hops von der Fehlerquelle entfernt! Kosten für das Unternehmen: 4 Mannmonate der Zeit ihrer besten Ingenieure, plus viel Zeit wurde von anderen Ingenieuren und Supportmitarbeitern ausgegeben, und alle Ausfallzeiten der betreffenden Simulatoren funktionierten nicht richtig.

    
T.E.D. 12.11.2008 15:14
quelle
2

Wenn ein Zeiger zuerst zugewiesen wird, hat er keinen Anhaltspunkt.

Der Zeiger ist "nicht initialisiert"

Eine Dereferenzierungsoperation für einen ungültigen Zeiger ist ein schwerwiegender Laufzeitfehler.

Wenn Sie Glück haben, wird die Dereferenzierungsoperation sofort zum Absturz gebracht oder gestoppt (Java verhält sich so) Weg).

Wenn Sie Pech haben, wird die fehlerhafte Pointer-Dereferenzierung einen zufälligen Bereich von Speicher, etwas die Operation des Programms etwas ändern, damit es etwas falsch geht unbestimmte Zeit später. Jedem Zeiger muss ein Pointe zugewiesen werden, bevor er unterstützt werden kann Dereferenzierungsoperationen.

    
user36834 12.11.2008 08:44
quelle
2

Zwei Dinge kommen mir in den Sinn. Das erste war eine Funktion in eingebettetem C (MCU). Ich habe versucht, einige Einschränkungen für einen Timer-Wert als eine eingegebene Funktion zu haben. also schrieb ich

%Vor%

Mein Ida war, das zu überprüfen:

%Vor%

Aber das ist das Äquivalent oder das Ergebnis

%Vor%

und das Ergebnis endete, dass der if-Test immer wahr war.

Die Sekunde war ein Zeigerfehler. (hier einfach dargestellt)

%Vor%

Dies führt zu einem Verlust von 1 Byte Speicher für jedes Mal, wenn die Funktion get_data() aufgerufen wurde

    
eaanon01 13.11.2008 21:57
quelle
2
%Vor%     
ani625 12.11.2008 09:17
quelle
1

Verwenden Sie nicht beschränkte Zeichenfolgenfunktionen wie strcpy () oder strcmp () anstelle von sicheren Versionen wie strncpy () und strncmp ().

    
Sherm Pendley 12.11.2008 08:01
quelle
1

Die Übergabe der virtuellen Adresse an die DMA-Engine war die schlechteste, nicht unbedingt C-bezogene, aber ich nehme an, dass 99% der DMA-bezogenen Inhalte in C geschrieben sind, also passt es irgendwie zusammen. Dieser kleine Fehler führte zu einer Speicherbeschädigung, die mich 1,5 Monate benötigte.

    
Ilya 12.11.2008 08:12
quelle
1

Schalter Fall ohne Pause.

    
domlao 12.11.2008 11:06
quelle
1

Da ich ein Lisp-Programmierer war, wurde ich benutzt, um schließende geschweifte Klammern einzudrücken, wie in:

%Vor%

und ich trug dies in C-Programmierung:

%Vor%

Dann bekam ich ein gutes Projekt in C, und ein anderer Programmierer musste Änderungen in der Nähe meines Codes vornehmen. Er hat meine schließenden Klammern falsch gelesen und etwas Speicher zu früh freigegeben. Dies verursachte einen äußerst subtilen Fehler, der in der kritischen Zeit stattfand. Als es gefunden wurde, wurde er schlecht gemacht. Aber man könnte sagen, dass es meine Schuld war. Das war kein Spaß, gelinde gesagt.

    
Mike Dunlavey 26.11.2008 16:53
quelle
1

Das Vergessen von Architektur-Constraints und die glückliche Einbettung in den Speicher-Mapping-I / O-Bereich eines Mikrocontrollers. Der magische Rauch wurde vom Prüfstand freigegeben.

    
Mihai Limbășan 26.11.2008 17:19
quelle
1

Ich hatte es mit dynamisch zugewiesenen 2D-Arrays zu tun, und statt freier () 'n Zeilen entschied ich mich, M Spalten zu befreien. Dies war in Ordnung für kleinere Eingänge, wo N == M, aber bei großen Eingängen, ich nur frei () 'd 50% von dem, was ich zugeordnet.

Achselzucken

Lebe und lerne.

    
Nick Presta 08.12.2008 00:30
quelle
1

Dies ist ein berühmtes historisches Beispiel (nicht etwas, das ich gemacht habe), aber

%Vor%

führte zu Explosion und Totalverlust von einer Ariane-V-Rakete .

>     
Crashworks 11.11.2010 06:07
quelle
0

Zu beachten sind Array-Grenzen. Wenn Sie sich außerhalb der Grenzen befinden, können Sie mit etwas Glück den Speicher überschreiben, der für andere Daten verwendet wird.

Ein üblicher Fehler, der damit zusammenhing, war das Aus für eine statische Array-Variable in einer Funktion. Das endete als eine Funktion, die Werte der lokalen Variablen der aufrufenden Funktion änderte. Das war nicht so geradlinig zu debuggen ..

    
Touko 12.11.2008 07:26
quelle
0

Ich erinnere mich an zwei Fehler:

  1. gibt die Adresse einer automatischen Variablen aus einer Funktion zurück, in der sie erstellt wurde;
  2. Kopieren einer Zeichenfolge in einen nicht initialisierten und nicht zugeordneten Zeiger auf char.
ayaz 12.11.2008 11:41
quelle
0
%Vor%

Ich denke C unterstützt String nativ (mit Metroworks codewarrior, vor etwa 8 Jahren).

Ich tat dies für ein endgültiges Projekt von etwa 15.000 Zeilen Code. Ich benutzte diese Bibliothek, um alles zu tun, was mit Strings zu tun hatte (Anhängen, Teilen usw.). Nur damit die TA's kein Bit meiner Aufgabe kompilieren konnten (mit GCC).

Ich habe nicht erfahren, dass Metroworks ihre eigene String-Bibliothek erstellt haben. Ich habe diese Klasse nicht bestanden.

    
UberJumper 12.11.2008 15:27
quelle
0
%Vor%

Das ist, als ich das meinte:

%Vor%

Dies führte zu vielen Stunden Debugging-Problemen, als ich annahm, dass es wie das letzte funktionierte.

    
Claudiu 14.11.2008 07:09
quelle
0

Vergessen, ; am Ende zu setzen.  Überschüssiges } .  Versehentlich ein ,

eingegeben

Dies macht mich stundenlang verrückt zu finden, was mit meinen Codes falsch ist.

    
Ji Ho Jeon 12.02.2016 03:47
quelle

Tags und Links