Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > it.comp.os.linux.development > #65 > unrolled thread

Spreco di memoria e minaccia alla sicurezza

Started byguido84 <guido84@invalid.invalid>
First post2017-06-12 12:11 +0000
Last post2017-06-13 10:16 +0100
Articles 7 — 3 participants

Back to article view | Back to it.comp.os.linux.development


Contents

  Spreco di memoria e minaccia alla sicurezza guido84 <guido84@invalid.invalid> - 2017-06-12 12:11 +0000
    Re: Spreco di memoria e minaccia alla sicurezza Alessandro Pellizzari <shuriken@amiran.it> - 2017-06-12 15:01 +0100
      Re: Spreco di memoria e minaccia alla sicurezza guido84 <guido84@invalid.invalid> - 2017-06-12 14:57 +0000
        Re: Spreco di memoria e minaccia alla sicurezza Alessandro Pellizzari <shuriken@amiran.it> - 2017-06-12 17:14 +0100
    Re: Spreco di memoria e minaccia alla sicurezza enoquick <enoquick@gmail.com> - 2017-06-12 21:40 -0500
      Re: Spreco di memoria e minaccia alla sicurezza guido84 <guido84@invalid.invalid> - 2017-06-13 07:28 +0000
        Re: Spreco di memoria e minaccia alla sicurezza Alessandro Pellizzari <shuriken@amiran.it> - 2017-06-13 10:16 +0100

#65 — Spreco di memoria e minaccia alla sicurezza

Fromguido84 <guido84@invalid.invalid>
Date2017-06-12 12:11 +0000
SubjectSpreco di memoria e minaccia alla sicurezza
Message-ID<ohm0ck$1rf6$1@gioia.aioe.org>
In tutto il libro che seguo c'e' in continuazione:
.....
char pippo[81];
.....

Esasperato dal doverlo scegliere prima, ho capito che potrei
metterci un numero molto grande (es. 1000), ma qui su icol.dev mi
e' stato detto di stare molto attento a quel che resta dopo '\0'.

Allora ho fatto la prova con: char pippo[]; e immediatamente gcc
m'ha dato un Warning dicendo che l'array veniva inteso di 1 solo
carattere, pero' il programma funzionava perfettamente lo stesso.

Allora astutissimamente gli ho messo:
char pippo[1];
adesso niente Warning e funzionamento sempre perfetto, anche con
stringhe lunghissime.

