Quanto è pericoloso accedere a un array fuori limite?


221

Quanto è pericoloso accedere a un array al di fuori dei suoi limiti (in C)? A volte può capitare di leggere dall'esterno dell'array (ora capisco di accedere alla memoria utilizzata da alcune altre parti del mio programma o anche oltre) o sto cercando di impostare un valore su un indice esterno all'array. Il programma a volte si arresta in modo anomalo, ma a volte viene eseguito, dando solo risultati inaspettati.

Ora quello che vorrei sapere è, quanto è davvero pericoloso? Se danneggia il mio programma, non è poi così male. Se d'altra parte si rompe qualcosa al di fuori del mio programma, perché in qualche modo sono riuscito ad accedere ad una memoria totalmente non correlata, allora è molto male, immagino. Ho letto un sacco di "tutto può succedere", "la segmentazione potrebbe essere il problema meno grave" , "il tuo disco rigido potrebbe diventare rosa e gli unicorni potrebbero cantare sotto la tua finestra", il che è bello, ma qual è davvero il pericolo?

Le mie domande:

  1. La lettura di valori esterni all'array può danneggiare qualcosa di diverso dal mio programma? Immagino che solo guardare le cose non cambi nulla, o cambierebbe, ad esempio, l'attributo "ultima apertura" di un file che mi è capitato di raggiungere?
  2. L'impostazione di valori fuori dall'array può danneggiare qualcosa di diverso dal mio programma? Da questa domanda Stack Overflow ho capito che è possibile accedere a qualsiasi posizione di memoria, che non esiste alcuna garanzia di sicurezza.
  3. Ora eseguo i miei piccoli programmi da XCode. Ciò fornisce una protezione aggiuntiva attorno al mio programma in cui non può raggiungere al di fuori della propria memoria? Può danneggiare XCode?
  4. Qualche consiglio su come eseguire il mio codice intrinsecamente difettoso in modo sicuro?

Uso OSX 10.7, Xcode 4.6.


In generale, il sistema operativo proteggerà se stesso e altri processi da malfunzionamenti. Tuttavia, non è qualcosa su cui vuoi necessariamente fare affidamento.
Hot Licks

7
Inoltre, non accadrà mai "di raggiungere" un file sul disco rigido durante l'accesso e l'indice dell'array fuori dai limiti (nella RAM).
Batterista,

1
credo che tu stia chiedendo di array C, giusto? quindi questo non ha nulla a che fare con ObjC e non si collega a nessun IDE.
Bryan Chen,

