Newsgroup: it.comp.programmare.win32
Titolo: Allineamento membri strutture a 1 byte

Appena metto questa opzione nel Visual Studio .NET il mio programma va in
crash!
Se metto l'allineamento predefinito non accade nulla e funziona
perfettamente.
Ho debuggato e ho scoperto che il problema non è sempre lo stesso, bensì
variabile!!!
Mi spiego meglio:
In una mia classe chiamo la funzione VirtualAlloc che mi restituisce
l'indirizzo della memoria appena allocata. Quando ho l'allineamento
predefinito tutto ok, se metto 1 byte la funzione mi restituisce 0 che è
segnalato come errore.
Ho quindi aggiunto una nuova istruzione all'allocazione "int errore =
GetLastError();" per vedere che errore mi dà e, come per magia, VirtualAlloc
non mi restituisce mai più 0!!!
Non è tutto, appena esce dal costruttore (è lui che chiama VirtualAlloc), il
puntatore utilizzato dalla VirtualAlloc viene azzerato senza che faccia
nulla!!!
Ho controllato passo passo e fino a quando non esce il puntatore ha il suo
bell'indirizzo.
Ho utilizzato la classe in un altro progetto con allineamento a 1 byte e
funziona benissimo!!!
Sto uscendo pazzo, non riesco a capire dov'è il bug!
Grazie a tutti
Giovanni.

 Giovanni.
HTH
C:\>iao Angelo
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG


E' un azzardo effettuare l'allineamento ad un byte...
ma perchè non usi quello predefinito? 


Guarda, ti porto esattamente dove mi dà errore:
ho una classe BASE dove nel costruttore chiamo questa virtual alloc (oppure
malloc... non mi cambia niente).
La classe BASE però è virtuale quindi ho una class
class DER: public BASE
La class DER ha una variabile membro che è di tipo class MYCLASS.
Nel cpp principale, dove c'è la funzione WinMain, dichiaro come variabile
globale una variabile di tipo DER.
Faccio il debug:
dichiaro la variabile DER ed entra nel suo costruttore che a sua volta
chiama i costruttori della classe BASE e di MYCLASS in questo ordine.
Chiama il costruttore di BASE e alloca spazio e mi restituisce il puntatore.
Appena esce dal costruttore di BASE il puntatore contiene ancora
l'indirizzo. Nel momento in cui entra nel costruttore di MYCLASS, senza che
faccia nessun operazione su vettori o altri puntatori, il mio puntatore
diventa nullo! E io quì stavo dando fuoco al pc!!!!
Non riesco a spiegarmelo in nessun modo...
Se hai qualche idea in merito o qualche dubbio dimmelo!
Grazie
Giovanni.

 ha scritto nel messaggio
news:2qvkifF...@uni-berlin.de...

Perchè devo trasmettere queste strutture via rete e quindi ho bisogno delle
dimensioni minime possibili...in una struttura c'è un char e me lo fa
occupare 4 byte!!! La struttura non mi consente nemmeno di dichiarare le
variabili in modo che si trovano già allineate.
E poi cmq sia perchè non dovrebbe funzionare il mio programma?
Grazie
Giovanni.

 E poi cmq sia perchè non dovrebbe funzionare il mio programma?
Beh...hai ragione però costringi il compilatore a operare in modo molto
anomalo...prova almeno un allinemento meno drastico...2 byte.
più si riduce l'allineamento e più si presuppone che conosci in dettaglio
come funziona un compilatore!! 

Ciao, AlterX!
Il giorno 17/09/2004 alle ore 17:17 hai scritto:
 A> Beh...hai ragione però costringi il compilatore a operare in modo molto
 A> anomalo...prova almeno un allinemento meno drastico...2 byte.
 A> più si riduce l'allineamento e più si presuppone che conosci in
 A> dettaglio come funziona un compilatore!!
