2012-10-05 21 views
37

Es fällt mir schwer zu verstehen, warum Sie asprintf benötigen würden. Hier im Handbuch sagt esWarum Asprintf verwenden?

Die Funktionen asprintf() und vasprintf() sind Analoga von sprintf (3) und vsprintf (3), mit der Ausnahme, dass sie einen String groß genug zu halten die Ausgabe einschließlich zuteil das abschließende Null-Byte, und geben Sie einen Zeiger über das erste Argument zurück. Dieser Zeiger sollte an frei (3) übergeben werden, um den zugewiesenen Speicher freizugeben, wenn es nicht mehr benötigt wird.

So, hier ist das Beispiel, das ich zu verstehen, ich versuche:

asprintf(&buffer, "/bin/echo %s is cool", getenv("USER")); 

Was ist der Unterschied, wenn der Puffer einen String groß genug ordnet vs sagen char * = (string)

+5

'asprintf()' und 'vasprintf()' sind GNU-Erweiterungen. Hinzugefügt das GNU-Tag. – alk

+3

Hmm, ich frage mich, ob der Fragesteller hier die Übungen macht: http://exploit-exercises.com/nebula/level02? – jordanpg

+1

Ein sehr guter Blogbeitrag zu diesem Thema findet sich hier: [Speicherverwaltung-in-c-und-auto] (http://insanecoding.blogspot.de/2014/06/memory-management-in-c- und-auto.html) ... übrigens. der komplette Blog ist lohnend zu lesen – antibus

Antwort

82

Wenn Sie sprintf() oder vsprintf() verwenden, müssen Sie zunächst einen Puffer zuweisen, und Sie müssen sicherstellen, dass der Puffer groß genug ist, um die Sprintf-Schreibvorgänge zu enthalten. Andernfalls überschreibt sprintf den Speicher, der hinter dem Ende des Puffers liegt.

char* x = malloc(5 * sizeof(char)); 
sprintf(x,"%s%s%s", "12", "34", "56"); // writes "123456" +null but overruns the buffer 

... schreibt die ‚6‘ und das abschließende null über das Ende des Raumes zu x zugeordnet, entweder eine andere Variable oder verursacht einen Segmentation Fault korrumpieren.

Wenn Sie Glück haben, wird es auf Speicher zwischen zugewiesenen Blöcken trampeln, und wird nicht schaden - dieses Mal. Dies führt zu zeitweiligen Fehlern - die schwierigste Art zu diagnostizieren. Es ist gut, ein Tool wie ElectricFence zu verwenden, das verursacht, dass Überläufe fehlschlagen - schnell.

Ein nicht böswilliger Benutzer, der eine überlange Eingabe bereitstellt, kann dazu führen, dass sich das Programm auf unerwartete Weise verhält. Ein böswilliger Benutzer könnte dies ausnutzen, um seinen eigenen ausführbaren Code in das System zu bekommen.

Ein Schutz dagegen ist, snprintf() zu verwenden, der die Zeichenfolge auf die maximale Länge abschneidet, die Sie bereitstellen.

char *x = malloc(5 * sizeof(char)); 
int size = snprintf(x, 5, "%s%s%s", "12", "34", "56"); // writes "1234" + null 

Der Rückgabewert size ist die Länge, dass würde geschrieben gewesen, wenn Platz vorhanden ist - nicht die abschließende Null- einschließlich.

In diesem Fall, wenn size größer als oder gleich 5 ist, dann wissen Sie, dass Kürzung aufgetreten ist - und wenn Sie nicht abgeschnitten werden wollten, können Sie eine neue Zeichenfolge zuweisen und snprintf() erneut versuchen.

char *x = malloc(BUF_LEN * sizeof(char)); 
int size = snprintf(x, 5, "%s%s%s", "12", "34", "56"); 
if(size >= BUF_LEN) { 
    realloc(&x,(size + 1) * sizeof(char)); 
    snprintf(x, 5, "%s%s%s", "12", "34", "56"); 
} 

(das ist ein ziemlich naive Algorithmus, aber es zeigt den Punkt)

asprintf() tut dies in einem Schritt für Sie - berechnet die Länge der Zeichenfolge, ordnet diese Menge an Speicher und schreibt die Zeichenfolge hinein.

char *x; 
int size = asprintf(&x, "%s%s%s", "12", "34", "56"); 

In allen Fällen, wenn Sie mit x beendet haben, müssen Sie es lösen, oder Sie lecken Speicher:

free(x); 

asprintf() ist eine implizite malloc(), so dass Sie es funktionierte zu überprüfen, genau wie Sie mit malloc() oder einem anderen System aufrufen würden.

if(size == -1) { 
    /* deal with error in some way */ 
} 

Beachten Sie, dass asprintf() Teil der GNU und BSD-Erweiterungen ist zu libc - man kann nicht sicher sein, es in jeder C-Umgebung zur Verfügung stehen wird. sprintf() und snprintf() sind Teil der POSIX und C99 Standards.

+0

Vielen Dank für diese Antwort. Habe eine Menge Dinge gelöscht –

+1

Außerdem solltest du das Ergebnis von 'malloc' (und Familie) nicht in C werfen (http://www.stackoverflow.com/questions/605845/do-i-cast-the- Ergebnis-von-malloc). –

+0

Sehr verspätet habe ich @ user694733's Punkte behoben. – slim

18

Die Vorteil ist Sicherheit.

Zahlreiche Programme haben das Ausnutzen von Systemausfällen ermöglicht, indem vom Programmierer bereitgestellte Puffer überfüllt wurden, wenn sie mit Benutzerdaten gefüllt wurden.

Mit asprintf reservieren Sie den Puffer für Sie garantiert, dass nicht passieren kann.

immer Sie müssen überprüfen Sie den Rückgabewert von asprintf, um sicherzustellen, dass die Zuordnungsspeicher tatsächlich gelungen. Siehe http://blogs.23.nu/ilja/2006/10/antville-12995/

+0

Ich erinnere mich daran, auf diesem vage zu lesen. Ist dies der einzige Grund, asprintf zu verwenden? –

+2

@BrandonLing gut, in vielen Fällen würde es auch Ihren Code kürzer machen! – Alnitak

+4

@BrandonLing: Es entfernt Code Duplikation - viele Male, wenn Sie eine nie abschneiden wollen 'sprintf' Sie gezwungen sind, Ihre eigene Funktion zu schreiben, die dies trotzdem tut, so haben Sie jetzt alles in einem einzigen, fertig verpackt funktionierte auf Kosten der Portabilität. –