17
Ecco il mio esempio preferito di risultati strani (si occupa dello stack, ma l'ho trovato davvero illuminante ...).
phipsgabler,

Risposte:


125

Per quanto riguarda lo standard ISO C (la definizione ufficiale della lingua), l'accesso a un array al di fuori dei suoi limiti ha un " comportamento indefinito ". Il significato letterale di questo è:

comportamento, in caso di utilizzo di un costrutto di programma non portabile o errato o di dati errati, per i quali la presente norma internazionale non impone requisiti

Una nota non normativa si espande su questo:

I possibili comportamenti indefiniti vanno dall'ignorare completamente la situazione con risultati imprevedibili, al comportamento durante la traduzione o l'esecuzione del programma in un modo documentato caratteristico dell'ambiente (con o senza l'emissione di un messaggio diagnostico), alla conclusione di una traduzione o esecuzione (con l'emissione di un messaggio diagnostico).

Questa è la teoria. Qual è la realtà?

Nel caso "migliore", accederai a un pezzo di memoria che è di proprietà del tuo programma attualmente in esecuzione (che potrebbe causare un comportamento anomalo del programma) o che non è di proprietà del tuo programma in esecuzione (che probabilmente causerà al tuo programma di crash con qualcosa come un errore di segmentazione). Oppure potresti tentare di scrivere nella memoria di tuo programma, ma è contrassegnato come di sola lettura; questo probabilmente causerà anche l'arresto anomalo del programma.

Ciò presuppone che il programma sia in esecuzione con un sistema operativo che tenta di proteggere i processi in esecuzione contemporaneamente l'uno dall'altro. Se il tuo codice è in esecuzione sul "bare metal", indica se fa parte di un kernel del sistema operativo o di un sistema incorporato, quindi non esiste tale protezione; il tuo codice di comportamento scorretto è ciò che doveva fornire tale protezione. In tal caso, le possibilità di danni sono notevolmente maggiori, tra cui, in alcuni casi, danni fisici all'hardware (o a cose o persone nelle vicinanze).

Anche in un ambiente con sistema operativo protetto, le protezioni non sono sempre al 100%. Esistono bug del sistema operativo che consentono ad esempio ai programmi non privilegiati di ottenere l'accesso root (amministrativo). Anche con i normali privilegi dell'utente, un programma malfunzionante può consumare risorse eccessive (CPU, memoria, disco), che può far crollare l'intero sistema. Molti malware (virus, ecc.) Sfruttano i sovraccarichi del buffer per ottenere un accesso non autorizzato al sistema.

(Un esempio storico: ho sentito che su alcuni vecchi sistemi con memoria core , accedere ripetutamente a una singola posizione di memoria in un loop stretto potrebbe letteralmente far sciogliere quel pezzo di memoria. Altre possibilità includono la distruzione di un display CRT e lo spostamento della lettura / scrivere la testa di un'unità disco con la frequenza armonica del cabinet dell'unità, facendola passare attraverso un tavolo e cadere sul pavimento.)

E c'è sempre Skynet di cui preoccuparsi.

La linea di fondo è questa: se potessi scrivere un programma per fare deliberatamente qualcosa di male , è almeno teoricamente possibile che un programma difettoso possa fare la stessa cosa accidentalmente .

In pratica, è molto improbabile che il tuo programma difettoso in esecuzione su un sistema MacOS X faccia qualcosa di più grave del crash. Ma non è possibile impedire completamente al codice buggy di fare cose davvero brutte.


1
grazie, lo capisco perfettamente. Ma innesca immediatamente una domanda di follow-up: cosa può fare un programmatore principiante, per proteggere il proprio computer dalle proprie creazioni forse orribili? Dopo aver testato a fondo un programma, posso liberarlo nel mondo. Ma la prima esecuzione di prova è destinata a essere un programma errato. Come potete proteggere i vostri sistemi da voi stessi?
ChrisD,

6
@ChrisD: Tendiamo ad essere fortunati. Cool Seriamente, la protezione a livello di sistema operativo è abbastanza buona in questi giorni. Nel peggiore dei casi, se scrivo una bomba a forcella accidentale , potrei dover riavviare per recuperare. Ma probabilmente non vale la pena preoccuparsi del danno reale al sistema, purché il programma non stia tentando di fare qualcosa al limite dell'essere pericoloso. Se sei davvero preoccupato, eseguire il programma su una macchina virtuale potrebbe non essere una cattiva idea.
Keith Thompson,

1
D'altra parte, ho visto accadere molte cose strane sui computer che ho usato (file corrotti, errori di sistema irrecuperabili, ecc.), E non ho idea di quanti di loro potrebbero essere stati causati da alcuni programmi C che espongono il temuto comportamento indefinito. (Finora nessun demone reale mi è volato via dal naso.)
Keith Thompson il

1
grazie per avermi insegnato le bombe a forcella - Ho fatto cose simili a quelle, quando ho cercato di afferrare la ricorsione :)
ChrisD

2
scientificamerican.com/article/… quindi è ancora possibile il fuoco con l'elettronica moderna.
Mooing Duck,

25

In generale, i sistemi operativi di oggi (quelli popolari comunque) eseguono tutte le applicazioni in aree di memoria protette utilizzando un gestore di memoria virtuale. Si scopre che non è terribilmente FACILE (per dire) semplicemente leggere o scrivere in una posizione che esiste nello spazio REALE al di fuori della regione (s) che sono state assegnate / allocate al processo.

Risposte dirette:

1) La lettura non danneggerà quasi mai direttamente un altro processo, tuttavia può danneggiare indirettamente un processo se ti capita di leggere un valore KEY utilizzato per crittografare, decrittografare o convalidare un programma / processo. Leggere fuori dai limiti può avere effetti alquanto negativi / imprevisti sul codice se si prendono decisioni in base ai dati che si stanno leggendo