Ah questa poi... c'e' un limite a tutto...
L'allineamento delle strutture dati serve solamente per ottimizzare
l'accesso alla memoria da parte del processore ed e' una prerogativa dei
processori x86 che sono storicamente piu' lenti (se "lento" ha ancora un
significato con i processori a oltre 3 GHz) quando accedono ad una locazione
di memoria avente un indirizzo con i due bit meno significativi diversi da
zero.
Il compilatore e il suo funzionamento c'entrano ben poco, assumendo che il
produttore abbia testato il suo prodotto, beninteso (trattandosi di
Microsoft ho anche qualche dubbio).
Il problema descritto puo' essere dovuto ad una moltitudine di fattori ma il
piu' comune e' senza dubbio qualche buffer overflow che prima andava a
pasticciare con locazioni di memoria allocate per consentire l'allineamento
dei dati (e quindi virtualmente innocue) mentre adesso la memoria che va a
sovrascrivere e' memoria vera, visto che non ci sono piu' i "buchi"
dell'allineamento. Altra causa e' la dimensione delle strutture allocate
codificata nel sorgente (quando si cambia l'allineamento, 99 volte su 100
cambia anche il sizeof di una struttura) che causano buffer overflow e
puntatori a ramengo.
Il programma in questione se funziona con l'allineamento predefinito e'
comunque una bomba a tempo con il timer guasto: puo' funzionare per 10 anni
senza dare problemi e improvvisamente crashare all'inverosimile provocando
danni inimmaginabili.
Un rimedio parziale potrebbe essere quello di limitare l'allinamento al byte
solo per le strutture che devono obbligatoriamente avere questa
caratteristica, utilizzando la direttiva #pragma pack(1) subito prima della
dichiarazione:
#pragma pack(1)
struct _dati {
[...]
};
Non so se quel coso .net supporta ancora questa direttiva, nel caso cambia
compilatore.
Bye
-- 
Jedi Saying:   Try not. Do, or do not. There is no try.
MaccaSoft:     
http://www.maccasoft.com
EclipseTrader: 
http://eclipsetrader.sourceforge.net

 puntatori a ramengo.
E se questi non sono aspetti di come il compilatore tratta le strutture e la 
memoria... 

 Bye
Questa direttiva e' supportata dal C++ di Visual Studio .NET. Anche il C#
(sempre Visual Studio .NET) supporta questa opzione, ovviamente la
direttiva non si chiama piu' #pragma, ma ora non mi ricordo.
Devo ancora verificare se il framework .NET Mono supporta questa opzione,
ma immagino in qualche modo di si, altrimenti la lettura da file di dati
usando strutture allineate al byte obbligherebbe a operazioni un po'
"macchinose", per non parlare della portabilita' tra windows e linux dei
binari .NET.
Ciauz.

 Se hai qualche idea in merito o qualche dubbio dimmelo!
Beh, io posso provare a darti qualche suggerimento:
1) sei sicuro che il puntatore che controlli in fase di debug sia proprio
quello in questione e non un suo omonimo appartenente a MYCLASS ? (no,
perché a volte ci casco pure io...)
2) il programma è proprio così semplice oppure è più complicato e nel post
hai sintetizzato? perché nella seconda delle ipotesi potrebbe benissimo
trattarsi di buffer overflow del costruttore di DER o di BASE, oppure di
un altro thread se usi thread multipli; prova a mettere un watch al
puntatore.
3) quando il pc mi fa lo stronzo in questa maniera, io di solito passo a
rimedi estremi: creo una copia di tutto il progetto duplicando la
directory che lo contiene, poi (lavorando sulla copia) tolgo pezzi di
codice ad uno ad uno finché alla fine, rimasto solo il pezzo in questione,
l'errore non si verifica più, e se ancora si verifica passo ad analizzare
l'assembly; in un modo o nell'altro, questi sistemi mi hanno sempre
funzionato ;) ;)
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

Dimenticavo di augurarti buona fortuna - scusate lo spam :PP


Sempre in merito al problema vi fornisco quest'altra curiosità:
cambiando il codice cambia l'errore che mi dà!
Adesso però è successa una cosa a dir poco sconvolgente.
Ho questo pezzo di codice:
for (i =0; i < MAX; i++)
  if (Pippo[i].Active)
  { FaiQuelloKeDeviFare;
     ....
  }
Mi dava un errore all'interno del blocco if e ho visto che una variabile era
sporca.
Ho quindi inserito un breakpoint all'interno dell'if e, magia delle magie,
il programma si blocca al breakpoint ad un certo valore di i (corretto),
controllo se Pippo[i].Active è uguale a 1 e, NON lo è! E' zero!!! Come ha
fatto ad entrare in quel ciclo (e raggiungere quindi il break inserito) ????
Sto controllando tutto e tra poco proverò anche a fare un altro progetto e
tagliare i pezzi di codice, ma questa quì non riesco a spiegarmela, a meno
che non vado a finire nell'area del codice e lo modifico in modo tale da
saltarmi a quell'istruzione li...mi sembra quasi impossibile che avvenga
questa casualità!!!
Grazie
Giovanni.

