Uso di reflection per invocare metodi interni

In un post precedente ho parlato dell’uso dell’attributo AllowPartiallyTrustedCallers a proposito della sicurezza applicata all’invocazione di metodi pubblici definiti all’interno di un assembly strong-named.  Rimanendo sempre sullo stesso tema, un altro attributo utile a “limitare” i possibili chiamanti di un determinato metodo è StrongNameIdentityPermissionAttribute, usato in questo modo:

[StrongNameIdentityPermissionAttribute(SecurityAction.LinkDemand, PublicKey = “public key”)]
public string MyMethod(string parameter) {}

La presenza di questo attributo permette la chiamata al metodo MyMethod dell’esempio solo al codice contenuto in un assembly firmato con strong name e che presenta la chiave pubblica specificata nell’attributo stesso. Qualsiasi altro codice che tentasse di invocare il metodo in questione provoca una eccezione del tipo SecurityException. Questa forma di sicurezza è la più affidabile a disposizione se vogliamo proteggere ad esempio metodi sensibili dall’invocazione da parte di codice maligno. Se invece il metodo in questione non è invocato dall’esterno dell’assembly, in altre parole non è public, potremmo pensare che basterebbe limitare il suo ambito di visibilità (es.: private, internal in C# oppure friend in VB.NET) per renderlo sicuro da chiamate da parte di codice non affidabile. Putroppo questa convinzione è errata, poichè attraverso l’uso delle tecniche di reflection può essere invocato qualsiasi metodo con qualsiasi ambito di visibilità, quindi anche i metodi marcati come internal o private. Infatti, utilizzando il tool Reflector oppure semplicemente ildasm è possibile leggere la firma di metodi con qualsiasi visibilità (quindi public, private, protected ed internal). Se il metodo MyMethod fosse “internal”, conoscendo la sua firma è possibile invocarlo da un altro assembly via reflection in questo modo:

object x = Activator.CreateInstanceFrom(“MyAssembly.dll”, “MyAssembly.MyNamespace”).Unwrap();
string result = x.GetType().InvokeMember(“MyMethod”, System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.Instance  
      | System.Reflection.BindingFlags.NonPublic, null, x, new object[] { “string parameter” }) as string;

bypassando quindi la protezione imposta dal livello di visibilità.

Da notare che richiamare un metodo non pubblico attraverso reflection richiede il permesso ReflectionPermission, impostabile attraverso l’uso dell’attributo ReflectionPermissionAttribute (in modo dichiarativo), oppure in modo programmatico.

In assenza di questo permesso è possibile invocare via reflection solo i metodi pubblici.

String intern pool

L’Intern pool, di cui non è la prima volta che ne parlo, è un hashtable mantenuto internamente dal CLR contenente stringhe generalmente usate per memorizzare valori costanti. In questo hashtable sono memorizzate le costanti stringa a livello di compilazione ed ogni stringa aggiunta esplicitamente attraverso l’utilizzo del metodo string.Intern, il quale aggiunge una stringa nell’intern pool (quindi nell’hashtable) e ne ritorna il riferimento se la stessa non è già presente, in caso contrario  ritorna sempicemente il riferimento ad essa. In questo modo è garantito che se due stringhe (o più) contengono gli stessi valori letterali sarà utilizzato (e quindi sarà presente in memoria) un unico riferimento, con evidente risparmio di risorse. Oltre a questo metodo, il metodo string.IsInterned ritorna il riferimento alla stringa nell’intern pool se presente, null in caso contrario.

L’intern pool è utile in opportuni scenari, ma ha un grosso svantaggio: poichè ogni stringa memorizzata nel pool è mantenuta all’interno di un hashtable interno del CLR, ne consegue che ogni stringa risulterà sempre raggiungibile dall’applicazione e quindi sopravviverà ad ogni garbage collector (poichè l’hashtable ne mantiene un riferimento). L’hashtable (e le stringhe in esso memorizzate) sarà distrutto e la memoria occupata reclamata solo quando il relativo appDomain (o processo) terminerà.

Come già detto, tutte le stringhe costanti sono inserite nell’intern pool automaticamente e quindi la memoria occupata non sarà reclamata fino a che il processo termina.  Questo comportamento è dimostrato dal seguente codice:

string a = “teststring”;
string b = “teststring”;
string x = string.IsInterned(a);
string y = string.IsInterned(b);
if (x != null)
    Console.WriteLine(“string a is interned”);
if (y != null)
    Console.WriteLine(“string b is interned”);
Console.WriteLine(object.ReferenceEquals(a,b));

L’output prodotto è il seguente:

string a in interned
string b is interned
true

Se questo comportamento non è quello desiderato è possibile utilizzare l’attributo a livello di assembly CompilationRelaxationsAttribute (namespace System.Runtime.CompilerServices), il quale permette disabilitare l’utilizzo dell’intern pool di stringhe da parte dell’assembly in cui l’attributo è definito, in questo modo:

[assembly: CompilationRelaxations(CompilationRelaxations.NoStringInterning)]

Applicando questo attributo sarebbe lecito aspettarsi che l’intern pool di stringhe non sia più gestito. Invece non è così, nonostante la documentazione MSDN affermi il contrario. Sembra che questo attributo non abbia alcun effetto pratico se non negli assembly precompilati in codice nativo con l’utility NGEN. In altre parole, inserendo o non inserendo l’attributo, l’intern pool è comunque gestito dal CLR, a meno che non si precompili l’assembly con NGEN.

Come controprova di quanto affermato è possibile eseguire il codice sopraindicato con o senza l’attributo CompilationRelaxations. L’output sarà in ogni caso identico, e dimostrerà che le 2 stringhe sono inserite nell’intern pool.

Mi piacerebbe conoscere pareri di eventuali altri sviluppatori che hanno già riscontrato questo comportamento.

TechEd 2007 sto arrivando (lo spero)

Anche quest’anno parto con lo stesso obiettivo ben preciso: assistere ad una conferenza Microsoft oltreoceano.

L’obiettivo è puntato sul TechEd 2007 che si terrà in quel di Orlando, Florida, dal 4 al 8 Giugno prossimi. Non mi faccio troppe illusioni perchè la mia attività (frenetica) di consulente mi ha sempre impedito per un motivo o per l’altro di assistere in passato ad altre conferenze simili.

Comunque, prima o poi l’occasione capita, e non me la lascerò certo sfuggire . Approfitto di questo post per estendere l’invito ad assistere al TechEd 2007 a tutti coloro che fossero interessati a partecipare, ma che, magari sono restii ad andare da soli . Quindi chiunque voglia farsi un viaggetto in Florida in occasione del TechEd 2007 può lasciare un commento a questo post oppure attraverso il form contact può inviarmi il proprio indirizzo mail o MSN, e sarà da me ricontattato.

Statistiche in ADO .NET 2.0

In ADO .NET 2.0 è possibile programmaticamente ottenere delle informazioni statistiche circa l’uso di una connessione ad un database. Bastano infatti solo 2 righe di codice:

connSQL.StatisticsEnabled = true;
System.Collections.IDictionary statsDict = connSQL.RetrieveStatistics();

per ottenere un dictionary di valori statistici validi nel momento in cui il metodo RetrieveStatistics() è invocato.
Tratto dalla documentazione MSDN, ecco un elenco (parziale) dei valori statistici più interessanti:

NetworkServerTime

Restituisce il tempo cumulativo atteso dal provider prima di ricevere una risposta dal database server, a partire dal momento in cui le statistiche sono abilitate.

PreparedExecs

Restituisce il numero dei comandi precompilati eseguiti, a partire dal momento in cui le statistiche sono abilitate.

Prepares

Restituisce il numero delle istruzioni precompilate eseguite, a partire dal momento in cui le statistiche sono abilitate.

SelectCount

Restituisce il numero delle istruzioni SELECT eseguite, a partire dal momento in cui le statistiche sono abilitate, incluse le istruzioni FETCH usate per leggere le righe da un cursore; il conteggio delle SELECT è aggiornato quando viene raggiunta la fine di un SqlDataReader

SelectRows

Ritorna il numero delle righe interessate, a partire dal momento in cui le statistiche sono abilitate. Il conteggio comprende tutte le righe generate da istruzioni SQL, anche se non utilizzate dal chiamante, ad esempio eventuali righe derivanti da un data reader chiuso prima di leggere l’intero resultset oppure le righe di un cursore.

ServerRoundtrips

Ritorna il numero di volte in cui viene inviato un comando al server ed attesa la conseguente risposta, a partire dal momento in cui le statistiche sono abilitate.

Transactions

Restituisce il numero delle transazioni utente iniziate, a partire dal momento in cui le statistiche sono abilitatea prescindere se andate a buon fine o no. In caso di auto commit impostato su on ogni comando è considerato una transazione.

UnpreparedExecs

Ritorna il numero delle istruzioni non compilate eseguite, a partire dal momento in cui le statistiche sono abilitate.

Curiosando il metodo RetrieveStatistics() con il tool Reflector si nota che esso utilizza una classe interna dell’assembly System.Data, precisamente SqlStatistics, marcata appunto come “internal sealed” (C#), oppure “Friend NotInheritable” (Visual Basic .NET). Quindi la suddetta classe non è nè visibile dall’esterno dell’assembly System.Data nè tantomeno ereditabile.

Taggato !!

Speravo di farla franca ma l’amico Mighell ha pensato bene di taggarmi ! Quindi adesso tocca a me: ecco le 5 cose che pochissime persone (forse nessuna…) conosce di me:

1) Ho tante passioni che non riesco a vivere come vorrei causa mancanza di tempo (chiamateli hobby….) e sono, in ordine sparso: astronomia, astrofisica, fisica quantistica, scacchi (il mio sogno è stato sempre battermi con l”International Woman Grandmaster Alexandra Kosteniuk, senza però che pensate a male ), tecnologia in generale. Insomma, roba pesante, e qui mi fermo perchè altrimenti divento prolisso! E’ chiaro che sono sempre stato attratto dalle cose complesse….il primo linguaggio di programmazione che ho affrontato sul serio è stato il C.

2) All’età di 5-6 anni ho rischiato seriamente di morire bevendomi, a causa della mia curiosità già supersviluppata, nientepopodimeno che …..la varechina ! Mi ha salvato una immediata lavanda gastrica (fortunatamente l’ospedale era giusto di fronte a casa mia…)

3) Il mio più grande cruccio è quello di non aver affrontato sul serio la scuola (anche se sono riuscito comunque a diplomarmi), e soprattutto di non aver intrapreso gli studi universitari (non è mai troppo tardi direbbe qualcuno, ma…)

4) Adoro la musica rock-blues e la chitarra elettrica; la folgorazione è avvenuta all’età di 15-16 anni ascoltando i mitici Led Zeppelin, e la musica dei Doors

5) Ho 4 nipotini a cui voglio un mondo di bene; uno in particolare, si chiama Alessandro, mi somiglia tantissimo, in tutti i sensi, è come se vedessi me stesso allo specchio quando avevo 8-9 anni.

E adesso, tagghiamo, tagghiamo, anche se sono arrivato tardi e la lista si è alquanto ristretta: Francesco Quaratino, Gianluca Cannalire, Marco Russo, Vito Carella, Antonello Tesoro