2) L'unico modo in cui potresti DANNEGGIARE qualcosa scrivendo a una loation accessibile da un indirizzo di memoria è se quell'indirizzo di memoria che stai scrivendo è in realtà un registro hardware (una posizione che in realtà non è per l'archiviazione dei dati ma per il controllo di un pezzo di hardware) non una posizione RAM. In effetti, normalmente non danneggerai normalmente qualcosa a meno che tu non stia scrivendo una posizione programmabile una volta che non è riscrivibile (o qualcosa del genere).

3) Generalmente eseguito dall'interno del debugger esegue il codice in modalità debug. L'esecuzione in modalità debug tende a (ma non sempre) fermare il codice più velocemente quando hai fatto qualcosa considerato fuori pratica o decisamente illegale.

4) Non utilizzare mai macro, utilizzare strutture di dati che dispongono già del controllo dei limiti dell'indice dell'array, ecc.

AGGIUNTIVO Vorrei aggiungere che le informazioni di cui sopra sono realmente solo per i sistemi che utilizzano un sistema operativo con finestre di protezione della memoria. Se si scrive codice per un sistema incorporato o anche un sistema che utilizza un sistema operativo (in tempo reale o altro) che non ha finestre di protezione della memoria (o finestre virtuali indirizzate), si dovrebbe prestare molta più attenzione nella lettura e nella scrittura in memoria. Anche in questi casi dovrebbero essere sempre utilizzate pratiche di codifica SICURE e SICURE per evitare problemi di sicurezza.


4
Devono essere sempre utilizzate pratiche di codifica sicure e protette .
Nik Bougalis,

3
Suggerirei di NON utilizzare try / catch per il codice buggy a meno che non si rilevino eccezioni molto specifiche e si sappia come recuperare da esse. La cattura (...) è la cosa peggiore che puoi aggiungere a un codice errato.
Eugene,

1
@NikBougalis - Sono completamente d'accordo, ma è ANCORA PIÙ IMPORTANTE se il sistema operativo non include la protezione della memoria / spazi di indirizzi virtuali, o se manca un sistema operativo :-)
trumpetlicks

@Eugene - Non ho mai notato che è un problema per me, ma sono d'accordo con te, l'ho modificato :-)
Trumpetlicks

1) intendi danni perché rivelerei qualcosa che avrebbe dovuto rimanere segreto? 2) Non sono sicuro di ottenere ciò che intendi, ma suppongo di accedere alla RAM solo cercando di accedere a posizioni al di fuori dei limiti dell'array?
ChrisD,

9

La mancata verifica dei limiti può portare a brutti effetti collaterali, tra cui falle di sicurezza. Uno dei brutti è l'esecuzione arbitraria di codice . Nell'esempio classico: se si dispone di un array di dimensioni fisse e si utilizza strcpy()per inserire una stringa fornita dall'utente, l'utente può fornire una stringa che trabocca sul buffer e sovrascrive altre posizioni di memoria, incluso l'indirizzo di codice in cui la CPU dovrebbe restituire quando la funzione finiture.

Ciò significa che il tuo utente può inviarti una stringa che farà essenzialmente chiamare il tuo programma exec("/bin/sh"), che lo trasformerà in shell, eseguendo tutto ciò che vuole sul tuo sistema, inclusa la raccolta di tutti i tuoi dati e la trasformazione della tua macchina in nodo botnet.

Vedi Smashing The Stack for Fun and Profit per i dettagli su come questo può essere fatto.


So che non dovrei accedere agli elementi dell'array oltre i limiti, grazie per aver rinforzato quel punto. Ma la domanda è, oltre a fare ogni sorta di danno al mio programma, posso inavvertitamente andare oltre la memoria del mio programma? E intendo su OSX.
ChrisD,

@ChrisD: OS X è un moderno sistema operativo, quindi ti fornirà una protezione completa della memoria. Ad esempio, non dovresti limitarti a ciò che il tuo programma è autorizzato a fare. Ciò non dovrebbe includere scherzi con altri processi (a meno che tu non stia eseguendo i privilegi di root).
che il

Preferirei dire sotto i privilegi ring 0, non quelli root.
Ruslan,

