Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Sony WF-1000X M6: le cuffie in-ear di riferimento migliorano ancora
Sony WF-1000X M6: le cuffie in-ear di riferimento migliorano ancora
WF-1000X M6 è la sesta generazione di auricolare in-ear sviluppata da Sony, un prodotto che punta a coniugare facilità di utilizzo con una elevata qualità di riproduzione dei contenuti audio e una cura nella riduzione del rumore ambientale che sia da riferimento
Snowflake porta l'IA dove sono i dati, anche grazie a un accordo con OpenAI
Snowflake porta l'IA dove sono i dati, anche grazie a un accordo con OpenAI
Snowflake ha presentato diverse novità per la sua piattaforma legate all'intelligenza artificiale. Quella forse più eclatante è una collaborazione con OpenAI, ma non mancano diverse nuove funzionalità che rendono la piattaforma più flessibile e in grado di rispondere meglio alle esigenze in continuo cambiamento delle aziende
Sistema Mesh Roamii BE Pro: il Wi-Fi 7 secondo MSI
Sistema Mesh Roamii BE Pro: il Wi-Fi 7 secondo MSI
Con velocità teoriche fino a 11 Gbps, gestione tramite app intelligente e protezione avanzata dei dispositivi, Roamii BE Pro porta il Wi‑Fi 7 tri‑band nelle abitazioni più esigenti. Un sistema Wi-Fi Mesh proposto da MSI allo scopo di garantire agli utenti una rete fluida e continua capace di sostenere streaming 8K, gaming competitivo e le applicazioni moderne più esigenti in termini di banda
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 11-06-2006, 04:37   #1
sottovento
Senior Member
 
L'Avatar di sottovento
 
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
[C] mandare in crash l'applicazione

