2009-08-16 4 views
19

Ich Verwendung dieses Musters sah auf eine Zeichenfolge in einigen Code verketten Ich arbeitete an:Ist sprintf (Puffer, "% s [...]", Puffer, [...]) sicher?

sprintf(buffer, "%s <input type='file' name='%s' />\r\n", buffer, id); 
sprintf(buffer, "%s</td>", buffer); 

und ich bin ziemlich sicher, es ist nicht sicher C. ist werden Sie feststellen, dass buffer bemerken ist sowohl die Ausgabe und die erste Eingabe.

Abgesehen von der offensichtlichen Möglichkeit eines Pufferüberlaufes, ich glaube, es gibt keine Garantie dafür gibt, dass Puffer nicht zwischen dem Beginn und dem Ende der Funktion verändert bekommen (dh es gibt keine Garantie, was den Staat Puffer wird während der Ausführung der Funktion sein). Die Signatur von sprintf gibt zusätzlich an, dass die Zielzeichenfolge restrict ed ist.

Ich erinnere mich auch einen Bericht von speculative writing in memcpy, und ich sehe keinen Grund, warum einige C-Bibliothek dasselbe in einem Sprintf tun könnte. In diesem Fall würde es natürlich auf seine Quelle schreiben. Also ist dieses Verhalten sicher?

FYI, ich vorgeschlagen:

char *bufEnd = buffer + strlen(buffer); 
/* sprintf returns the number of f'd and print'd into the s */ 
bufEnd += sprintf(bufEnd, " <input type='file' name='%s' />\r\n", id); 

diese zu ersetzen.

+0

Auch wenn es * sicher * ist (wird nicht abstürzen usw.) Ich kann mir vorstellen, dass es ein anderes Ergebnis als das erwartete ergibt. –

+0

@AndrewMedico Wie ist das? – cat

Antwort

18

Vom glibc sprintf() documentation:

Das Verhalten dieser Funktion ist undefiniert, wenn das Kopieren stattfindet zwischen Objekten, die sich überlappen-für Beispiel, wenn s auch als Argument angegeben wird unter Kontrolle gedruckt werden der '% s'-Konvertierung.

Es kann in einer bestimmten Implementierung sicher sein; aber du konntest nicht darauf zählen, dass es tragbar ist.

Ich bin mir nicht sicher, ob Ihr Vorschlag auch in allen Fällen sicher wäre. Sie könnten immer noch überlappende Puffer sein. Es ist spät und meine Frau buggin mich, aber ich denke, dass Sie immer noch den Fall haben könnten, in dem Sie die ursprüngliche Zeichenfolge erneut in der verketteten Zeichenfolge verwenden und das Nullzeichen überschreiben und so die Sprintf-Implementierung möglicherweise nicht wissen, wo die wiederverwendet wird Zeichenfolge endet.

Sie möchten nur mit einem snprint() zu einem Temp-Puffer, dann strncat() auf den ursprünglichen Puffer.

+1

Okay, wollte nur einen Plausibilitätscheck. [POSIX sagt dasselbe] (http://www.opengroup.org/onlinepubs/9699919799/functions/sprintf.html): > Wenn das Kopieren erfolgt zwischen Objekten, die als Ergebnis eines Aufrufs von sprintf überlappen() oder snprintf(), die Ergebnisse sind nicht definiert. –

+0

Eigentlich überlappe ich Puffer nicht in meinem zweiten - es ist ein streng anderer Puffer. Ich benutze das Original nicht. –

+0

Es sei denn, du siehst etwas, was ich nicht kann, was durchaus möglich ist. –

4

In diesem speziellen Fall ist es funktionieren wird, da die Zeichenfolge in buffer werden die erste Sache, die in buffer (wieder nutzlos) eingeben wird, so sollten Sie strcat() stattdessen mit dem [fast] gleiche erhalten bewirken.

Aber, wenn Sie strcat() mit den Formatierungsmöglichkeiten sprintf() zu kombinieren versuchen, können Sie dies versuchen:

sprintf(&buffer[strlen(buffer)], " <input type='file' name='%s' />\r\n", id);
3

Wenn Sie formatierten Text an das Ende eines Puffers mit printf verketten möchten(), Ich würde empfehlen, dass Sie eine Ganzzahl verwenden, um die Endposition zu verfolgen.

int i = strlen(buffer); 
i += sprintf(&buffer[i], " <input type='file' name='%s' />\r\n", id); 
i += sprintf(&buffer[i], "</td>"); 

oder:

int i = strlen(buffer); 
i += sprintf(&buffer[i], " <input type='file' name='%s' />\r\n", id); 
strcat(&buffer[i], "</td>"); 

Und bevor die Menschen zum Berserker Downvoting dieses („Dies ist nicht sicher Sie den Pufferüberlauf kann!“), Ich bin Adressierung nur eine vernünftige Art und Weise zu bauen eine formatierte Zeichenfolge in C/C++.

+0

Ich denke, Ihr Vorschlag ist funktional der gleiche wie mein vorgeschlagener Ersatz, aber mit etwas anderer Notation. Ich kann sehen, warum einige es bevorzugen würden, es so geschrieben zu sehen. –