Più interessante è che i compilatori iper-moderna può decidere che se tenta codice per leggere foo[0]attraverso foo[len-1]dopo aver utilizzato in precedenza un controllo lencontro la lunghezza della matrice a uno eseguire o saltare un pezzo di codice, il compilatore deve sentirsi libero di correre che altro codice incondizionatamente anche se l'applicazione possiede l'archiviazione oltre l'array e gli effetti della lettura sarebbe stato benigno, ma l'effetto dell'invocazione dell'altro codice non lo sarebbe.
supercat,

8

Scrivi:

Ho letto un sacco di "tutto può succedere", "la segmentazione potrebbe essere il problema meno grave", "il tuo hard disk potrebbe diventare rosa e gli unicorni potrebbero cantare sotto la tua finestra", il che è bello, ma qual è davvero il pericolo?

Diciamo così: carica una pistola. Puntalo fuori dalla finestra senza alcun obiettivo e fuoco particolare. Qual è il pericolo?

Il problema è che non lo sai. Se il tuo codice sovrascrive qualcosa che va in crash il tuo programma, stai bene perché lo fermerà in uno stato definito. Tuttavia, se non si arresta in modo anomalo, iniziano a sorgere i problemi. Quali risorse sono sotto il controllo del tuo programma e cosa potrebbe far loro? Quali risorse potrebbero essere sotto il controllo del tuo programma e cosa potrebbe fare loro? Conosco almeno un grosso problema causato da un tale trabocco. Il problema riguardava una funzione statistica apparentemente insignificante che incasinava una tabella di conversione non correlata per un database di produzione. Il risultato fu una pulizia molto costosa in seguito. In realtà sarebbe stato molto più economico e più facile da gestire se questo problema avesse formattato i dischi rigidi ... in altre parole: gli unicorni rosa potrebbero essere il tuo minimo problema.

L'idea che il tuo sistema operativo ti proteggerà è ottimista. Se possibile, cerca di evitare di scrivere fuori dai limiti.


ok, questo era esattamente ciò di cui avevo paura. Cercherò di "evitare di scrivere fuori dai limiti" ma, visto quello che ho fatto negli ultimi mesi, lo farò sicuramente ancora. Come siete diventati così bravi nella programmazione senza un modo sicuro di esercitarsi?
ChrisD,

3
Chi ha detto che qualsiasi cosa sia mai stata al sicuro;)
Udo Klein

7

Non eseguire il programma come root o qualsiasi altro utente privilegiato non danneggerà nessuno del tuo sistema, quindi in genere questa potrebbe essere una buona idea.

Scrivendo i dati in una posizione di memoria casuale non "danneggi" direttamente nessun altro programma in esecuzione sul tuo computer mentre ogni processo viene eseguito nel suo spazio di memoria.

Se si tenta di accedere a qualsiasi memoria non allocata al processo, il sistema operativo interromperà l'esecuzione del programma con un errore di segmentazione.

Quindi direttamente (senza eseguire come root e accedere direttamente a file come / dev / mem) non c'è pericolo che il tuo programma interferisca con qualsiasi altro programma in esecuzione sul tuo sistema operativo.

Tuttavia - e probabilmente questo è ciò di cui hai sentito parlare in termini di pericolo - scrivendo ciecamente dati casuali in posizioni casuali di memoria per caso puoi sicuramente danneggiare tutto ciò che sei in grado di danneggiare.

Ad esempio, il tuo programma potrebbe voler eliminare un file specifico fornito da un nome file memorizzato da qualche parte nel tuo programma. Se per caso sovrascrivi la posizione in cui è memorizzato il nome del file, potresti invece eliminare un file molto diverso.


1
Se si sta eseguendo come root (o qualche altro utente privilegiato), però, guardare fuori. I sovraccarichi di buffer e array sono un exploit malware comune.
John Bode,

in realtà l'account che utilizzo per tutto il mio calcolo quotidiano non è un account amministratore (utilizzo la terminologia OSX poiché è il mio sistema). Vuoi dire che non posso danneggiare qualcosa cercando di impostare QUALSIASI posizione di memoria? Questa è in realtà una grande notizia!
ChrisD,