Ragazzi ho risolto...
...non so perchè, ma quel ca**one del VisualC quando ho impostato nelle
proprietà del progetto l'allineamento a 1 byte, per alcuni moduli non ha
reimpostato le proprietà (forse avevo provato a cambiarle...non ricordo),
quindi in alcuni trattava le strutture in un modo e in altri in un altro.
Grazie a tutti per le risposte
Giovanni.
PS
Adesso si che sono felice :-) ...cavolo, è dura trovare i bug quando ci
sono, figuratevi quando non ci sono!!! :-)

 Sto uscendo pazzo, non riesco a capire dov'è il bug!
Dalla documentazione MSDN:
The different default setting for Win32 can impact your source code by 
changing the offsets of some structure members. Examine your code 
closely to see whether you have hard-coded these offsets, or whether 
your code makes assumptions based on a certain default pack size.
Fermo restando che non oso pensare perchè ti poni il problema delle 
dimensioni durante il trasferimento. Se trasferisci il blocco di memoria 
della classe/struttura spero ti renda conto che è profondamente error 
prone. Giusto questo episodio ti dovrebbe far pensare che il 
destinatario *non sa* quello che riceve e con ogni probabilità non 
riceve quello che vuole.

 come funziona un compilatore!! 
Non c'è bisogno di sapere nulla. Il compilatore usa di default un 
allineamento a 4 byte per la semplice ragione che ciò favorisce 
l'indirizzamento in un sistema, guardacaso, a 32 bit. Allineando le 
strutture al byte il compilatore non opera in modo "anomalo"... 
semplicemente succede che a runtime il sistema è penalizzato nelle 
performaces.

 ha scritto nel messaggio
news:joH2d.268552$OR2.12...@news3.tin.it...

Non ho ben capito quest'ultima frase, cmq sia il destinatario sa
perfettamente ciò che deve ricevere e in quale struttura deve inserire le
informazioni (che è la stessa utilizzata per l'invio).
Ciao
Giovanni.

 informazioni (che è la stessa utilizzata per l'invio).
Facciamo un esempio pratico, anzi due:
Supponiamo che il programma destinatario usi un allineamento diverso 
delle strutture. Riceve il blocco di byte, li mette in memoria pensando 
che sia l'immagine di quella struttura ma in realtà è un immagine 
diversa. Se va bene da i numeri del lotto.
Seconda ipotesi, che probabilmente non ti interessa ma è giusto dirla. 
Supponiamo che dall'altra parte ci sia un programma che gira su un'altro 
sistema, se non sbaglio basta anche java. Riceve una struttura binaria 
ma il suo contenuto lo interpreta con un byte order diverso, in pratica 
non ci capisce nulla.
Lasciando momentaneamente da parte il secondo caso, il primo è già 
dimostrato dai fatti che è un problema. La soluzione è che devi 
implementare correttamente la serializzazione degli oggetti, evitando 
così anche il problema di trasferire byte in più o in meno dovuti al 
diverso allineamento delle strutture.

 ha scritto nel messaggio
news:ghX2d.271292$OR2.12...@news3.tin.it...

Ho capito cosa intendi, ed effettivamente lo trovo giusto, solo che cmq non
è il mio caso perchè sia il server, che l'interfaccia client è scritta da me
nel medesimo modo. Quindi non ci potrebbero mai essere problemi di
incompatibilità. Se invece qualcun'altro dovesse utilizzare il mio codice
hai ragione.
Cmq sia, secondo te dovrei andare a scrivere nel buffer di invio manualmente
ogni campo di ogni struttura per evitare il problema dell'allineamento?
...non so, non mi sembra una soluzione molto elegante, anche se, a parte
indicare l'allineamento a 1 byte, è l'unica che immagino.
Grazie di tutto
Giovanni.

 hai ragione.
Forse ti sfugge che i programmi (specie quando funzionano) campano
molto piu' di quanto dovrebbero.
Fra n anni la patata bollente che tu lasci potrebbe passare ad altro
programmatore e il tuo programma potrebbe essere molto impotrante per
l'utilizzatore.
Tralasciando che le porcherie che sono permesse oggi da un S.O.
potrebbero non esserti piu' concesse domani. Programmare con un minimo
di criterio e' un investimento per il futuro, sioa per te che per il
tuo utente.


 indicare l'allineamento a 1 byte, è l'unica che immagino.
Se non trovi elegante questa cosa dire allora di tutti i protocolli 
internet che trasferiscono le informazioni in testo?

 internet che trasferiscono le informazioni in testo?
Indipendentemente dal motivo per cui spediscono tutto in testo (che non e'
cosi' stupido come puo' sembrare), parafrasando un famoso proverbio: "due
schifezze non fanno una cosa bella".
Ciauz.

 cosi' stupido come puo' sembrare), 
Infatti non mi pare di averlo considerato stupido.

 Infatti non mi pare di averlo considerato stupido.
ho abusato in dialettica, volevo solo precisare che che c'e' una
ragione per cui e' tutto trasferito in formato testo, anche se non e'
elegante o pratico.
Ciauz.

 elegante o pratico.
E allora dimmela, perché io non l'ho mai capita! :PP
Non ho lavorato molto spesso coi sockets, ma le volte che li ho utilizzati
e che dovevo realizzare io sia il client che il server, ho sempre spedito
tutto direttamente in formato "binario" per così dire, cioè non in formato
testo, e non ho mai avuto problemi. Probabilmente ho sbagliato per
questioni di principio a me non chiare, ma a parte l'eleganza, a me
sembrava molto più pratico come facevo io...


 sembrava molto più pratico come facevo io...
Una volta esistevano (forse ancora adesso) i server VAX (almeno mi
sembra fossero quelli) che lavoravano con
byte di 7 bit, e non 8, ragion per cui gli unici byte che era "sicuro"
far passare in rete senza fra crashare qualche server erano i primi 127,
gli ASCII "stampabili".
Sul perche' certi protocolli (tipo SMTP, POP o HTTP) utilizzino una
"sintassi" cosi' complicata (vedi ad esempio com'e' composto l'header
di un messaggio di posta[RFC 822] o lo standard MIME) immagino sia dovuto
ad una "moda" di allora :-P
Questa e' la mia spiegazione, ma prendila con le pinze perche' e' il
"merge" di un po' di roba che ho letto.
Ciauz.

 sembrava molto piů pratico come facevo io...
