Autor Thema: Arbeiten mit Strings in C  (Gelesen 12417 mal)

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« am: 07. March 2011, 23:03 »
char *fdisk_string = "fdisk ";
strcat(fdisk_string, install_device);
Keine gute Idee. Oder was meinst du, welcher Speicher da für den zusammengesetzten String benutzt wird...?
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

sfan

  • Beiträge: 94
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 08. March 2011, 16:25 »
char *fdisk_string = "fdisk ";
strcat(fdisk_string, install_device);
Keine gute Idee. Oder was meinst du, welcher Speicher da für den zusammengesetzten String benutzt wird...?

Mein Vorschlag wäre:
char* fdisk_str;
fdisk_str = malloc(20); // müsste reichen
sprintf("fdisk %s", install_device);


Sfan

oern

  • Beiträge: 44
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 08. March 2011, 17:13 »

Mein Vorschlag wäre:
char* fdisk_str;
fdisk_str = malloc(20); // müsste reichen
sprintf("fdisk %s", install_device);

"Müsste reichen" würde ich auf keinen Fall sagen, ich denke eher das:

fdisk_str = malloc(strlen("fdisk ") + strlen(install_device) + 1));

system() führt keinen Shell-Befehl aus, sondern ein Programm. Wie die FIXME-Kommentare zeigen, sollte sich das aber ändern.

taljeth's Einwand, welcher Speicher denn benutzt wird ist natürlich absolut berechtigt. Ich glaube, ich hatte da schon mal Probleme mit.

Gruß,
oern

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 08. March 2011, 22:35 »
fdisk_str = malloc(20); // müsste reichen
sprintf("fdisk %s", install_device);
Eigentlich hätte ich erwartet, dass heutzutage bekannt ist, dass Buffer Overflows gefährlich sind...
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

sfan

  • Beiträge: 94
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 09. March 2011, 07:24 »
fdisk_str = malloc(20); // müsste reichen
sprintf("fdisk %s", install_device);
Eigentlich hätte ich erwartet, dass heutzutage bekannt ist, dass Buffer Overflows gefährlich sind...


Wenn ich es mir so recht überlege ist 20 wenig....
system() führt keinen Shell-Befehl aus, sondern ein Programm. Wie die FIXME-Kommentare zeigen, sollte sich das aber ändern.
Dann könnte ich das ja fixen.


Sfan

DerHartmut

  • Beiträge: 236
    • Profil anzeigen
    • Mein Blog
Gespeichert
« Antwort #5 am: 09. March 2011, 08:50 »
Diese Diskussion sollte man in einen eigenen Thread verschieben, sonst wird's schnell unübersichtlich.
$_="krJhruaesrltre c a cnp,ohet";$_.=$1,print$2while s/(..)(.)//;
Nutze die Macht, nutze Perl ;-)

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 09. March 2011, 09:40 »
Ja, ich hab es mal ausgelagert.

fdisk_str = malloc(20); // müsste reichen
sprintf("fdisk %s", install_device);
Eigentlich hätte ich erwartet, dass heutzutage bekannt ist, dass Buffer Overflows gefährlich sind...


Wenn ich es mir so recht überlege ist 20 wenig....
Ob 20, 42 oder 1337 ist völlig egal, das Problem steckt im "// müsste reichen". Das ist keine Annahme, die du machen kannst. Wenn es eine konstante Länge ist und du nicht weißt, wie lange der Quellstring ist, ist es falsch und verursacht im allgemeinen Fall einen Buffer Overflow.

sprintf sollte man deswegen überhaupt nie benutzen. snprintf ist okay, dann wird der String eben notfalls abgeschnitten. asprintf alloziert einfach genug neuen Speicher, ist aber nicht Standard-C. Genauso sollte man nie Sachen wie gets oder strcpy benutzen. (Ausnahmen bestätigen die Regel, müssen aber gut begründet sein)
« Letzte Änderung: 09. March 2011, 09:42 von taljeth »
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 09. March 2011, 11:12 »
Hallo,


snprintf ist okay, dann wird der String eben notfalls abgeschnitten.
Bei snprintf ist aber der Rückgabewert interessant, der sagt wie lang der String geworden wäre wenn er nicht abgeschnitten werden müsste (oder wie lang der String tatsächlich ist falls der Buffer gereicht hat) so das man zumindest prüfen kann ob der resultierende String gültig ist.

asprintf alloziert einfach genug neuen Speicher, ist aber nicht Standard-C
Schade.


In Anbetracht dessen das diese Pannen selbst in Vorzeigeprojekten passieren, siehe Linux via USB zu kapern, sollte man eigentlich erwarten können das die zugrunde liegende Problematik allen Informatik-Studenten im ersten Semester eingeprügelt wird. Entweder man benutzt eine Sprache die selbstverwaltete Strings hat (z.B. als Klasse in einer OO-Sprache) oder man speichert Strings in schnöden Arrays und muss die Länge immer händisch exakt mitführen.


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 09. March 2011, 11:58 »
asprintf alloziert einfach genug neuen Speicher, ist aber nicht Standard-C
Schade.
Für C1X ist es aber anscheinend vorgesehen. (strdup soll dann übrigens auch endlich mal in die Standardbibliothek, das hab ich auch schon vermisst)
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 09. March 2011, 12:52 »
Geh mal zu einer Embedded-Messe, wo ein großer Aufsteller steht "finde den Bug in folgender C-Funktion". Dann folgt meist eine simple Implementation einer Stringumkehr oder einer RLE-Decodierung. Das Ding funktioniert meistens sogar.