Come già accennato prima, il danno peggiore che puoi fare per caso è il danno peggiore che puoi fare come utente. Se vuoi essere sicuro al 100% di non distruggere nessuno dei tuoi dati, probabilmente potresti voler aggiungere un account diverso al tuo computer e sperimentarlo.
mikyra,

1
@mikyra: questo è vero solo se i meccanismi di protezione del sistema sono efficaci al 100%. L'esistenza di malware suggerisce che non puoi sempre fare affidamento su questo. (Non voglio suggerire che valga la pena preoccuparsi; è possibile, ma improbabile, che un programma possa sfruttare accidentalmente le stesse falle di sicurezza sfruttate dal malware.)
Keith Thompson,

1
L'elenco qui include: Esecuzione di codice da fonti non attendibili. Basta fare clic sul pulsante OK su qualsiasi popup del firewall senza nemmeno leggere di cosa si tratta o spegnerlo completamente se non è possibile stabilire la connessione di rete desiderata. Patch binari con l'hack più recente da fonti dubbie. Non è colpa della volta se il proprietario inviterà volontariamente qualsiasi ladro con entrambe le braccia e porte fortificate extra forti spalancate.
mikyra,

4

NSArrays in Objective-C viene assegnato un blocco di memoria specifico. Superare i limiti dell'array significa che si accederà alla memoria non assegnata all'array. Questo significa:

  1. Questa memoria può avere qualsiasi valore. Non è possibile sapere se i dati sono validi in base al tipo di dati.
  2. Questa memoria può contenere informazioni riservate come chiavi private o altre credenziali utente.
  3. L'indirizzo di memoria potrebbe non essere valido o protetto.
  4. La memoria può avere un valore variabile perché è accessibile da un altro programma o thread.
  5. Altre cose usano lo spazio degli indirizzi di memoria, come le porte mappate in memoria.
  6. La scrittura di dati su un indirizzo di memoria sconosciuto può causare l'arresto anomalo del programma, la sovrascrittura dello spazio di memoria del sistema operativo e in genere fa esplodere il sole.

Dal punto di vista del tuo programma, vuoi sempre sapere quando il tuo codice supera i limiti di un array. Ciò può comportare la restituzione di valori sconosciuti, causando l'arresto anomalo dell'applicazione o la fornitura di dati non validi.


NSArraysavere eccezioni illimitate. E questa domanda sembra riguardare l'array C.
Batterista,

Intendevo davvero matrici C. So che c'è NSArray, ma per ora la maggior parte dei miei esercizi sono in C
ChrisD

4

Potresti provare a utilizzare lo memcheckstrumento in Valgrind quando esegui il test del codice: non rileva le violazioni dei singoli limiti dell'array all'interno di un frame dello stack, ma dovrebbe rilevare molti altri tipi di problemi di memoria, inclusi quelli che potrebbero causare sottili, più ampi problemi al di fuori dell'ambito di una singola funzione.

Dal manuale:

Memcheck è un rilevatore di errori di memoria. Può rilevare i seguenti problemi comuni nei programmi C e C ++.

  • Accedendo alla memoria non dovresti, ad es. Sovraccaricare e sottovalutare i blocchi heap, scavalcare la parte superiore dello stack e accedere alla memoria dopo che è stata liberata.
  • Utilizzo di valori non definiti, ovvero valori che non sono stati inizializzati o che sono stati derivati ​​da altri valori non definiti.
  • Liberazione errata della memoria heap, come blocchi heap a doppia liberazione o uso non corrispondente di malloc / new / new [] rispetto a free / delete / delete []
  • Puntatori src e dst sovrapposti in memcpy e funzioni correlate.
  • Perdite di memoria.

ETA: Anche se, come dice la risposta di Kaz, non è una panacea e non sempre fornisce l'output più utile, specialmente quando si utilizzano schemi di accesso entusiasmanti .


Sospetto che l'analizzatore di XCode troverebbe la maggior parte di questo? e la mia domanda non è tanto su come trovare questi bug, ma se eseguire un programma che ha ancora questi bug è pericoloso per la memoria non allocata al mio programma. Dovrò eseguire il programma per vedere accadere i bug
ChrisD

3

