2012-10-05 10 views
37

Trudno mi zrozumieć, dlaczego potrzebujesz asprintf. Tutaj w instrukcji jest napisaneDlaczego warto korzystać z Asprintf?

asprintf funkcje() i vasprintf() są analogi sprintf (3) i vsprintf (3), z wyjątkiem tego przeznaczyć one ciąg wystarczająco duże, aby pomieścić wyjście w tym kończący bajt zerowy i zwracają do niego wskaźnik za pomocą pierwszego argumentu. Wskaźnik ten należy przekazać do za darmo (3), aby zwolnić przydzielony magazyn, gdy nie jest już potrzebny.

Więc tutaj jest przykładem, że staram się zrozumieć:

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

Jaka jest różnica jeśli bufor przydziela ciąg wystarczająco duży vs mówiąc char * = (String)

+5

'asprintf()' i 'vasprintf()' są rozszerzeniami GNU. Dodano tag GNU. – alk

+3

Hmm, zastanawiam się, czy pytający wykonuje ćwiczenia tutaj: http://exploit-exercises.com/nebula/level02? – jordanpg

+1

Bardzo dobry wpis na blogu na ten temat można znaleźć tutaj: [zarządzanie pamięcią-in-c-and-auto] (http://insanecoding.blogspot.de/2014/06/memory-management-in-c- i-auto.html) ... btw. kompletny blog wart jest przeczytania. – antibus

Odpowiedz

82

Jeśli używasz sprintf() lub vsprintf(), trzeba przydzielić bufor pierwszy, i trzeba mieć pewność, że bufor jest wystarczająco duża, aby pomieścić co sprintf pisze. W przeciwnym razie sprintf z powodzeniem zastąpi pamięć znajdującą się poza końcem bufora.

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

... pisze „6” i kończącą null poza koniec przestrzeni przydzielonej x albo uszkadzając jakąś inną zmienną, lub powodując winy segmentacji.

Jeśli masz szczęście, będzie deptać pamięć pomiędzy przydzielonymi blokami i nie zaszkodzi - tym razem. Prowadzi to do sporadycznych błędów - najtrudniejszej do zdiagnozowania. Dobrze jest użyć narzędzia takiego jak ElectricFence, które powoduje szybkie awarie.

Nieuczciwy użytkownik, który dostarcza zbyt długie dane wejściowe, może spowodować, że program zachowuje się w nieoczekiwany sposób. Złośliwy użytkownik może wykorzystać to jako sposób na uzyskanie własnego kodu wykonywalnego w systemie.

Jednym z zabezpieczających przed tym jest użycie snprintf(), który obcina łańcuch do maksymalnej podanej długości.

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

wartość Zwrot size jest długością że byłby napisany jeśli przestrzeń była dostępna - nie wliczając NULL kończącego.

W tym przypadku, jeśli size jest większa lub równa 5, to wiesz, że wystąpiło obcięcie - a jeśli nie chcesz obcięcia, możesz przydzielić nowy ciąg i ponownie spróbować snprintf().

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"); 
} 

(to jest algorytm dość naiwny, ale ilustruje punkt)

asprintf() robi to w jednym kroku dla Ciebie - oblicza długość łańcucha, przyznaje, że ilość pamięci i zapisuje ciąg w tym.

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

We wszystkich przypadkach, gdy skończysz z x trzeba go zwolnić, lub wyciek pamięci:

free(x); 

asprintf() jest niejawna malloc(), więc trzeba sprawdzić to działało, tak jak z malloc() lub dowolnym innym wywołaniem systemowym.

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

Zauważ, że asprintf() jest częścią rozszerzenia GNU i BSD do libc - nie może być pewien, że będzie dostępny w każdym środowisku C. sprintf() i snprintf() są częścią standardów POSIX i C99.

+0

Dziękuję za tę odpowiedź. Oczyszczone wiele rzeczy –

+1

Ponadto, [nie powinieneś rzutować wyniku 'malloc' (i rodziny) w C] (http://www.stackoverflow.com/questions/605845/do-i-cast-the- result-of-malloc). –

+0

Bardzo późno naprawiłem punkty @ user694733. – slim

18

korzyści to bezpieczeństwo.

Liczne programy pozwoliły na wystąpienie błędów systemowych, ponieważ przepełnione bufory dostarczone przez programistów zostały przepełnione danymi użytkownika.

Posiadanie asprintf alokować bufor dla Ciebie gwarantuje, że nie może się zdarzyć.

Jednak ty musi sprawdzić wartość zwracaną asprintf aby zapewnić, że przydział pamięci faktycznie udało. Zobacz http://blogs.23.nu/ilja/2006/10/antville-12995/

+0

Pamiętam, że czytałem o tym mgliście. Czy to jedyny powód, aby używać asprintf? –

+2

@BrandonLing dobrze, w wielu przypadkach skróciłoby to również Twój kod! – Alnitak

+4

@BrandonLing: Usuwa powielanie kodu - wiele razy, gdy chcesz nigdy nie przycinać 'sprintf', musisz napisać własną funkcję, która to robi, tak więc teraz masz wszystko zapakowane w jedną, gotową wykonał funkcję, kosztem przenoszenia. –

Powiązane problemy