Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ANS] SO2 2023, reimpl fprintf, nessuna risposta corretta? #41

Open
interestingmaneuver opened this issue May 31, 2024 · 1 comment
Open
Labels
help wanted Extra attention is needed

Comments

@interestingmaneuver
Copy link
Contributor

Argomento:
SO2 2023

Domanda:
Si supponga di avere il seguente frammento di codice. Quale dei seguenti frammenti di codice ha lo stesso effetto?

int var = somefunction1();
double var2 = somefunction2();
fprintf(stdout, "%d\n%lf\n", var, var2);

Secondo me nessuna delle risposte è da ritenersi corretta, perché:

A:

int var = somefunction1();
double var2 = somefunction2();
char buf[4];
sprintf(buf, "%d", var);
write(1, buf, sizeof(var));
write(1, "\n", 1);
sprintf(buf, "%lf", var2);
write(1, buf, sizeof(var2));
write(1, "\n", 1);

A. buf è troppo piccolo, anche senza guardare il resto, var potrebbe avere un intero che richiede più di 3 cifre (+ terminatore), così come var2 potrebbe richiederne più di 3. Al di là del buffer overflow, comunque non produrrebbe l'effetto desiderato perché si limita a stampare 4 cifre.

B:

int var = somefunction1();
double var2 = somefunction2();
char *buf = calloc(sizeof(var2) > sizeof(var) ? sizeof(var2) : sizeof(var), sizeof(char));
sprintf(buf, "%d", var);
write(1, buf, sizeof(var));
write(1, "\n", 1);
sprintf(buf, "%lf", var2);
write(1, buf, sizeof(var2));
write(1, "\n", 1);

B. Questa è la risposta corretta nel json. In realtà questa ha gli stessi problemi di A: la riga 3 è semplicemente calloc(8, 1) su x86-64. L'intero massimo rappresentabile è 2147483647, che ha 10 cifre, poi ci sono anche i negativi, -2147483648 ne ha 11. Anche ignorando gli overflow il write stampa comunque solo 4 cifre (su x86), quindi non ha lo stesso effetto dell'originale.

Se proprio vogliamo esagerare, il secondo sprintf potrebbe scrivere anche più di 300 byte secondo questo warning di GCC:

<source>:25:5: warning: 'sprintf' may write a terminating nul past the end of the destination [-Wformat-overflow=]
   25 |     sprintf(buf, "%lf", var2);
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:25:5: note: 'sprintf' output between 4 and 318 bytes into a destination of size 8

C:

int var = somefunction1();
double var2 = somefunction2();
char *buf = calloc(sizeof(var2) > sizeof(var) ? sizeof(var2) : sizeof(var), sizeof(char));
sprintf(buf, "%d\n", var);
write(1, buf, sizeof(var) + 1);
sprintf(buf, "%lf\n", var2);
write(1, buf, sizeof(var2) + 1);

C. Lo stesso di B tranne per l'"aggiunta" di un overrun sul write e sullo sprintf (più di prima). Comunque in A, B, C il write scrive anche i byte nulli, che non considererei proprio avere lo stesso effetto di fprintf.

D:

int var = somefunction1();
double var2 = somefunction2();
write(1, (char *)&var, sizeof(var));
write(1, (char *)&var2, sizeof(var2));

D. Ironicamente la versione più sicura, però scrive i due numeri in binario mentre fprintf li converte in ASCII, in più mancano i newline.

@interestingmaneuver interestingmaneuver added the help wanted Extra attention is needed label May 31, 2024
@FeddyLix17
Copy link
Contributor

FeddyLix17 commented Jul 24, 2024

@interestingmaneuver premesso che anche secondo me (per gli stessi motivi che hai scritto) nessun blocco di codice riportato è esattamente equivalente a quello riportato dalla domanda (considerato che la funzione write() non è normalmente predisposta per la stampa di interi composti da più cifre)

tolte le opzioni D ed A (sicuramente diverse), tra l'opzione B e C sceglieri la B in quanto nell'fprintf() il numero e il carattere "\n" vengono stampati "separatamente" e non "seguendo lo stesso flusso dati di un buffer"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

2 participants