Se si esegue mai la programmazione a livello di sistema o la programmazione di sistemi incorporati, possono accadere cose molto brutte se si scrive in posizioni di memoria casuali. I sistemi più vecchi e molti microcontroller utilizzano IO mappato in memoria, quindi scrivere su una posizione di memoria che si associa a un registro periferico può creare scompiglio, specialmente se fatto in modo asincrono.

Un esempio è la programmazione della memoria flash. La modalità di programmazione sui chip di memoria è abilitata scrivendo una specifica sequenza di valori in posizioni specifiche all'interno dell'intervallo di indirizzi del chip. Se un altro processo dovesse scrivere in qualsiasi altra posizione nel chip mentre era in corso, ciò causerebbe il fallimento del ciclo di programmazione.

In alcuni casi l'hardware avvolgerà gli indirizzi (i bit / byte più significativi dell'indirizzo vengono ignorati), quindi la scrittura su un indirizzo oltre la fine dello spazio di indirizzi fisico comporterà effettivamente la scrittura dei dati nel mezzo delle cose.

Infine, le CPU più vecchie come l'MC68000 possono essere bloccate al punto che solo un reset hardware può farle funzionare di nuovo. Non ci ho lavorato per un paio di decenni, ma credo che sia quando si è verificato un errore del bus (memoria inesistente) durante il tentativo di gestire un'eccezione, si fermerebbe semplicemente fino a quando non viene affermato il ripristino dell'hardware.

La mia più grande raccomandazione è una spina palese per un prodotto, ma non ho alcun interesse personale in esso e non sono affiliato in alcun modo a loro - ma basato su un paio di decenni di programmazione C e sistemi embedded in cui l'affidabilità era fondamentale, PC di Gimpel Lint non rileverà solo questo tipo di errori, ma renderà un programmatore C / C ++ migliore anche fuori di te, insistendo costantemente sulle tue cattive abitudini.

Consiglierei anche di leggere lo standard di codifica MISRA C, se riesci a catturarne una copia da qualcuno. Non ne ho visti di recenti, ma ai vecchi tempi hanno dato una buona spiegazione del perché non dovresti / non dovresti fare le cose che coprono.

Non so di te, ma circa la seconda o la terza volta che ricevo un coredump o un blocco da qualsiasi applicazione, la mia opinione su qualunque azienda lo abbia prodotto diminuisce della metà. La quarta o la quinta volta, qualunque sia il pacchetto, diventa un articolo da scaffale e guido un paletto di legno attraverso il centro del pacchetto / disco in cui sono arrivato solo per assicurarmi che non ritorni più a perseguitarmi.


A seconda del sistema, le letture fuori range possono anche innescare comportamenti imprevedibili, oppure possono essere benigne, sebbene un comportamento hardware benigno su carichi fuori range non implica un comportamento benigno del compilatore.
supercat,

2

Sto lavorando con un compilatore per un chip DSP che genera deliberatamente codice a cui si accede oltre la fine di un array da codice C che non lo fa!

Questo perché i loop sono strutturati in modo tale che la fine di un'iterazione precarichi alcuni dati per l'iterazione successiva. Quindi il dato precaricato alla fine dell'ultima iterazione non viene mai effettivamente utilizzato.

Scrivere codice C in questo modo invoca comportamenti indefiniti, ma questa è solo una formalità da un documento standard che si occupa della massima portabilità.

Più spesso, un programma che accede fuori dai limiti non è abilmente ottimizzato. È semplicemente buggy. Il codice recupera un valore di garbage e, a differenza dei loop ottimizzati del suddetto compilatore, il codice utilizza quindi il valore nei calcoli successivi, corrompendoli in tal modo.

Vale la pena catturare bug del genere, e quindi vale la pena rendere indefinito il comportamento anche solo per quel motivo: in modo che il runtime possa produrre un messaggio diagnostico come "array overrun in line 42 of main.c".

Sui sistemi con memoria virtuale, potrebbe accadere che un array sia allocato in modo tale che l'indirizzo che segue sia in un'area non mappata della memoria virtuale. L'accesso quindi bombarderà il programma.

Per inciso, nota che in C ci è permesso creare un puntatore che è uno oltre la fine di un array. E questo puntatore deve comparare maggiore di qualsiasi puntatore all'interno di un array. Ciò significa che un'implementazione C non può posizionare un array proprio alla fine della memoria, in cui l'indirizzo uno più si avvolge e appare più piccolo di altri indirizzi nell'array.