Das Teil strotzt meist vor Fehlern, die üblichen Kandidaten sind:
- malloc() darf NULL zurückgeben
- scanf(), printf() dürfen fehlschlagen
- sscanf() darf ungültig sein, wenn der Formatstring nicht passt
- sprintf() ist ungültig, wenn Quelle und Ziel überlappen
- strcpy und Freunde ohne 'n'
- off-by-one-Fehler (Array ab eins, For-Schleife eins zu groß, ...)
- falsche Variable zurückgegeben (gerne auch die Eingabe)

Das sind böse Dinger. Jeder, der C programmiert, sollte mindestens diese kennen.

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #10 am: 09. March 2011, 13:27 »
Warum sollte man überprüfen ob printf fehlschlägt? Da sehe ich keinen Sinn drin...
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 09. March 2011, 14:14 »
Der Punkt galt nicht nur für scanf() und printf(), sondern auch für deren Freunde. Und bei sprintf() kann das - abhängig vom Kontext - durchaus sinnvoll sein...

sfan

  • Beiträge: 94
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 09. March 2011, 14:32 »
readline() kann auch NULL zurückgeben.
Das kann man so ausschliessen:
eingabe = readline("Geben sie etwas ein [etwas]: ");
if(eingabe == NULL) {
  eingabe = "etwas";
}
if(!strlen(eingabe)) {
  eingabe = "etwas";
}


Sfan

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 09. March 2011, 21:18 »
Hallo,


Geh mal zu einer Embedded-Messe
War ich vor genau einer Woche erst. ;)

wo ein großer Aufsteller steht "finde den Bug in folgender C-Funktion"
Ja, diese Dinger kenne ich ganz gut, meistens ist der Fehler für den geübten C-Coder recht offensichtlich aber manchmal müssen selbst echte Cracks richtig suchen bis man den Fehler findet. Interessant ist das an diesen Ständen meistens irgendwelche Wundertools angeboten werden die solche Fehler automagisch finden sollen, nur wirklich funktionieren tun diese Tools auch nicht weil es einfach ziemlich schwer ist klar zu definieren was nun genau ein Fehler ist und was nicht. Oft bringen diese Tools extrem viele Fehlalarme und finden gleichzeitig die tatsächlichen Fehler trotzdem nicht. :(

In Deiner Liste fehlen noch so lustige Sachen wie das Zurückgeben von Pointern auf lokale Variablen usw.
Das es bei C so enorm viele Stolperfallen gibt liegt einfach daran das C eben doch nur ein besserer und portablerer Assembler ist. ;) Aber man kann sich auch mit Java oder C# genau so effektiv ins eigene Knie schießen nur das dort die Probleme nicht immer so offensichtlich sind.

Aber all diese Punkte lassen sich im wesentlichen auf 2 grundsätzliche Probleme zurückführen: Bereichsüberschreitungen und ungültige Pointer. Wenn man das den jungen Programmierern so beibringen würde das sie ein gutes Gespür dafür entwickeln diese 2 grundsätzlichen Probleme in beliebigen Code zu sehen dann könnte man IMHO einen enormen Beitrag zur allgemeinen Sicherheit von Software beitragen.


Grüße
Erik
Reality is that which, when you stop believing in it, doesn't go away.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #14 am: 09. March 2011, 22:48 »
Manchmal hängt es aber auch an nur einem grundlegendem Problem: Mangelnder Sprachkenntnis.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

bluecode

  • Beiträge: 1 391
    • Profil anzeigen
    • lightOS
Gespeichert
« Antwort #15 am: 10. March 2011, 12:14 »
Aber all diese Punkte lassen sich im wesentlichen auf 2 grundsätzliche Probleme zurückführen: Bereichsüberschreitungen und ungültige Pointer.
Das sind aber Probleme, die man gerade nicht in Java/C# hat: In dem Sinn, dass es manchmal still und heimlich funktioniert und ein andermal nicht und die Auswirkungen irgendwo ganz anders zu spüren sind, zB hatte ich schon einen Bufferoverflow gesehen der netterweise die Schleifenvariable auf 0 setzt und das ganze zu einer Endlosschleife machte; Sondern in Java/C# gibt konsistent Exceptions, deren Auslöser auch lokalisierbar ist.
lightOS
"Überlegen sie mal 'nen Augenblick, dann lösen sich die ganzen Widersprüche auf. Die Wut wird noch größer, aber die intellektuelle Verwirrung lässt nach.", Georg Schramm

 

Einloggen