Mythos mangelnde Speichersicherheit
Der Mythos der mangelnden Speichersicherheit in "C" hält sich ja hartnäckig und wird durch
Pressemeldungen z.B. auf
heise.de oder golem.de immer wieder aufs Neue unters Volk gebracht,
hauptsächlich um Sprachen wie Rust o.ä. zu bewerben.
Ich werde also hier versuchen damit aufzuräumen.
Ist "C" speichersicher ?
Ganz klare Antwort : per se -
nein !
Erweiterte Antwort : wenn man es haben will -
ja !
Die Sprache "C" enthält keine und die
Basis-Bibliothek "libc" eher wenig Ansätze für Speichersicherheit. Dies muss man als
Anfänger in der "C"-Programmierung möglichst schnell verinnerlichen. Und als Profi sollte
man es sich immer wieder mal ins Gedächtnis rufen. Dieser "Mangel" hilft auf der anderen Seite
dabei kompakte und schnelle Programme zu erzeugen (wofür "C" ja mal entwickelt wurde, Stichwort
"Betriebssystem").
Grundsätzlich muss sich der geneigte C-Programmierer selbst um die Speichersicherheit in seinem
Programm kümmern. Dafür kann er aber auch selbst entscheiden, ob, und wenn ja, wo er etwas
dafür unternehmen muss bzw. will.
Da es viele verschiedene Arten von Speicherunsicherheit gibt, sind auch die Möglichkeiten zur Vermeidung vielfältig und
vielgestaltig. Genauso vielfältig sind auch die Gründe für oder gegen den Einsatz von
Speichersicherheitstechnologien.
Möglichkeiten um die Speichersicherheit zu erhöhen
Grundsätzliche Anmerkungen
Für die Speichersicherheit kann man selbst schon ein paar grundsätzliche Vorkehrungen
treffen.
Externe Tools
Als "externe Tools" bezeichne ich hier Programme, mit denen sich der Quellcode auf mögliche
Fehler und Überraschungen überprüfen lässt. Je nach verwendetem Programm werden
damit syntaktische und semantische Auffälligkeiten gefunden.
- Für die syntaktischen Probleme ist der Compiler zuständig.
Manche sematischen Probleme merkt der Compiler auch schon an, je nach Warnstufe.
- Besser dafür geeignet sind aber Code-Checker. Sie finden zwar auch nicht alles, aber doch
sehr vieles. Ist man im Embedded-Bereich unterwegs und trickst ein wenig beim Programmieren,
sollte man sich aber darüber im Klaren sein, daß auch die Trickserei "angemeckert"
wird.
Im Profibereich sind lint und seine auf verschiedene Einsatzzwecke
spezialisierten Abkömmlinge verbreitet.
- Privat unter Linux setze ich cppcheck ein. Anders als der Name suggeriert, funktioniert das auch
hervorragend für "C". Es lässt sich gut konfigurieren und bringt (manchmal zu)
ausführliche Ergebnisse. Es lohnt sich auf jeden Fall, mal das Manual zu lesen.
Programmerweiterungen
Es gibt drei Möglichkeiten zur Programmerweiterung :
- Compilerflags
- Bibliotheken
- eigener Debug- bzw. Testcode
Die folgenden Sachen habe ich noch nicht intensiv ausprobiert. Sobald ich mich ausführlich(er)
damit beschäftigt habe (ist ja grad gar keine "Dauenrd-am-Strand"-Zeit), werde ich meine
Erfahrungen hier einfließen lassen.
- Compilerflags
Beim gcc sind das die -fsanitize...-Flags.
Durch Setzen dieser Flags werden spezifische Funktionalitäten eingeschaltet, die
Auswirkungen zur Laufzeit des Programms haben.
- Bibliotheken
Hier sei z.B. auf efence verwiesen, mit dem man Problemen bei der Verwendung von dynamisch zugewiesenem
Speicher auf den Grund gehen kann.
- eigener Debug- bzw. Testcode
Für und Wider des Einsatzes für Speichersicherheit
Auch hier muss man wieder unterscheiden :
- externe Tools
- Programmerweiterungen
Die aufgeführten Erkenntnisse entstammen meiner eigenen Programmiererfahrung und sind sicher
nicht vollsrtändig. Aber sie regen vielleicht den einen oder anderen zum Nachdenken an.
Externe Tools
Für den Einsatz externer Tools spricht :
- keine direkte Veränderung des Quellcodes
- kein zusätzlicher, erst beim Übersetzen bzw. Linken hinzugefügter Code
- Hinweise können sehr Code-spezifisch bearbeitet werden
- evtl. werden weitere Fehler gleich mit angezeigt
Dagegen spricht :
- werden nicht oft genug ausgeführt
- werden leicht vergessen
- stehen nicht zur Verfügung
- liefern unverständliche Ergebnisse
Programmerweiterungen
Für Programmerweiterungen spricht :
- selbst implementiert können sie sehr spezifisch eingesetzt werden
- vom Compiler erzeugt treffen sie (normalerweise) alle verwundbaren Stellen
- sind leicht ein- und ausschaltbar
- je nach Herkunft gut optimiert
Dagegen spricht :
- zusätzlicher Programmieraufwand
- Verwendung muss unbedingt dokumentiert werden
- bei externen Quellen muss man sich auf deren Fehlerfreiheit verlassen
- das ausfühbare Programm wird größer
- das ausfühbare Programm wird langsamer
- automatisch erzeugt landen sie auch an Stellen, wo sie eigentlich unnötig sind
Fazit
Speichersicherheit beim Programmieren mit "C" ist kein Hexenwerk. Aber es gibt sie auch nicht umsonst. Sie
erfordert Wissen und Aufwand.
Dieses Wissen kann, sollte und eigentlich muss man sich erarbeiten. Z.B. ist eine IDE, die einem "memory
leaks" anzeigt, dabei sehr hilfreich. Der GNU Debugger GDB erfüllt diese Aufgagen ebenfalls, wenn auch auf komplett andere Weise, sehr gut.
Dafür erhält man, so man es will und den Aufwand nicht scheut, kompakte und schnelle
Programme.
© Uwe Jantzen 28.04.24