Ciao a tutti,
ci risiamo: il cliente, nella sua applicazione che mi ha chiesto di analizzare (non capisce perche' non funziona), fra le altre cose ha scritto:

Codice:
char *p;

p = "una stringa qualsiasi"
poi utilizza la variabile p, con il valore cosi' assegnato, in vari punti del metodo.

Analogamente, ha scritto una funzione di questo genere:

Codice:
 
char *funzione ()
{
  switch(qualcosa)
  {
  case 1: return "una stringa";
  case 2: return "altra stringa";
  ...
  }
}
Il risultato e' che l'applicazione registra un crash ogni 2/3 settimane attribuibile a questo codice o al codice approssimativamente "vicino" a questo.

Ho parlato di questo, spiegando che questo codice e' errato Il cliente mi ha risposto che lo usa da anni e che, se non produco CONTROESEMPI che mostrino che questo codice e' errato, non cambiara' una virgola.
L'agilita' mentale del mio cliente, dunque, mi impone di cercare un esempio di utilizzo di questo codice che vada sempre in crash. (in teoria dovrebbe essere lui a mostrare la correttezza dell'applicazione e non io a fare il contrario).

E' praticamente una sfida titanica: nel 90% dei casi (direi nel 99.999% nei casi di piccole applicazioni) questo codice non dara' problemi, anche se errato.

Qualcuno ha idee/suggerimenti/feeling?
L'ambiente e' Windows, il compilatore Visual Studio.

Ringrazio anticipatamente chiunque per qualsiasi considerazione di qualsiasi tipo

High Flying
Sottovento
__________________
In God we trust; all others bring data
sottovento è offline   Rispondi citando il messaggio o parte di esso
Old 11-06-2006, 06:17   #2
71104
Bannato
 
L'Avatar di 71104
 
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
scusa ma perché è errato...?
71104 è offline   Rispondi citando il messaggio o parte di esso
Old 11-06-2006, 06:24   #3
71104
Bannato
 
L'Avatar di 71104
 
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
ipotizzando che sia errato a causa del cast implicito (da const char* a char*), prova a mostrargli questo:
Codice:
char *asd() {
    return "lol";
}
.
.
.
asd()[0] = 0;
bada bene, non l'ho manco provato, potrebbe addirittura non crashare...
ma se ricordo bene in realtà crasherà
71104 è offline   Rispondi citando il messaggio o parte di esso
Old 11-06-2006, 06:45   #4
sottovento
Senior Member
 
L'Avatar di sottovento
 
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
Quote:
Originariamente inviato da 71104
ipotizzando che sia errato a causa del cast implicito (da const char* a char*), prova a mostrargli questo:
Codice:
char *asd() {
    return "lol";
}
.
.
.
asd()[0] = 0;
bada bene, non l'ho manco provato, potrebbe addirittura non crashare...
ma se ricordo bene in realtà crasherà
Avevo gia' provato una soluzione simile: ovviamente va in crash appunto per il motivo che hai accennato. Su Windows si aprira' una finestra col bollone rosso che avvertira' che la memoria non poteva essere "written".

Il motivo per cui il codice errato e' che il C (quello ufficiale) dice che queste costanti non hanno scope. Subito dopo il loro utilizzo, la memoria da loro occupata potrebbe essere utilizzata per qualsiasi altra cosa.
Il problema e' che praticamente non succede mai.

Mi spiego:

char *p = "una stringa";

Questo e' legale: il compilatore riconosce che non e' un assegnamento bensi' una inizializzazione, quindi allochera' automaticamente la memoria necessaria.

char *p;
p = "una stringa";

In questo caso, p punta ad una locazione temporanea di memoria, la cui validita' non e' specificata da nessuna parte.
Su altri sistemi operativi con cui mi e' toccato lavorare (non proprio comuni), il compilatore assegnava davvero una locazione temporanea che poi rilasciava immediatamente, con il "sano" risultato di un crash ripetitivo dell'applicazione.

L'applicazione attuale, invece, sembra andare in crash raramente, per cui e' difficile stabilire il motivo. Ritengo che uno dei vari motivi sia questo pezzo di codice.
Ho passato il codice come il riso, controllando allocazioni/deallocazioni e validita' degli oggetti e puntatori, questo mi sembra il pezzo piu' debole.
Naturalmente, con dei crash cosi' rari (l'applicazione gira 24H), e' difficile fare analisi dettagliate, anche con un debugger.

Grazie per il suggerimento

High Flying
Sottovento
__________________
In God we trust; all others bring data
sottovento è offline   Rispondi citando il messaggio o parte di esso
Old 11-06-2006, 06:49   #5
sottovento
Senior Member
 
L'Avatar di sottovento
 
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
Dimenticavo: grazie anche per il link sul trusted computing


High Flying
Sottovento
__________________
In God we trust; all others bring data
sottovento è offline   Rispondi citando il messaggio o parte di esso
Old 11-06-2006, 10:14   #6
crick_pitomba
Member
 
Iscritto dal: Oct 1999
Messaggi: 111
Quote:
Originariamente inviato da sottovento
Ciao a tutti,
ci risiamo: il cliente, nella sua applicazione che mi ha chiesto di analizzare (non capisce perche' non funziona), fra le altre cose ha scritto:

...

Codice:
 
char *funzione ()
{
  switch(qualcosa)
  {
  case 1: return "una stringa";
  case 2: return "altra stringa";
  ...
  }
}
Il risultato e' che l'applicazione registra un crash ogni 2/3 settimane attribuibile a questo codice o al codice approssimativamente "vicino" a questo.
...
mi son ricordato del classico errore che si fa con i puntatori
Codice:
int * somma(int a, int b){
 int c=a+b;
return &c;
}
che ovviamente porta a risultati indesiderati.

pensavo che il problema che hai posto potesse essere ricollegato ad una cosa simile

quindi ho mandato in esecuzione il seguente frammento di codice per vedere cosa accadeva
Codice:
char *p;
i=0;
while (i++<100){
	p=funzione(i%3);
	printf("%s, %i\n", p,p);
}
mi aspettavo che il puntatore cambiasse... invece è rimasto sempre lo stesso durante l'esecuzione.

sono andato a vedere nella documentazione del visual c++, in relazione alle stringhe letterali ed ho trovato

"Microsoft Specific

In some cases, identical string literals can be "pooled" to save space in the executable file. In string-literal pooling, the compiler causes all references to a particular string literal to point to the same location in memory, instead of having each reference point to a separate instance of the string literal. /GF enables string pooling.

END Microsoft Specific"

se non interpreto male, in pratica è come se il compilatore allocasse effettivamente della memoria per le stringhe letterali e dal mio test sembra anche indipendente dallo scope.

per provare ho modificato leggermente il codice

Codice:
	i=0;
	while (i++<100){
		p=funzione(i%3);
		printf("%s, %i\n", p,p);

	}
		
	
	q="altra stringa";
	printf("%s, %i\n", q,q);
incredibile ma vero:
p è definito nella funzione, q all'esterno... ma hanno lo stesso indirizzo


per come la vedo io, in pratica questo mette al riparo il cliente da errori di memoria non allocata perchè il compilatore crea un guscio di protezione

Quote:
Originariamente inviato da sottovento

char *p;
p = "una stringa";

In questo caso, p punta ad una locazione temporanea di memoria, la cui validita' non e' specificata da nessuna parte.
Su altri sistemi operativi con cui mi e' toccato lavorare (non proprio comuni), il compilatore assegnava davvero una locazione temporanea che poi rilasciava immediatamente, con il "sano" risultato di un crash ripetitivo dell'applicazione.
in pratica abbiamo scoperto che con visual studio p punta ad una locazione di memoria ben definita... e la validità di questa locazione risulta anche nelle specifiche delle stringhe letterali di visual studio. come al solito ms fa le cose a modo suo.

è ragionevole pensare che quel valore resti invariato per l'intera esecuzione del programma.

cosa ne pensi?
crick_pitomba è offline   Rispondi citando il messaggio o parte di esso
Old 11-06-2006, 10:40   #7
thebol
Senior Member
 
Iscritto dal: Dec 2000
Città: bologna
Messaggi: 1309
Quote:
Originariamente inviato da crick_pitomba
incredibile ma vero:
p è definito nella funzione, q all'esterno... ma hanno lo stesso indirizzo


per come la vedo io, in pratica questo mette al riparo il cliente da errori di memoria non allocata perchè il compilatore crea un guscio di protezione



in pratica abbiamo scoperto che con visual studio p punta ad una locazione di memoria ben definita... e la validità di questa locazione risulta anche nelle specifiche delle stringhe letterali di visual studio. come al solito ms fa le cose a modo suo.

è ragionevole pensare che quel valore resti invariato per l'intera esecuzione del programma.

cosa ne pensi?
in realtà avevo già sentito di sta cosa tempo fa, e non relativa al visual studio. Era considerata una possibilie ottimizzazione che il compilatore poteva fare.

ps.è quando vedo questi post, che mi accorgo di quanto sia comodo java
thebol è offline   Rispondi citando il messaggio o parte di esso
Old 11-06-2006, 11:32   #8
andbin
Senior Member
 
L'Avatar di andbin
 
Iscritto dal: Nov 2005
Città: TO
Messaggi: 5206
Quote:
Originariamente inviato da sottovento
char *p = "una stringa";

Questo e' legale: il compilatore riconosce che non e' un assegnamento bensi' una inizializzazione, quindi allochera' automaticamente la memoria necessaria.

char *p;
p = "una stringa";

In questo caso, p punta ad una locazione temporanea di memoria, la cui validita' non e' specificata da nessuna parte.
Guarda che il risultato è lo stesso ...

Prendiamo per esempio:
Codice:
char *p1 = "hello";
char *p2;

p2 = "hello";
Sono praticamente la stessa cosa (come risultato intendo). Anzi, se il compilatore è "furbo" (e per queste cose credo praticamente tutti, VC++, gcc, ecc...) non solo entrambi i puntatori punteranno ad un stringa "hello" ma pure alla stessa identica stringa. In pratica il compilatore scopre che le due stringhe costanti sono uguali e ne inserisce 1 sola nel "constant pool".

Poi dove le stringhe costanti risiedono in memoria ... dipende dal compilatore e sopratutto dal S.O. Nei sistemi a 32 bit dove ci sono tutti i sistemi di protezione, se le stringhe sono allocate in un'area read-only ... non c'è santo che tenga, non puoi alterarne il contenuto.

Sui vecchi sistemi MS-DOS, dove non esisteva alcun sistema di protezione, se facevi char *p="ciao"; e poi p[0]='C'; non ottenevi alcun errore di protezione e il primo carattere veniva cambiato senza problemi.
__________________
Andrea, SCJP 5 (91%) - SCWCD 5 (94%)
andbin è offline   Rispondi citando il messaggio o parte di esso
Old 11-06-2006, 13:08   #9
71104
Bannato
 
L'Avatar di 71104
 
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
Quote:
Originariamente inviato da andbin
Nei sistemi a 32 bit dove ci sono tutti i sistemi di protezione, se le stringhe sono allocate in un'area read-only ... non c'è santo che tenga, non puoi alterarne il contenuto.
be' non essere così assoluto, quale grande esperto di Win32 conoscerai sicuramente anche tu la funzione VirtualProtect, e magari anche VirtualProtectEx
71104 è offline   Rispondi citando il messaggio o parte di esso
Old 11-06-2006, 13:09   #10
71104
Bannato
 
L'Avatar di 71104
 
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
Quote:
Originariamente inviato da sottovento
Il motivo per cui il codice errato e' che il C (quello ufficiale) dice che queste costanti non hanno scope. Subito dopo il loro utilizzo, la memoria da loro occupata potrebbe essere utilizzata per qualsiasi altra cosa.
Il problema e' che praticamente non succede mai.
toglici "praticamente"; comunque guarda che se hai prodotto un codice che va in crash come quello che ti ho mostrato hai raggiunto il tuo scopo: hai dato al tizio una prova di crash causata da quel codice no?

PS: ma perché non fate il debug di quel programma quando crasha?

Ultima modifica di 71104 : 11-06-2006 alle 13:11.
71104 è offline   Rispondi citando il messaggio o parte di esso
Old 11-06-2006, 14:40   #11
andbin
Senior Member
 
L'Avatar di andbin
 
Iscritto dal: Nov 2005
Città: TO
Messaggi: 5206
Quote:
Originariamente inviato da 71104
be' non essere così assoluto
Volevo dire che a livello di linguaggio "C" non è possibile fare niente, perché è una questione del sistema operativo. Se poi il sistema operativo ti mette a disposizione delle funzioni per "alterare" le protezioni sulla memoria ... beh, è un'altra cosa.

Quote:
Originariamente inviato da 71104
quale grande esperto di Win32
Non ho ben capito in quale senso l'hai detto ma ... non sono né un super-esperto né un guru ...

Quote:
Originariamente inviato da 71104
conoscerai sicuramente anche tu la funzione VirtualProtect, e magari anche VirtualProtectEx
Sì, di nome le conosco, so cosa fanno, a grandi linee, ma non ho mai avuto necessità di usarle. E giusto per curiosità ho fatto una prova proprio adesso su Windows con VC++:

Codice che causa l'errore di protezione:
Codice:
#define STRICT
#include <stdio.h>
#include <windows.h>

int main (void)
{
    char *str = "hello";

    printf ("Prima: %s\n", str);

    str[0] = 'H';

    printf ("Dopo: %s\n", str);

    return 0;
}
Codice modificato che non causa l'errore di protezione:
Codice:
#define STRICT
#include <stdio.h>
#include <windows.h>

int main (void)
{
    BOOL  bRet;
    DWORD dwOldProtect;

    char *str = "hello";

    printf ("Prima: %s\n", str);

    bRet = VirtualProtect (str, lstrlen (str)+1, PAGE_READWRITE, &dwOldProtect);

    str[0] = 'H';

    printf ("Dopo: %s\n", str);

    return 0;
}
Ok??
__________________
Andrea, SCJP 5 (91%) - SCWCD 5 (94%)
andbin è offline   Rispondi citando il messaggio o parte di esso
Old 11-06-2006, 15:58   #12
sottovento
Senior Member
 
L'Avatar di sottovento
 
Iscritto dal: Nov 2005
Città: Texas
Messaggi: 1722
Beh, a dirla tutta, ho fatto qualche prova:

char *p = "ciao";

Questa e' una inizializzazione (cosi' la chiamano K&R) ed anche su VS l'istruzione

p[0] = 'C'

e' valida, senza alcuna modifica. Non sono esperto di questi sistemi, ho fatto un piccolo progetto (mantenendo tutte le opzioni di default) ed ha girato senza alcun problema. In effetti, non vedo alcuna violazione dello standard C in questo.

Ho fatto anche l'altra prova:


char *p;
p = "ciao";
il tentativo di modificare con

p[0] = 'C'

porta al bollone rosso del crash (la memoria non poteva essere written).

Come avete detto (grazie soprattutto ad andbin e crick_pitomba) sembra che davvero Visual Studio produca un codice NON STANDARD (e' bene precisarlo, visto che abbiamo anche la pretesa di far girare il codice su altre piattaforme) in modo da allocare queste stringhe nella heap.
Questo, teoricamente, per un motivo di ottimizzazione del codice. Per risparmiare spazio, insomma, ed e' per questo motivo che non si puo' cambiare detta stringa (visto che l'istruzione non e' legale nello standard C, la definisco come voglio. Non fa una piega).

A questo punto, confidente delle varie analisi che ho fatto in questi giorni (vale a dire, il resto del software sembra a posto), mi viene una domanda:
Cosa succede quando la macchina e' sotto stress?
In altri termini: ho un grosso carico di lavoro, memoria tutta occupata e le cpu che lavorano come matte. Che fine fa quest'area?
E poi, visto che non e' standard, quanto persiste? Tutta la durata dell'applicazione (beh, bella ottimizzazione! Fa proprio ridere!), la durata di un modulo? (cos'e' un modulo)? La vita di un oggetto? Se questa stringa e' usata in un oggetto richiamato periodicamente, come si comporta? Quanto dura?

Come dicevo, il crash avviene ogni 2 o 3 settimane e sembra sia imputabile a questo codice o qualcosa che avviene nello stesso task.

Grazie a tutti per il preziosissimo aiuto!!!

High Flying
Sottovento
__________________
In God we trust; all others bring data
sottovento è offline   Rispondi citando il messaggio o parte di esso
Old 11-06-2006, 16:49   #13
repne scasb
Bannato
 
Iscritto dal: Feb 2003
Messaggi: 947
Si tratta di un comportamento del compilatore oltremodo "subdolo", dovuto ad un eccessiva ottimizzazione del medesimo. Alcuni compilatori assumono che una costante stringa, indipendentemente dal punto del codice dove si trova sia valutata come un array di char "globale". Si analizzi la seguente funzione:

Codice:
char * funzione()

{
    return "Stringa";
}
Il corrispettivo in assembly per x86/32 sara':

Codice:
    .... <<-- Codice specifico dipendente dal sistema operativo

    push ebx
    push ecx
    push edx
    push esi
    push edi
    push ebp
    mov ebp,esp
    sub esp,4h
    mov [ebp-4h],00408004 <<-- valore arbitrario
    mov eax,[ebp-4h]
    mov esp,ebp
    pop ebp
    pop edi
    pop esi
    pop edx
    pop ecx
    pop ebx
    ret
Cio' che e' importante notare e' il valore '00408004'. Ossia, si tratta di un offset assoluto che e' invariante rispetto al codice eseguibile (il compilatore, in generale, non e' in grado di generare codice automodificante); se la stringa "Stringa" fosse aleatoria, il corrispondente codice assembly x86/32 del compilatore sarebbe stato:

Codice:
    .... <<-- Codice specifico dipendente dal sistema operativo

    push ebx
    push ecx
    push edx
    push esi
    push edi
    push ebp
    mov ebp,esp
    sub esp,4h
    mov eax,[_const_001]
    mov [ebp-4h],eax
    mov eax,[ebp-4h]
    mov esp,ebp
    pop ebp
    pop edi
    pop esi
    pop edx
    pop ecx
    pop ebx
    ret
Ossia l'indirizzo di memoria che contiene il punto iniziale della stringa "Stringa" non e' un offset inmodificabile, ma e' contenuto in una locazione di memoria essa stessa variabile (_const_001). Al contrario, l'uso di un offset nel codice assembly dimostra che in effetti la stringa "Stringa" permane in memoria immultabile per l'intero codice. La stringa "Stringa" si trova e permane all'indirizzo 00408004.

Dove puo' scaturire allora l'errore? L'errore nasce da un'ulteriore ottimizzazione di alcuni "balordi" compilatori, che applicano il seguente principio: costanti stringa "uguali" occupano medesime porzioni di memoria. Ad esempio:

Codice:
#include <stdio.h>

char * funzione(void);

void main(void)

{
    char *p="Stringa";
    char *q;

    p[0]='A';

    q=funzione();

    printf("%s",q);
}

char * funzione()

{
    return "Stringa";
}
Su alcuni "balordi" compilatori il risultato sara' la stanpa di: Atringa. Credo che l'errore possa essere questa...chiamiamola ottimizzazione ("Duplicate string merged").
repne scasb è offline   Rispondi citando il messaggio o parte di esso
Old 11-06-2006, 18:08   #14
crick_pitomba
Member
 
Iscritto dal: Oct 1999
Messaggi: 111
Quote:
Originariamente inviato da repne scasb
Si tratta di un comportamento del compilatore oltremodo "subdolo", dovuto ad un eccessiva ottimizzazione del medesimo. Alcuni compilatori assumono che una costante stringa, indipendentemente dal punto del codice dove si trova sia valutata come un array di char "globale". Si analizzi la seguente funzione:
considerazioni interessanti... e ho voluto provare

sulla mia versione, con un progetto applicazione console win32 con opzioni di default, sia

Codice:
  char *q;
    p[0]='A';
    q=funzione();
    printf("%s",q);
che
Codice:
char *p = "ciao";
p[0] = 'C';
mi danno un errore sul tentativo di modificare la stringa. A questo punto solo un manuale di c può risolvere l'arcano.

ho ripreso in mano il mio vecchio manuale di c e ho scoperto l'arcano: evidentemente troppo java mi aveva fatto arruginire il C-ervello :P

secondo il manuale (kelley/pohl),dichiarare

Codice:
char *p="prova";
significa creare un puntatore alla stringa costante "prova". Quindi immodificabile per definizione e qualsiasi cosa provo a fare su quella stringa, "correttamente", il programma va in crash.

se voglio un array modificabile di caratteri devo usare la sintassi

Codice:
char p[]="prova";
ovviamente in questo caso non posso fare

Codice:
char p[];
p="prova";
ed è il compilatore a fermarmi

Alla fine della storia il comportamento del compilatore risulta essere perfettamente coerente con la teoria...

Tornando al problema originale che avevi posto. per quanto detto sopra sia
Codice:
char *p= "pippo";
che

Codice:
char *p;
p="pippo";
sono valide e da quanto detto finora la cosa è più che lecita: sto parlando di un puntatore a caratteri (e non di stringhe) che può essere modificato a piacimento. è la stessa cosa che fare

Codice:
int i;
i=10;
i=20;
non è sbagliato, ma è sconsigliato farlo perchè potrebbe portare ad errori logici nel programma lasciare variabili non inizializzate...

Potrei avere bisogno di questo codice:
Codice:
char *p; //p è un puntatore non inizializzato
p="pippo"; //p viene fatto puntare alla stringa "pippo"
//...
p="paperino"; //p viene fatto puntare alla stringa "paperino"
e quindi quel tipo di assegnamento deve essere valido.

lavorando con la notazione
char p[]
non ho tutta questa flessibilità.

Questo per quanto riguarda le dichiarazioni e definizioni di puntatori a caratteri, diversamente questo tipo di codice:

Codice:
char *f(){
 return "pippo";
}

void main (){
char* p=f();
}
funziona per pura fortuna... tecnicamente quelle stringhe non dovrebbero esistere fuori dal loro scope e quello che le tiene in vita è una particolare implementazione del compilatore.

scusate l'eccessiva lunghezza :P
crick_pitomba è offline   Rispondi citando il messaggio o parte di esso
Old 11-06-2006, 18:59   #15
71104
Bannato
 
L'Avatar di 71104
 
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
Quote:
Originariamente inviato da andbin
Non ho ben capito in quale senso l'hai detto ma ... non sono né un super-esperto né un guru ...
comunque dicevo sul serio ^^
via non fare il modesto, hai dimostrato spesso una esperienza quantomeno non comune
71104 è offline   Rispondi citando il messaggio o parte di esso
Old 11-06-2006, 19:10   #16
71104
Bannato
 
L'Avatar di 71104
 
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
Quote:
Originariamente inviato da repne scasb
Codice:
char * funzione()

{
    return "Stringa";
}
Il corrispettivo in assembly per x86/32 sara':

Codice:
    .... <<-- Codice specifico dipendente dal sistema operativo

    push ebx
    push ecx
    push edx
    push esi
    push edi
    push ebp
    mov ebp,esp
    sub esp,4h
    mov [ebp-4h],00408004 <<-- valore arbitrario
    mov eax,[ebp-4h]
    mov esp,ebp
    pop ebp
    pop edi
    pop esi
    pop edx
    pop ecx
    pop ebx
    ret
veramente il mio compilatore (Microsoft, e l'Intel si comporta analoga) non salva i registri tra chiamate; inoltre il mov esp,ebp subito prima del ripristino del vecchio frame pointer se ho fatto bene i conti è inutile (infatti il mio compilatore non lo genera)

Quote:
Cio' che e' importante notare e' il valore '00408004'. Ossia, si tratta di un offset assoluto che e' invariante rispetto al codice eseguibile (il compilatore, in generale, non e' in grado di generare codice automodificante);
in quel punto metterà sicuramente un fixup, sfruttando così il "supporto del sistema operativo per codice automodificante"
(la rilocazione insomma )

Quote:
[...] Ossia l'indirizzo di memoria che contiene il punto iniziale della stringa "Stringa" non e' un offset inmodificabile, ma e' contenuto in una locazione di memoria essa stessa variabile (_const_001). Al contrario, l'uso di un offset nel codice assembly dimostra che in effetti la stringa "Stringa" permane in memoria immultabile per l'intero codice. La stringa "Stringa" si trova e permane all'indirizzo 00408004.
a meno di rilocazione del modulo naturalmente

Quote:
Dove puo' scaturire allora l'errore? L'errore nasce da un'ulteriore ottimizzazione di alcuni "balordi" compilatori, che applicano il seguente principio: costanti stringa "uguali" occupano medesime porzioni di memoria. Ad esempio:

Codice:
#include <stdio.h>

char * funzione(void);

void main(void)

{
    char *p="Stringa";
    char *q;

    p[0]='A';

    q=funzione();

    printf("%s",q);
}

char * funzione()

{
    return "Stringa";
}
Su alcuni "balordi" compilatori il risultato sara' la stanpa di: Atringa. Credo che l'errore possa essere questa...chiamiamola ottimizzazione ("Duplicate string merged").
un programma simile a runtime non può stampare quell'output su nessun compilatore a cui sia lecito attribuire questo nome: se il compilatore effettua quell'ottimizzazione vuol dire che la sezione contenente la stringa costante deve essere accessibile in sola lettura, quindi con la maggior parte dei compilatori esistenti il programma dovrebbe semplicemente crashare all'istruzione
Codice:
p[0]='A';
71104 è offline   Rispondi citando il messaggio o parte di esso
Old 11-06-2006, 21:24   #17
andbin
Senior Member
 
L'Avatar di andbin
 
Iscritto dal: Nov 2005
Città: TO
Messaggi: 5206
Quote:
Originariamente inviato da 71104
comunque dicevo sul serio ^^
Grazie.



Comunque volevo precisare una cosa sul codice che ho postato (il primo, quello senza VirtualProtect). L'ho compilato in modalità "Debug" e mi ha dato appunto l'errore di protezione. Ho provato solo ora a compilarlo in modalità "Release". In effetti questo codice:
Codice:
char *str = "hello";
str[0] = 'H';
funziona senza problemi in modalità "Release"!
Adesso, perché questo .... non lo so di preciso. Ho provato a guardare le differenze tra Debug e Release nelle proprietà del progetto per capire quale (se c'era) opzione che potesse influire su questo diverso comportamento ma non ho trovato nulla.

Il gcc su Linux invece è più coerente ... l'assegnazione crasha in qualunque condizione.
__________________
Andrea, SCJP 5 (91%) - SCWCD 5 (94%)
andbin è offline   Rispondi citando il messaggio o parte di esso
Old 12-06-2006, 21:29   #18
71104
Bannato
 
L'Avatar di 71104
 
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
Quote:
Originariamente inviato da andbin
Comunque volevo precisare una cosa sul codice che ho postato (il primo, quello senza VirtualProtect). L'ho compilato in modalità "Debug" e mi ha dato appunto l'errore di protezione. Ho provato solo ora a compilarlo in modalità "Release". In effetti questo codice:
Codice:
char *str = "hello";
str[0] = 'H';
funziona senza problemi in modalità "Release"!
Adesso, perché questo .... non lo so di preciso.
la variabile str era globale, ho indovinato? ^^
(hmm, no, non sembra che io abbia azzeccato visto che probabilmente le due righe di codice riportate erano consecutive, però io provo non si sa mai )

in caso avessi toppato: hai usato variabili globali in quel programma?

Ultima modifica di 71104 : 12-06-2006 alle 21:31.
71104 è offline   Rispondi citando il messaggio o parte di esso
Old 12-06-2006, 22:01   #19
andbin
Senior Member
 
L'Avatar di andbin
 
Iscritto dal: Nov 2005
Città: TO
Messaggi: 5206
Quote:
Originariamente inviato da 71104
la variabile str era globale, ho indovinato? ^^
(hmm, no, non sembra che io abbia azzeccato visto che probabilmente le due righe di codice riportate erano consecutive, però io provo non si sa mai )

in caso avessi toppato: hai usato variabili globali in quel programma?
No ... ho usato proprio il primo codice che avevo postato. Tutto era nel main ...
Comunque guarda ... io non starei a cercare l'ago nel pagliaio ... il VC++ sappiamo tutti com'è fatto ... Eppoi se andassi sempre a cercare le cose più strane .... non la finirei più.

L'altro giorno ho visto che il gcc ha l'opzione -fwritable-strings (che non ho mai usato). Indovinate fa??? Ma poi il man dice anche ... Writing into string constants is a very bad idea; "constants" should be constant.
Quindi perché complicarsi la vita cercando di scrivere su stringhe literal??
__________________
Andrea, SCJP 5 (91%) - SCWCD 5 (94%)
andbin è offline   Rispondi citando il messaggio o parte di esso
Old 13-06-2006, 01:34   #20
71104
Bannato
 
L'Avatar di 71104
 
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
Quote:
Originariamente inviato da andbin
Comunque guarda ... io non starei a cercare l'ago nel pagliaio ... il VC++ sappiamo tutti com'è fatto ...
manco per il cavolo invece... a parte che semmai dovresti parlare del compilatore, non dell'IDE, ma comunque entrambi sono tra i migliori esistenti nelle loro rispettive categorie, specialmente l'IDE.

ti spiego il ragionamento che ho fatto io circa le variabili globali, e come mai la stringa diventi magicamente da read-only a read-write cambiando le opzioni del compilatore: in modalità Release l'IDE setta automaticamente le opzioni (comunque modificabili a piacere) in modo tale che il programma sia ottimizzato al massimo, anche dal punto di vista della dimensione dell'eseguibile finale nonché della sua immagine caricata in memoria; di conseguenza quando il compilatore vede che hai usato una intera sezione .rdata (la cui dimensione ammonta come minimo a 4 kb) per soli 6 byte ("hello"), si chiede come mai sprecare 4090 bytes (se non sul disco quantomeno in RAM) piuttosto che mettere quella stringa assieme a tante altre variabili globali in una sezione .data che nota bene, non è read-only; in questo modo sfrutti i bytes di frammentazione interna della sezione .data (sempre a meno di non sforare il page bound ovviamente) piuttosto che creare un'altra frammentazione interna di 4090 bytes.

l'ipotesi della variabile globale mi era venuta in mente dal fatto che il ragionamento vale solo se effettivamente esiste una sezione .data, cioè se il programma di fatto usa variabili globali; ma ho toppato a indovinare perché anche se non ne hai usate tu, le usi comunque per forza senza saperlo visto che linki le librerie di runtime. che ci vuoi fare, ormai a causa di vari lavori che sto facendo sono abituato a ridefinire nei miei eseguibili il vero entry point e a rimuovere il runtime del compilatore tutte le volte


Quote:
Eppoi se andassi sempre a cercare le cose più strane .... non la finirei più.
scherzi?? è proprio con quelle cose che la mia cultura ha subito gli allargamenti più significativi
71104 è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


Sony WF-1000X M6: le cuffie in-ear di riferimento migliorano ancora Sony WF-1000X M6: le cuffie in-ear di riferiment...
Snowflake porta l'IA dove sono i dati, anche grazie a un accordo con OpenAI Snowflake porta l'IA dove sono i dati, anche gra...
Sistema Mesh Roamii BE Pro: il Wi-Fi 7 secondo MSI Sistema Mesh Roamii BE Pro: il Wi-Fi 7 secondo M...
Recensione HUAWEI Mate X7: un foldable ottimo, ma restano i soliti problemi Recensione HUAWEI Mate X7: un foldable ottimo, m...
Nioh 3: souls-like punitivo e Action RPG Nioh 3: souls-like punitivo e Action RPG
Le tute spaziali AxEMU di Axiom Space pe...
Dongfeng sfida la NATO: navi dalla Cina ...
5G Standalone per il mondo marittimo: Er...
Nova Lake-S: configurazioni fino a 52 co...
Baxi presenta la pompa di calore Alya E ...
PC ASUS e Acer vietati in Germania: il t...
Stellantis rilancia il diesel in Europa:...
Truffa per utenti Trezor e Ledger: lette...
Wi-Fi 7 conveniente: FRITZ! lancia 4630,...
La Formula 1 dei robot tagliaerba miglio...
Il nuovo gioco del creatore di God of Wa...
Grok arriva sulle Tesla in Europa: l'int...
Assassin's Creed IV: Black Flag Remake p...
Il padre di God of War attacca Sons...
È operativo il primo computer qua...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 06:14.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Served by www3v