La mia domanda e' questa.
Visto che:
- pippo[1] e' un puntatore all' INIZIO della stringa (lo dicono
in altre pagine)
- la fine e' IN OGNI CASO determinata da '\0' o da BLANK (e non
dall'81)
- l'indirizzo fisico del vettore non e' ancora determinato (viene
fissato di volta in volta durante l'esecuzione?),

allora dico: perche' mai nel libro che ho non fanno altro che
scrivere in continuazione "char pippo[81];" ?
Non sarebbe il caso di mettere SEMPRE "char pippo[1];" ?


-- 
Saluti,
Guido

[toc] | [next] | [standalone]


#66

FromAlessandro Pellizzari <shuriken@amiran.it>
Date2017-06-12 15:01 +0100
Message-ID<eq7l5jF9dpaU1@mid.individual.net>
In reply to#65
On 12/06/17 13:11, guido84 wrote:

> Allora astutissimamente gli ho messo:
> char pippo[1];
> adesso niente Warning e funzionamento sempre perfetto, anche con
> stringhe lunghissime.

Questo perche`, per efficienza, Linux alloca memoria in blocchi di 
dimensione fissa (mi pare 4k), quindi finche` i tuoi dati stanno dentro 
il blocco, e tu eccedi nell'ultima variabile dichiarata, va tutto bene.

Ma gia` se provi a fare

char pippo[1];
char pluto[1];

Scrivendo oltre il limite di pippo rischi di sovrascrivere pluto.

> allora dico: perche' mai nel libro che ho non fanno altro che
> scrivere in continuazione "char pippo[81];" ?
> Non sarebbe il caso di mettere SEMPRE "char pippo[1];" ?

No. Vedi sopra.

Il modo giusto e` usare malloc per allocare la memoria che ti serve, e 
poi verificare di volta in volta che non la stai eccedendo.

A quel punto pippo diventa davvero un puntatore a un'area dinamica di 
memoria, e lo puoi dichiarare con

char *pippo;


Bye.

[toc] | [prev] | [next] | [standalone]


#67

Fromguido84 <guido84@invalid.invalid>
Date2017-06-12 14:57 +0000
Message-ID<ohma5d$fvf$1@gioia.aioe.org>
In reply to#66
Il 12/6/2017 16:01:23 Alessandro Pellizzari scrisse:
>On 12/06/17 13:11, guido84 wrote:

>> Allora astutissimamente gli ho messo:
>> char pippo[1];
>> adesso niente Warning e funzionamento sempre perfetto, anche con
>> stringhe lunghissime.

>Questo perche`, per efficienza, Linux alloca memoria in blocchi di
>dimensione fissa (mi pare 4k), quindi finche` i tuoi dati stanno dentro
>il blocco, e tu eccedi nell'ultima variabile dichiarata, va tutto bene.

>Ma gia` se provi a fare

>char pippo[1];
>char pluto[1];

>Scrivendo oltre il limite di pippo rischi di sovrascrivere pluto.

TNX! questa me la faccio piu' tardi, voglio fargli sovrascrivere
pluto (ma 4k sono veramente moltissmi, glieli daro' da file).

>> allora dico: perche' mai nel libro che ho non fanno altro che
>> scrivere in continuazione "char pippo[81];" ?
>> Non sarebbe il caso di mettere SEMPRE "char pippo[1];" ?

>No. Vedi sopra.

>Il modo giusto e` usare malloc per allocare la memoria che ti serve, e
>poi verificare di volta in volta che non la stai eccedendo.

>A quel punto pippo diventa davvero un puntatore a un'area dinamica di
>memoria, e lo puoi dichiarare con

>char *pippo;

Per imparare le funzioni e poi saperle usare, per atoi() ho
cercato di poter dargli la stringa in input:
1. da argv[1], ormai facile: ./prova 111
2. col comando echo, unico modo: ./prova $(echo 111)
3. passandogliela con una pipe: echo 111 | ./prova -

Per fare il 3 (tralasciando per il momento che non so fargli
distinguere "-" da qualsiasi altro carattere diverso da cifre),
non posso (mi sembra!) usare malloc, perche' scanf() non me lo
puo' dire quanto e' lunga prima di riceverla. E per riceverla
deve avere un posto-vettore dove metterla... insomma: il gatto
che si mangia la coda. Percio' ho trovato l'escamotage di pippo[0]
(adesso ho visto che prende anche lo zero).

Ecco il codice.
------
#include <stdio.h>
#include <string.h>

int atoi(char *origine);
char dapipe[0];

int main(int argc, char** argv)
{
int arg1, arg2;

// ./prova  (per l'help)
if (argc == 1)
{
printf("\033[33mUsage: Stringa di arg1 in numero allo stdout \033[m \n");
}

else
{
arg1 = atoi(argv[1]);

// echo 123 | ./prova -
if (arg1 == 0)
{
scanf("%s", dapipe);
arg2 = atoi(dapipe);
printf("%d\n", arg2);
}

// Caso ordinario
else
{
printf("%d\n", arg1);
}
}

return 0;
}
----------------


-- 
Saluti,
Guido

[toc] | [prev] | [next] | [standalone]


#68

FromAlessandro Pellizzari <shuriken@amiran.it>
Date2017-06-12 17:14 +0100
Message-ID<eq7svpFb80eU1@mid.individual.net>
In reply to#67
On 12/06/17 15:57, guido84 wrote:

> Il 12/6/2017 16:01:23 Alessandro Pellizzari scrisse:

>> Ma gia` se provi a fare
> 
>> char pippo[1];
>> char pluto[1];
> 
>> Scrivendo oltre il limite di pippo rischi di sovrascrivere pluto.
> 
> TNX! questa me la faccio piu' tardi, voglio fargli sovrascrivere
> pluto (ma 4k sono veramente moltissmi, glieli daro' da file).

No, in questo caso non serve che allochi 4k.
Ti basta scrivere 2 caratteri dentro pippo, e il secondo te lo trovi in 
pluto.

Questo presupponendo che la memoria venga allocata in ordine. Non so se 
le versioni recenti di gcc o del kernel rispettino questa regola o 
randomizzino la memoria apposta per evitare buffer overflow.

> Per fare il 3 (tralasciando per il momento che non so fargli
> distinguere "-" da qualsiasi altro carattere diverso da cifre),
> non posso (mi sembra!) usare malloc, perche' scanf() non me lo
> puo' dire quanto e' lunga prima di riceverla. E per riceverla
> deve avere un posto-vettore dove metterla... insomma: il gatto
> che si mangia la coda. Percio' ho trovato l'escamotage di pippo[0]
> (adesso ho visto che prende anche lo zero).

In questo caso devi bufferizzare l'input, manualmente o tramite qualche 
libreria.

Prepari un buffer di (diciamo) 4k. Provi a leggere 4k. Se l'input 
finisce prima, ti fermi e analizzi quello che hai, altrimenti allochi 
altri 4k, continui a leggere nel nuovo buffer, ecc. ecc. finche` non 
raggiungi la fine dell'input. A quel punto sai quanto hai letto e lo 
processi.

In alternativa allochi 4k, provi a leggere, se non basta usi realloc per 
allargare il buffer (di solito si raddoppia ogni volta), e vai avanti 
finche` l'input non e` finito.

Il tuo prossimo problema e` che atoi va in overflow superati i 9 
miliardi di miliardi (una ventina di cifre, su architettura 64bit), 
quindi leggere piu` di 20-25 bytes e` comunque inutile, e dobresti usare 
una libreria come bcmath.

Hai voluto lavorare a basso livello? E adesso pedala! ;D

Bye.

[toc] | [prev] | [next] | [standalone]


#70

Fromenoquick <enoquick@gmail.com>
Date2017-06-12 21:40 -0500
Message-ID<ohnjbf$9ev$1@virtdiesel.mng.cu.mi.it>
In reply to#65
Il 12/06/2017 07:11, guido84 ha scritto:
> In tutto il libro che seguo c'e' in continuazione:
> ......
> char pippo[81];
> ......
> 
> Esasperato dal doverlo scegliere prima, ho capito che potrei
> metterci un numero molto grande (es. 1000), ma qui su icol.dev mi
> e' stato detto di stare molto attento a quel che resta dopo '\0'.
> 
> Allora ho fatto la prova con: char pippo[]; e immediatamente gcc
> m'ha dato un Warning dicendo che l'array veniva inteso di 1 solo
> carattere, pero' il programma funzionava perfettamente lo stesso.
> 
> Allora astutissimamente gli ho messo:
> char pippo[1];
> adesso niente Warning e funzionamento sempre perfetto, anche con
> stringhe lunghissime.
> 
> La mia domanda e' questa.
> Visto che:
> - pippo[1] e' un puntatore all' INIZIO della stringa (lo dicono
> in altre pagine)
> - la fine e' IN OGNI CASO determinata da '\0' o da BLANK (e non
> dall'81)
> - l'indirizzo fisico del vettore non e' ancora determinato (viene
> fissato di volta in volta durante l'esecuzione?),
> 
> allora dico: perche' mai nel libro che ho non fanno altro che
> scrivere in continuazione "char pippo[81];" ?
> Non sarebbe il caso di mettere SEMPRE "char pippo[1];" ?
> 
> 

Mi sa che stai confondendo il concetto di puntatore a stringa vs array 
di caratteri
Ma per capirlo meglio postare un esempio di codice.

[toc] | [prev] | [next] | [standalone]


#72

Fromguido84 <guido84@invalid.invalid>
Date2017-06-13 07:28 +0000
Message-ID<oho46j$15ph$1@gioia.aioe.org>
In reply to#70
Il 13/6/2017 04:40:46 enoquick scrisse:
>Il 12/06/2017 07:11, guido84 ha scritto:
>> In tutto il libro che seguo c'e' in continuazione:
>> ......
>> char pippo[81];
>> ......
>> 
>> Esasperato dal doverlo scegliere prima, ho capito che potrei
>> metterci un numero molto grande (es. 1000), ma qui su icol.dev mi
>> e' stato detto di stare molto attento a quel che resta dopo '\0'.
>> 
>> Allora ho fatto la prova con: char pippo[]; e immediatamente gcc
>> m'ha dato un Warning dicendo che l'array veniva inteso di 1 solo
>> carattere, pero' il programma funzionava perfettamente lo stesso.
>> 
>> Allora astutissimamente gli ho messo:
>> char pippo[1];
>> adesso niente Warning e funzionamento sempre perfetto, anche con
>> stringhe lunghissime.
>> 
>> La mia domanda e' questa.
>> Visto che:
>> - pippo[1] e' un puntatore all' INIZIO della stringa (lo dicono
>> in altre pagine)
>> - la fine e' IN OGNI CASO determinata da '\0' o da BLANK (e non
>> dall'81)
>> - l'indirizzo fisico del vettore non e' ancora determinato (viene
>> fissato di volta in volta durante l'esecuzione?),
>> 
>> allora dico: perche' mai nel libro che ho non fanno altro che
>> scrivere in continuazione "char pippo[81];" ?
>> Non sarebbe il caso di mettere SEMPRE "char pippo[1];" ?

>Mi sa che stai confondendo il concetto di puntatore a stringa vs array
>di caratteri
>Ma per capirlo meglio postare un esempio di codice.

Be' me l'ha spiegato Alessandro P., una stringa e' un puntatore
all'inizio piu' \0 alla fine. Si puo' mettere dentro un array
statico, oppure allocando (dinamicamente) spazio in memoria con
malloc, dal puntatore fino al numero di byte che si danno a
malloc stesso.

Un array invece non e' detto che abbia \0, e' semplicemente un
puntatore alla prima cella piu' il numero di celle riservate a
lui, non importa se e cosa ci sia gia' dentro o ci si metta.

Adesso devo sviscerarlo bene, ma ho gia' fatto il malloc per i
caratteri, poi lo faro' per gli interi e i reali.

Questo l'ho trovato fatto, devo capire ancora il ruolo delle
tonde (char *) prima di malloc(), e anche le doppie parentesi
di if, spero-penso che siano come per la bash:

------------
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
char *stringa;
//if((stringa = (char *) malloc(2147483647)) == NULL) // 0x7fff.ffff
if ((stringa = (char *) malloc(0x09fffffff)) == NULL)
{
printf("memoria insufficiente \n");
exit(1);
}
printf("OK \n");

return 0;
}
------------

Non so perche' con gli esa ne prende di piu': 9fff.ffff contro
gli equivalenti di 7fff.ffff coi decimali.


-- 
Saluti,
Guido

[toc] | [prev] | [next] | [standalone]


#73

FromAlessandro Pellizzari <shuriken@amiran.it>
Date2017-06-13 10:16 +0100
Message-ID<eq9oqiFo373U1@mid.individual.net>
In reply to#72
On 13/06/17 08:28, guido84 wrote:

> Questo l'ho trovato fatto, devo capire ancora il ruolo delle
> tonde (char *) prima di malloc(), 

malloc torna un (void *) (un puntatore generico)
Mettendo (char *) prima forzi il compilatore a gestirlo come un 
puntatore a char, abilitando check e ottimizzazioni aggiuntive.

> e anche le doppie parentesi
> di if, spero-penso che siano come per la bash:

Non sono doppie parentesi. Stai raggruppando un'assegnazione (stringa = 
malloc()) prima di confrontarla con null.

Per chiarezza e` meglio "esplodere" il comando cosi`:

char *stringa = (char *)malloc(2147483647);
if (stringa == null) { ... }

Ochio che stai allocando 2GB di memoria, con quella riga.
Funziona solo perche` Linux non alloca veramente la memoria finche` non 
ci scrivi sopra, ma altri S.O. potrebbero allocarla veramente anche se 
non ti serve.

Bye.

[toc] | [prev] | [standalone]


Back to top | Article view | it.comp.os.linux.development


csiph-web