Dlaczego Warto Używać Asprintf?

Ciężko mi zrozumieć, dlaczego potrzebujesz asprintf. Tutaj w instrukcji jest napisane

Funkcje asprintf() i vasprintf() są analogami sprintf (3) i vsprintf (3), z tą różnicą, że przydzielają ciąg znaków wystarczająco duży, aby wyjście zawierające kończący bajt null i zwracające wskaźnik do niego poprzez pierwszy argument. Wskaźnik ten należy przekazać do free(3) zwalnia przydzieloną przestrzeń dyskową, gdy nie jest już potrzebna.

Więc tutaj jest to przykład, który staram się zrozumieć:

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

Jaka jest różnica, jeśli bufor przydziela łańcuch wystarczająco duży, a nie mówi char * = (string)

Author: Michael Gaskill, 2012-10-05

2 answers

Jeśli używasz sprintf() lub vsprintf (), musisz najpierw przydzielić bufor i upewnić się, że bufor jest wystarczająco duży, aby zawierał to, co pisze sprintf. W przeciwnym razie sprintf z radością nadpisze każdą 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

... zapisuje " 6 " i zakończenie null poza końcem przestrzeni przydzielonej x, albo uszkadzając jakąś inną zmienną, albo powodując błąd segmentacji.

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

Nie-złośliwy użytkownik, który zapewnia zbyt długie wejście, może spowodować, że program zachowa się w nieoczekiwany sposób. Złośliwy użytkownik może wykorzystać to jako sposób na wprowadzenie własnego kodu wykonywalnego do systemu.

Jedną z osłon przed tym jest użycie snprintf(), które obcina ciąg do maksymalnej długości, którą podasz.

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

Wartość zwracana size jest długością, jaką zostałaby zapisana, gdyby spacja była dostępna -- nie wliczając kończącego null .

W tym przypadku, jeśli size jest większe lub równe 5, to wiesz, że doszło do okrojenia - i jeśli nie chcesz okrojenia, możesz przydzielić nowy łańcuch i spróbować ponownie 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 dość naiwny algorytm, ale ilustruje punkt)

asprintf() robi to w jednym kroku - oblicza długość łańcucha, przydziela tę ilość pamięci i zapisuje do niego łańcuch.

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

We wszystkich przypadkach, gdy skończysz z x musisz go zwolnić, albo wyciekniesz pamięć:

free(x);

asprintf() jest niejawnym malloc(), więc musisz sprawdzić, czy działa, tak jak z malloc() lub jakimkolwiek innym wywołaniem systemowym.

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

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

 89
Author: slim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-30 12:49:48

Korzyścią jest bezpieczeństwo.

Liczne programy pozwoliły na exploity systemowe, ponieważ bufory dostarczane przez programistów były przepełnione, gdy były wypełnione danymi dostarczanymi przez użytkownika.

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

Jednak musisz sprawdzić wartość zwracaną asprintf, aby upewnić się, że alokacja pamięci rzeczywiście się powiodła. Zobacz http://blogs.23.nu/ilja/2006/10/antville-12995/

 19
Author: Alnitak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-05 13:19:27