Per trasferire dati a 7 bit, che oggi credo proprio significhi solo 
aumentare il volume dei dati.
Se trasferisci in formato binario stai attento quando trasferisci degli 
interi. Ricorda che l'ordine dei byte non č uguale in tutti i sistemi, 
windows (x86) adotta un sistema little endian (i bite meno significativi 
in fondo) mentre molti altri sistemi adottano un sistema big endian (i 
byte piů significativi in fondo). Per convenzione, nelle trasmissioni la 
parte meno significativa deve essere trasmessa per prima.

 questioni di principio a me non chiare, ma a parte l'eleganza, a me


Dunque è essenzialmente storico il motivo per cui esistono tanti
protocolli in forma di testo, quindi oggi non è più un problema inviare
tutto in formati binari, no? Tantopiù che in tal modo le trasmissioni
diventano più veloci e la vita diventa molto più difficile per chi deve
intercettare/spiare, giusto?


 sotto *nix, Windows, MacOS, ecc...).
Che la direttiva "#pragma" sia usatissima non lo metto in dubbio, che 
nello specifico venga usata la direttiva "#pragma pack" ho invece dei 
seri dubbi. Specialmente per lo scopo di cui sopra (che IMHO ha un forte 
sapore di accrocchio).

 sistemi precisi.
Come due?

 intercettare/spiare, giusto?
No, questo non c'entra nulla. Un computer non č un uomo, non gli č piů 
facile leggere un testo ASCII rispetto ad un codice binario.

 facile leggere un testo ASCII rispetto ad un codice binario.
Appunto, io mi riferivo a persone che utilizzano degli strumenti per
intercettare/spiare; prendi MSN Messenger ad esempio: il suo protocollo,
rigorosamente ASCII, è stato sgamato in cinque minuti (e tutto sommato M$
non ne è neanche tanto dispiaciuta: se il suo network si espande tanto
meglio... ;), mentre se fosse stato in formato binario la cosa sarebbe
stata un attimino più complessa: i messaggi di testo sarebbero stati
ancora in chiaro, ma dedurre il resto sarebbe stato più difficile.
