Citazione da: cdimauro - 01 Dicembre 2014, 17:25:12Ma non sempre è possibile prevederli.Dipende, con il range type (bounded) esempi classici che delegano il range checking in runtime possono essere controllati in compile time, per esempio: buffer[f()]; il ritorno di f() deve essere lo stesso range type che utilizza l'array del tipo buffer. Andando sul generale non puoi iterare quel buffer con un indice che non è dichiarato dello stesso range type. Se l'array viene dichiarato con un tipo range bounded, il type checking implica il range checking.
Ma non sempre è possibile prevederli.
Il range checking avviene per gli unbounded range, in cui il tipo range è conosciuto solo durante il runtime (ma nel mission critical non si usano mai). Il range checking di Ada in compile time si comporta molto bene in questi casi, soprattutto quando l'array non è guarded nei cicli (for i in buffer'Range), in particolare nei cicli generici non ti permette di accedere ad un array se l'index non è controllato nella condizione.Onestamente non ho trovato casi in cui un unbounded range non venisse catchato in compile time, sicuramente saranno casi eccessivamente complicati.. ma qui ci vuole un po' di software engineering e buon senso, casi così delicati vanno trattati con estrema semplicità per essere il più possibile padroneggiati. In ogni caso c'è il bounds checking in runtime, che protegge i casi in cui il guard sull'array non può essere garantito.
Il vero problema comunque sono gli array dinamici, che oltre ad essere pericolosi per la sicurezza (buffer overflow, il resize non è altro che un free()/malloc() quindi tutti i reference diventano dangling pointer, etc) offre delle pessime performance se fai tantissime operazioni di modifica.
Morale della favola, evitare gli array dinamici ed utilizzare solo ed esclusivamente strutture dati. Questo è uno dei motivi per cui Wirth non implementò mai gli array dinamici nei suoi linguaggi.
Citazione da: cdimauro - 01 Dicembre 2014, 17:25:12Ma non sempre è possibile prevederli. Per questo motivo ho lavorato a una nuova tecnologia per accelerare in hardware il controllo dei bound;mi sa che non sei il primo ad averci pensato, anche se in quel caso non ne e' valsa la candela: idee varie in OpenRISC!
Ma non sempre è possibile prevederli. Per questo motivo ho lavorato a una nuova tecnologia per accelerare in hardware il controllo dei bound;
esattamente cosa presenti ?
hai un nodello HDL ?
Citazione da: dsar - 02 Dicembre 2014, 12:07:05Non so se ti rendi conto dell'idea totalmente insana, ci metteresti due/tre mesi per finire di compilarloper questa porcata lavoro sotto QEMU/MIPS su un muletto di ordine almeno i2fossi matto ad usare un SoC a 800Mhz che performa meno di un P3pero' anche cosi' il cross compilare e' un bel macello, e metterlo a posto anche peggio in compenso per PowerPC si trovano bootstrap (l'ho fatto, funge)e anche per ARM c'e' qualcosa (non l'ho provato di persona)
Non so se ti rendi conto dell'idea totalmente insana, ci metteresti due/tre mesi per finire di compilarlo
Citazione da: cdimauro - 02 Dicembre 2014, 22:12:04Alla fine emuli i MIPS con gli x86, eh! Ma lasciali perdere e dedicati direttamente a questi ultimi. per forza, non ho abbastanza quattrini per comprare hw + carrozzato, volendo dalla Cina ci sarebbe pure qualcosa di + potente della + potente CPU mips che ho in casa, un R16K a 800Mhz, che non accendo quasi masi, si succhia 600Watt e' un 4 CPU.mi costa di meno usare un muletto intel per QEMU/MIPS-catalyst (che crede di fare compilazione nativa)Vedremo con Edison, per ora non c'e' alcun rimpiazzo, da parte mia, per i SoC MIPS in compenso ho definitivamente abbandonato PowerPC: Cerbero, di cui vedi le foto nell'altro thread e' l'ultimo progetto, poi metto la parola fine.E pure sulle HP.
Alla fine emuli i MIPS con gli x86, eh! Ma lasciali perdere e dedicati direttamente a questi ultimi.
Citazione da: cdimauro - 02 Dicembre 2014, 22:12:04CitazioneMorale della favola, evitare gli array dinamici ed utilizzare solo ed esclusivamente strutture dati. Questo è uno dei motivi per cui Wirth non implementò mai gli array dinamici nei suoi linguaggi.Non sono d'accordo perché sono strumenti molto utili.Per esempio? Allargare l'array di una hash table
CitazioneMorale della favola, evitare gli array dinamici ed utilizzare solo ed esclusivamente strutture dati. Questo è uno dei motivi per cui Wirth non implementò mai gli array dinamici nei suoi linguaggi.Non sono d'accordo perché sono strumenti molto utili.
typedef struct _dictobject PyDictObject;struct _dictobject { PyObject_HEAD Py_ssize_t ma_fill; /* # Active + # Dummy */ Py_ssize_t ma_used; /* # Active */ /* The table contains ma_mask + 1 slots, and that's a power of 2. * We store the mask instead of the size because the mask is more * frequently needed. */ Py_ssize_t ma_mask; /* ma_table points to ma_smalltable for small tables, else to * additional malloc'ed memory. ma_table is never NULL! This rule * saves repeated runtime null-tests in the workhorse getitem and * setitem calls. */ PyDictEntry *ma_table; PyDictEntry *(*ma_lookup)(PyDictObject *mp, PyObject *key, long hash); PyDictEntry ma_smalltable[PyDict_MINSIZE];};
od avere stringhe di larghezza infinitamente arbitraria?
Il primo l'ho sempre reputato un aborto computazionale,
il secondo non ne vale assolutamente la pena ed è pessimizzante a mai finire, potrei accettarlo solo per stringhe che poi non verranno più toccate.
Ormai sono abituato a ragionare con chunk di dati (con possibilità di essere cachati per velocizzare le operazioni) e mi trovo non bene ma benissimo.
Dai poi un'occhiata ai principali software che garantiscono (o cercano di farlo) un security by design, nessuno di loro utilizza array allocati dinamicamente.
Lasciando perdere poi il problema sicurezza e inadeguatezza per i dati, il fatto che un puntatore possa puntare a qualcosa di diverso da record/struct/class rende lento e complesso il garbage collector di oltre il 50%, ci sono almeno una quindicina di block descriptor in più solo per gestire il caso degli array allocati dinamicamente, contro un solo block descriptor per record/struct/class, poi la situazione peggiora se un puntatore può puntare "in mezzo" all'array ma fortunatamente questo è un problema dei linguaggi C/C++ . (Ok questo è più un problema implementativo che non riguarda il programmatore/utilizzatore).
Da premettere che per me è un "non problema", spostare una delle tante possibili soluzioni lato hardware non mi ispira tantissimo.. abbiamo già architetture abbastanza complesse. Secondo me ultimamente nel mondo dell'informatica si sta perdendo quel concetto di semplicità che spesso è la soluzione migliore per il controllo della complessità di oggi.
(Con questo non voglio sminuire ciò che stai facendo, che sono sicuro sia un ottimo lavoro)
P.S. ho letto dell'MPX, non risolve però i problemi dei dangling pointer
e comunque ci sono delle problematiche che il runtime check non ha (i falsi positivi)
Sorry per il ritardo ma non ho avuto respiro
Citazione da: cdimauro - 03 Dicembre 2014, 18:33:36Puoi fornire un'implementazione che sia più robusta e altrettanto efficiente?Mi sono preso un po' di tempo (in quel poco che ho) per guardare il .h e un po' il .c, in particolare il commento di documentazione.Mi permetto una critica perché sulle hash table ho un'esperienza di quasi un decennio. Il fatto che quel codice usi open address al posto del chaining ed una tabella eccessivamente piccola è già una scelta discutibile in un linguaggio che fa largo uso di dict ed è facile che degradi presto a linear list (ovvio che poi richiede il resizing della tabella). Se sono tanto preoccupati per le performance di mallocing, basta utilizzare una migliore allocation strategy oppure ci sono altri metodi di open addressing che non richiedono il resize della tabella. Nell'open address non ha senso partire con una tabella piccola e poi allargarla, ed è nato proprio per evitare l'uso di heap (e per un numero limitato di entry).Quindi quale "efficienza"? L'unica cosa che vedo è solo una riduzione della memoria utilizzata, ma non della computazione generale.
Puoi fornire un'implementazione che sia più robusta e altrettanto efficiente?
E poi non è bello sapere queste cose per un programmatore Python :-)
ora che lo so userei in modo diverso le dict, in genere mi piace pensare che ci siano casi ottimizzati in generale, non nel particolare (e mi pare di vedere che ce ne siano tanti), per esempio vedo che hanno ottimizzato in un certo senso il caso di dict piccole per le kwargs, e questo è buono perché è molto importante
Citazione da: cdimauro - 03 Dicembre 2014, 18:33:36Prova a generare in maniera efficiente una pagina web. Se non ricorri a un oggetto StringBuilder / StringIO / buffer che si allunga a dismisura, i tempi di generazione della pagina saranno estremamente elevati.Come lo risolvi diversamente, e in maniera più "sicura", questo problema?Ma in quel modo non ho a che fare con oggetti che non si allungano a dismisura, anzi.. lavorare con chunk di dati è molto meglio, non deallochi/riallochi l'intero dato (causando dangling pointer) ma aggiungi solo ciò che ti serve.
Prova a generare in maniera efficiente una pagina web. Se non ricorri a un oggetto StringBuilder / StringIO / buffer che si allunga a dismisura, i tempi di generazione della pagina saranno estremamente elevati.Come lo risolvi diversamente, e in maniera più "sicura", questo problema?
L'array allocato dinamicamente è una pessima idea in generale, pensa che molti per risolvere il problema dei dangling pointer utilizzano un puntatore a puntatore (quindi si avrà sempre un riferimento al nuovo array allocato), ma si ha due livello di indirizzamento che rallenta di parecchio l'accesso (questo era il metodo utilizzato dalle glib, non so se le cose siano cambiate).
A proposito di Glib, implementa un "cesso" di array dinamico (che cresce ad ogni elemento aggiunto), ad ogni g_array_append_val() veniva fatto un malloc(), copia e free() con performance a dir poco VOMITEVOLI! Se si voleva evitare la riallocazione frequente bisognava crearlo con g_array_sized_new() (anziché g_array_new()) per preallocare una buona porzione dati, ma ciò col tempo non bastava (diamine!) che ricominciava col suo diabolico malloc(), copia e free(). Non capisco come mi piaceva quella cagata pazzesca di glib e gtk+, errori di gioventù (avevo 17 anni o su di lì). Spero che oggi sia un tantino ottimizzato, ma non ho interesse a guardarne il codice o la guida
Citazione da: cdimauro - 03 Dicembre 2014, 18:33:36Purtroppo è un problema generale e molto comune. Non possiamo riscrivere tutto il software esistente in maniera "secure by design", magari con un linguaggio di programmazione diverso. La realtà è costituita da miliardi di righe di codice con cui dobbiamo convivere, e per le quali trovare soluzioni "a buon mercato" per renderli più robusti è una strada percorribile e, anzi, abbastanza richiesta.Purtroppo gran parte del codice che c'è (a mio parere) è codice merda, che è meglio riscrivere.
Purtroppo è un problema generale e molto comune. Non possiamo riscrivere tutto il software esistente in maniera "secure by design", magari con un linguaggio di programmazione diverso. La realtà è costituita da miliardi di righe di codice con cui dobbiamo convivere, e per le quali trovare soluzioni "a buon mercato" per renderli più robusti è una strada percorribile e, anzi, abbastanza richiesta.
Io sono molto a favore dei runtime check (soprattutto se non sono eccessivamente invasivi ma economici), ci si lamenta tanto di come questi runtime check rallentino il software che poi in realtà i veri bottleneck sono altrove.
Ci sono una miriade di problemi a cui deve badare il programmatore, se un gruppo di questi problemi si può evitare selezionando solo certe tecniche, abilitando certe feature ed evitandone altre, posso solo reputarlo "good engineering". Infatti apprezzo molto quei progetti che hanno delle linee guida, in particolare definiscono un subset degli strumenti a disposizione e soprattutto ne danno una motivazione, uno può non essere d'accordo.. ma che ci sia è una cosa da apprezzare
cmq io mi sa che come soluzione bovina hw punto di prepotenza alle classiche (per i MIPS) TLB entriesin salsa bovina: virtual memory for sandboxing everything
semplicemente perche' so come funzionano, e + o - posso pensare a come implementarlo.per chiudere il giro, e' la stessa conclusione a cui sono giunti in OpenRISC
nella versione HP della CPU emulator per motorola 332 EVS c'era una opzione che permetteva di tracciare TUTTI i puntatorigiusto per vedere se si sfora dal rangequel debugger HP lo fa in hw, ci sono dei comparatori di memoriaper armare i comparatori gli si passa la base del puntatore, ed il sizeci sono trigger che si armano solo quando il PC raggiunge istruzioni che fanno uso di una EA in cui e' coinvolto un puntatore da controllarequindi nella parte sw vengono tracciati i punti del codice assemblydove si fa riferimento al puntatore che si desidera monitoraretutto viene etichettato in modo incrementale e gestito in hw con un numero limitato di possibili controlli ( mi pare siano 8 )dopo di che, in esecuzione, ogni volta che viene incontrata l'istruzione incriminata scatta il via libera per il comparatore hw, e si controlla l'EA finalee se sfora si alza una exceptionfacendo sapere all'utente chi/dove/perche' ha sforatomolto primitivo ma apprezzatocostava un bel po' negli anni '90
gdb funziona circa in quel modo, cerca di seguire un po' il codicema ha tipicamente senso quando il codice segmenta, e non primaovvero si cerca grossolanamente il punto dove segmentae poi lo si analizza nel dettaglio, seguendo istruzione per istruzionecon strumenti che analizzano lo spazio dei puntatori