Tuttavia, l'accesso a valori non inizializzati o fuori limite è talvolta una valida tecnica di ottimizzazione, anche se non massimamente portabile. Questo è ad esempio il motivo per cui lo strumento Valgrind non segnala gli accessi a dati non inizializzati quando si verificano tali accessi, ma solo quando il valore viene successivamente utilizzato in qualche modo che potrebbe influenzare l'esito del programma. Ottieni una diagnostica come "ramo condizionale in xxx: nnn dipende da un valore non inizializzato" e talvolta può essere difficile rintracciare dove ha origine. Se tutti questi accessi fossero intrappolati immediatamente, ci sarebbero molti falsi positivi derivanti dal codice ottimizzato del compilatore e dal codice ottimizzato a mano correttamente.

A proposito, stavo lavorando con alcuni codec di un fornitore che stava emettendo questi errori quando veniva portato su Linux ed eseguito sotto Valgrind. Ma il venditore mi ha convinto che solo diversi bitdel valore utilizzato in realtà proveniva da una memoria non inizializzata, e quei bit venivano accuratamente evitati dalla logica. Furono usati solo i bit buoni del valore e Valgrind non ha la capacità di rintracciare il singolo bit. Il materiale non inizializzato proviene dalla lettura di una parola oltre la fine di un flusso di dati codificati, ma il codice sa quanti bit sono presenti nel flusso e non utilizzerà più bit di quanti ce ne siano effettivamente. Poiché l'accesso oltre la fine dell'array del flusso di bit non causa alcun danno all'architettura DSP (non c'è memoria virtuale dopo l'array, nessuna porta mappata in memoria e l'indirizzo non si avvolge) è una tecnica di ottimizzazione valida.

"Comportamento indefinito" non significa molto, perché secondo ISO C, semplicemente includendo un'intestazione che non è definita nello standard C, o chiamando una funzione che non è definita nel programma stesso o nello standard C, sono esempi di undefined comportamento. Comportamento indefinito non significa "non definito da nessuno sul pianeta" solo "non definito dallo standard ISO C". Ma ovviamente, a volte un comportamento indefinito non è assolutamente definito da nessuno.


Inoltre, a condizione che esista almeno un programma che una particolare implementazione elabora correttamente, anche se tassativamente nomina tutti i limiti di implementazione indicati nella norma, tale implementazione potrebbe comportarsi in modo arbitrario se alimentata con qualsiasi altro programma privo di violazioni dei vincoli e ancora " conforme". Di conseguenza, il 99,999% dei programmi C (qualsiasi cosa diversa dal "programma unico" di una piattaforma) si basa su comportamenti in cui lo standard non impone requisiti.
supercat

1

Oltre al tuo programma, non penso che spezzerai nulla, nel peggiore dei casi proverai a leggere o scrivere da un indirizzo di memoria che corrisponde a una pagina che il kernel non ha assegnato ai tuoi processi, generando la giusta eccezione ed essere ucciso (voglio dire, il tuo processo).


3
..Che cosa? Che ne dici di sovrascrivere la memoria nel tuo processo usato per memorizzare alcune variabili usate in seguito ... che ora ha misteriosamente cambiato il suo valore! Quei bug sono molto divertenti da rintracciare, te lo assicuro. Un segfault sarebbe il miglior risultato. -1
Ed S.

2
Voglio dire che non "interromperà" altri processi, oltre al proprio programma;)
jbgs

In effetti non mi interessa se interrompo il mio programma. Sto solo imparando, ovviamente il programma è sbagliato se accedo a qualcosa fuori limite dal mio array. Sto solo diventando sempre più preoccupato per i rischi di rompere qualcos'altro mentre
eseguo il

Il fatto è: posso essere sicuro che se provo ad accedere alla memoria non assegnata a me, che il mio processo verrà ucciso? (essere su OSX)
ChrisD,

3
Anni fa, ero un goffo programmatore C. Ho avuto accesso a matrici fuori dai loro limiti centinaia di volte. Oltre al fatto che il mio processo è stato ucciso dal sistema operativo, non è mai successo nulla.
jbgs
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.