Fragen? Antworten! Siehe auch: Alternativlos
#include <string.h> int main() { char buf[10]; memcpy(buf,"fnord",6); // ok memcpy(buf,"fnordfnord",11); // not ok }Wieso heult der Compiler da nicht? Weil der Compiler nur die Typen kontrolliert, und die sind hier OK.
Es gab da jetzt mehrere Ansätze, wie man dieses Problem lösen kann. Einer davon ist der hier:
$ gcc -O -o t t.c -D_FORTIFY_SOURCE=1 $ ./t *** buffer overflow detected ***: ./t terminatedDas hat mehrere Nachteile. Es funktioniert nur mit -O oder stärkerem Optimizer. Es funktioniert nur auf einige eingebaute Funktionen. Es funktioniert nur, wenn das Ziel ein Buffer und kein Pointer ist (weil das über Makros implementiert ist, die sizeof() benutzen). Und es fügt zusätzlichen Code ein, der das Programm langsamer machen wird.
Hier ist die neue Lösung mit den oben beschriebenen Attributen:
#includeWenn wir das mit dem neuen gcc kompilieren, auch ohne Optimizer, gibt es diese Warnung (auch wenn gar keine Warnungen angeschaltet wurden!):__attribute__((access(read_only,2,3), access(write_only,1,3))) void* memcpy2(void* dest, const void* src, size_t len) { return memcpy(dest,src,len); } int main() { char buf[10]; memcpy2(buf,"fnord",6); // ok memcpy2(buf,"fnordfnord",11); // should reject or at least warn }
t.c: In function ‘main’: t.c:11:3: warning: ‘memcpy2’ writing 11 bytes into a region of size 10 overflows the destination [-Wstringop-overflow=] 11 | memcpy2(buf,"fnordfnord",11); // should reject or at least warn | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ t.c:4:7: note: in a call to function ‘memcpy2’ declared with attribute ‘write_only (1, 3)’ 4 | void* memcpy2(void* dest, const void* src, size_t len) {Auch diese Lösung hat Nachteile. Auch sie funktioniert nur, wenn der Compiler die Größe des Zielbuffers kennt, und die Länge der Quelle zur Compilezeit feststeht. Auf der anderen Seite kann man durch Inlining den Kontext der für den Compiler zur Compilezeit sichtbaren Konstanten erweitern, es erzeugt keine Laufzeitkosten, funktioniert auch ohne Optimizer und man kann seine eigenen Funktionen annotieren, um diese Diagnostik im Compiler freizuschalten. Das ist schonmal ein guter Schritt nach vorne, insbesondere da Microsoft vergleichbare Funktionalität seit Jahrzehnten bietet. Die verwendet außer Microsoft selbst kaum jemand, weil die Windows-Coder alle doof sind. Das wäre jetzt die Gelegenheit für die Linux-Gemeinde, es denen mal so richtig zu zeigen!!1!