Non riesco a capire!

di il
56 risposte

56 Risposte - Pagina 2

  • Re: Non riesco a capire!

    Questo l'ho capito in parte.
    perchè se scrivo involontariamente su un indirizzo valido ma non allocato e poi dealloco la variabile
    il sistema giustamente andrà in errore!
    ora siccome il sistema verifica se un indirizzo è allocato o meno,questa operazione la fa prima di deallocare.
    io vorrei ripetere questo meccanismo ma non prima di deallocare ma prima di scrivere all'interno della variabile!
    adesso se non capisco come fa non posso farglielo ripetere!
  • Re: Non riesco a capire!

    Non ho capito che hai detto.

    Che vuoi dire con

    ' il sistema verifica se un indirizzo è allocato o meno'

    ?

    Non è così quando vai a zonzo in memoria... nessuno ti assicura nulla sulla possibilità di scrivere o non scrivere in quella zona di memoria ...

    RIPETO ... NON so cosa tu voglia fare ma

    1) se vuoi intercettare l'evento di "violazione d'accesso" di una locazione di memoria non assegnata al processo, lo puoi fare (come hai visto);

    2) se vuoi individuare i limiti di un array allocato in precedenza, NON puoi farlo con certezza perché PRIMA o DOPO quel buffer puoi avere altre zone di memoria allocate o indirizzi assegnati che non puoi prevedere con certezza
  • Re: Non riesco a capire!

    Riepilogando in maniera sintetica
    Quando uso l'operatore new il sistema mi da un indirizzo e marca X byte come allocati e pronti all'uso segnandosi da qualche parte l'indirizzo che mi ha dato e magari segnandosi anche quanti byte mi ha allocato.
    quando uso l'operatore delete dovrebbe recuperare le informazioni che si era conservato,indirizzo e numero di byte allocati precedentemente, verifica se l'indirizzo che gli passo e = a quello conservato e se sono uguali esegue l'operazione.
    adesso quando scrivo in questa variabile e sforo le sue dimensioni in fase di scrittura non mi dice niente.
    ma quando vado a deallocare la variabile se ho sforato in precedenza mi da errore corruzione heap.

    quello che vorrei capire e come fa a "capire " che lo heap e stato corrotto e come capire se un indirizzo è allocato o meno!

    quello che vorrei fare io e semplicemente farmi dare lo stesso errore,corruzione heap, in fase di scrittura cosi da poterlo gestire ed evitare che me lo dia quando dealloco la variabile.
  • Re: Non riesco a capire!

    smalldragon ha scritto:


    Quando uso l'operatore new il sistema mi da un indirizzo e marca X byte come allocati e pronti all'uso segnandosi da qualche parte l'indirizzo che mi ha dato e magari segnandosi anche quanti byte mi ha allocato.
    Il sistema non marca nulla ma registra in una tabella indirizzo e dimensioni dell'area riservata. L'area PUO' anche essere più grande di quella richiesta, decide il sistema in base a tante cose che adesso non interessano. Quindi, se allochi un'area di 7 byte il sistema può riservare anche 16 byte senza alcun problema.
    quando uso l'operatore delete dovrebbe recuperare le informazioni che si era conservato,indirizzo e numero di byte allocati precedentemente, verifica se l'indirizzo che gli passo e = a quello conservato e se sono uguali esegue l'operazione.
    Corretto

    ...
    quello che vorrei capire e come fa a "capire " che lo heap e stato corrotto e come capire se un indirizzo è allocato o meno!
    In modalità DEBUG (non in RELEASE) il runtime scrive dei particolari byte nell'area allocata e ai confini di questa.
    In questo modo riesce a comprendere cosa è successo.
    quello che vorrei fare io e semplicemente farmi dare lo stesso errore,corruzione heap, in fase di scrittura cosi da poterlo gestire ed evitare che me lo dia quando dealloco la variabile.
    Non puoi perché il tutto viene gestito dalla versione DEBUG della new e delete (o malloc e free) e dal runtime della versione DEBUG.
  • Re: Non riesco a capire!

    E non c'è un sistema per accedere a quella tabella delle aree riservate?
  • Re: Non riesco a capire!

    @smalldragon,
    ti sono CHIARI i meccanismi di allocazione della memoria fatti

    1) DAL SISTEMA OPERATIVO per il procsso e
    2) DAL PROCESSO per le sue necessita' interne?

    Hai CHIARO di come sono implementate le varie "malloc", "calloc", "new" e "new[]" ?

    Hai CHIARO come la memoria del processo viene suddivida dal runtime del C/C++?
    Area costanti? Variabili globali? Stack dei thread? Heap?
  • Re: Non riesco a capire!

    smalldragon ha scritto:


    E non c'è un sistema per accedere a quella tabella delle aree riservate?
    Non sono documentate quindi non capiresti nulla e sono gestite all'interno del runtime o all'interno dello stesso sistema operativo.

    Stai cercando di fare qualcosa che non è possibile fare e che, ti ripeto, NON HA ALCUN SENSO fare perché non serve a nulla di pratico.
  • Re: Non riesco a capire!

    smalldragon ha scritto:


    E non c'è un sistema per accedere a quella tabella delle aree riservate?
    Non è proprio una tabella ma una struttura complessa di tanti elementi collegati tra loro che non è facile indagare (l'allocazione della memoria è un argomento MOLTO complesso, più di quello che immagini).

    Si possono sfruttare delle funzioni del CRT come la _heapwalk che permette di esplorare l'heap ... classico esempio questo
    
    #include <stdio.h>
    #include <malloc.h>
    
    void heapdump(void);
    
    int main(void)
    {
        char *buffer;
    
        heapdump();
        if((buffer = (char *)malloc(59)) != NULL)
        {
            heapdump();
            free(buffer);
        }
        heapdump();
    }
    
    void heapdump(void)
    {
        _HEAPINFO hinfo;
        int heapstatus;
        int numLoops;
        hinfo._pentry = NULL;
        numLoops = 0;
        while((heapstatus = _heapwalk(&hinfo)) == _HEAPOK &&
              numLoops < 100)
        {
            printf("%8s block at %Fp of size %4.4X\n",
                   (hinfo._useflag == _USEDENTRY ? "USED" : "FREE"),
                   hinfo._pentry, hinfo._size);
            numLoops++;
        }
    
        switch(heapstatus)
        {
        case _HEAPEMPTY:
            printf("OK - empty heap\n");
            break;
        case _HEAPEND:
            printf("OK - end of heap\n");
            break;
        case _HEAPBADPTR:
            printf("ERROR - bad pointer to heap\n");
            break;
        case _HEAPBADBEGIN:
            printf("ERROR - bad start of heap\n");
            break;
        case _HEAPBADNODE:
            printf("ERROR - bad node in heap\n");
            break;
        }
    }
    
    che ha molte limitazioni (leggi MSDN) e non è "praticamente" utilizzabile per quello che vuoi fare tu.

    In ogni caso, tu stai cercando di fare qualcosa che non è "praticamente" possibile fare e che, ti ripeto, NON HA ALCUN SENSO fare perché non serve a nulla di pratico.
  • Re: Non riesco a capire!

    @smalldragon, l'implementazione della gestione delle eccezioni fornita dal codice assembler e' la BANALISSIMA implementazione mediante setjmp/longjmp, che puoi implementare anche in C, SENZA scomodare il lnguaggio macchina.

    La struttura dati gestita e' un banale stack di indirizzi che rappresentan i vari "try/catch" nidificati, in cui il TOP dello stack, che DEVE ESSERE GLOBALE, e' memorizzato in "fs:[0]".

    Quando il SISTEMA OPERATIVO genera un'eccezione (generata da codice DI SO o per eccezioni hardware), il controllo viene passato alla routine DEL PROCESSO, il cui indirizzo e' memorizzato in "fs:[0]". Da li, parte la gestione UTENTE dell'eccezione.

    https://docs.microsoft.com/en-us/windows/win32/debug/structured-exception-handling.

    La gestione della memoria di un processo, e la validazione degli indirizzi, in C/C++, E' TUTTA UN"ALTRA QUESTIONE.

    La CPU controlla SOLO se l'indirizzo e' VALIDO per il processo corrente e se ci sono i diritti di lettura/scrittura in base all'operazione che si sta' eseguendo.

    MA NON HA NESSUNA INFORMAZIONE su che cosa voglia dire quell'indirizzo! Perche' il SIGNIFICATO dell'indirizzo (se e' una variabile, un vettore, ..) E' RESPONSABILITA" dell'appricazione contenuta nel processo!

    Chissa' se cosi ti si illumina la lampadina della comprensione
  • Re: Non riesco a capire!

    Grazie delle risposte
    qualcosa mi e chiaro
    @migliorabile
    grazie per il link anche se è troppo generico

    migliorabile ha scritto:


    Hai CHIARO di come sono implementate le varie "malloc", "calloc", "new" e "new[]" ?
    vedro di trovare in rete i sorgenti in rete cosi da studiarmeli ed approfondire.
    gli altri aspetti mi erano già chiari.
    @oregon
    il poter evitare errori senza doversi portare le dimensioni degli array, ogni volta, o dover calcolare, sempre, le dimensioni di quest'ultimi a parer mio è una cosa molto utile anche se di difficile realizzazione!
  • Re: Non riesco a capire!

    Guarda che la programmazione C/C++/Asm va avanti da decenni senza i problemi che riscontri tu. L'uso consapevole dei puntatori è patrimonio di ogni bravo programmatore che lavora con questi linguaggi. Personalmente non ho mai avuto problemi di nessun tipo con i puntatori (fin quando ho seguito precise regole). Ti possono comunque venire in aiuto gli "smart pointer" ... dai una lettura a

    SMART POINTERS
    https://italiancoders.it/smart-pointers-in-c

    P.S. Fra l'altro continui a non capire (e tu non l'hai mai spiegato chiaramente) quale sia la differenza in Asm se hai una procedura a cui passi ad esempio ESI come puntatore ad un'area di memoria. La procedura cosa sa di quel puntatore? Nulla. Come in C. Non sa se è valido, non sa se è utilizzabile ... non sa nulla ... Quindi cosa faresti in Asm di diverso?
  • Re: Non riesco a capire!

    smalldragon ha scritto:


    il poter evitare errori senza doversi portare le dimensioni degli array, ogni volta, o dover calcolare, sempre, le dimensioni di quest'ultimi a parer mio è una cosa molto utile anche se di difficile realizzazione!
    Guarda che questo che dici già da un pezzo si può fare in C++ (con l'ovvio trade-off dell'esecuzione più lenta)
    #include <iostream>
    #include <algorithm> 
    #include <vector>
    using namespace std;
    
    int main(void)
    {     
        int i;
        vector<int> v;
    
        v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5);
    
        for(i = 0; i < 10000; i++) try {
            cout << v.at(i) << endl;
        }catch(const out_of_range& e){}
    
        for(i = 0; i < 10000; i++) try {
            v.at(i) *= 10;
        }catch(const out_of_range& e){}
    
        for_each (v.begin(), v.end(), [ ](int n) {
            cout << n << endl;
        });
    
        return 0;
    }
  • Re: Non riesco a capire!

    Ci sono librerie PIU' INTELLIGENTI anche come alternative della malloc/calloc/free che assicurano che uno stia utilizzando un puntatore VALIDO.

    La PRIMA regola FONDAMENTALE e' NON USARE l'aritmetica dei puntatori!
    La SECONDA regola e' usare puntatore SOLO ad oggetti allocati nello heap
    La TERZA regola e' validare il puntatore, e questo lo si fa aggiungendo delle informazioni (in testa ed in coda) al brocco si memoria allocato.

    ESISTE anche una libreria che implementa un "Garbage Collector Conservativo" decisamente buona:

    https://www.hboehm.info/gc

    Invece di continuare a pasticciare come stai facendo, potersti STUDIARTI questo, DECISAMENTE piu' interessante

  • Re: Non riesco a capire!

    @oregon

    oregon ha scritto:


    Guarda che la programmazione C/C++/Asm va avanti da decenni senza i problemi che riscontri tu. L'uso consapevole dei puntatori è patrimonio di ogni bravo programmatore che lavora con questi linguaggi.

    questo lo so'
    e per fortuna che non mi hanno aspettato altrimenti stavamo ancora hai sistemi base!
    da una prima occhiata veloce credo che sia quello che serve a me.

    oregon ha scritto:


    P.S. Fra l'altro continui a non capire (e tu non l'hai mai spiegato chiaramente) quale sia la differenza in Asm se hai una procedura a cui passi ad esempio ESI come puntatore ad un'area di memoria. La procedura cosa sa di quel puntatore? Nulla. Come in C. Non sa se è valido, non sa se è utilizzabile ... non sa nulla ... Quindi cosa faresti in Asm di diverso?
    non voglio fare cose diverse dal normale!
    lettura / scrittura del puntatore vorrei semplicemente che se quel puntatore,nel caso non sia valido, quando faccio l'operazione mi, "dica", restituisca un errore che poi potrei gestire.
    e questo fatto qui quando ho a che fare con gli array/stringhe allocate non me lo fa quando faccio le normali operazioni di lettura/scrittura!
    me lo fa solo quando dealloco!
    ho capito che quando alloca alloca + spazio di quanto ce ne chiedo.
    ed ho capito anche che quando alloca mette dei byte di controllo.
    comunque spero che nel link che mi hai mandato ci sia qualche risposta.
    ti sembrerà strano ma per me è più facile capire un listato assembly che un omologo in c++
  • Re: Non riesco a capire!

    Weierstrass ha scritto:


    smalldragon ha scritto:


    il poter evitare errori senza doversi portare le dimensioni degli array, ogni volta, o dover calcolare, sempre, le dimensioni di quest'ultimi a parer mio è una cosa molto utile anche se di difficile realizzazione!
    Guarda che questo che dici già da un pezzo si può fare in C++ (con l'ovvio trade-off dell'esecuzione più lenta)
    #include <iostream>
    #include <algorithm> 
    #include <vector>
    using namespace std;
    
    int main(void)
    {     
        int i;
        vector<int> v;
    
        v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5);
    
        for(i = 0; i < 10000; i++) try {
            cout << v.at(i) << endl;
        }catch(const out_of_range& e){}
    
        for(i = 0; i < 10000; i++) try {
            v.at(i) *= 10;
        }catch(const out_of_range& e){}
    
        for_each (v.begin(), v.end(), [ ](int n) {
            cout << n << endl;
        });
    
        return 0;
    }
    lo traduco in asm e verifico se fa al caso mio comunque ti ringrazio
Devi accedere o registrarti per scrivere nel forum
56 risposte