Domanda

In una risposta per la sua domanda polemica, Mash ha dimostrato che non è necessario il "rischio" di parole chiave per leggere e scrivere direttamente il byte di qualsiasi .NET istanza di oggetto.È possibile dichiarare le seguenti tipologie:

   [StructLayout(LayoutKind.Explicit)]
   struct MemoryAccess
   {

      [FieldOffset(0)]
      public object Object;

      [FieldOffset(0)]
      public TopBytes Bytes;
   }

   class TopBytes
   {
      public byte b0;
      public byte b1;
      public byte b2;
      public byte b3;
      public byte b4;
      public byte b5;
      public byte b6;
      public byte b7;
      public byte b8;
      public byte b9;
      public byte b10;
      public byte b11;
      public byte b12;
      public byte b13;
      public byte b14;
      public byte b15;
   }

E poi si possono fare cose come il cambio di un "immutabili", string.Il seguente codice stampato "bar" sulla mia macchina:

 string foo = "foo";
 MemoryAccess mem = new MemoryAccess();
 mem.Object = foo;
 mem.Bytes.b8 = (byte)'b';
 mem.Bytes.b10 = (byte)'a';
 mem.Bytes.b12 = (byte)'r';
 Console.WriteLine(foo);

È anche possibile attivare un Tipo accessviolationexception corrompendo i riferimenti dell'oggetto con la stessa tecnica.

Domanda:Ho pensato che (in puro C# codice gestito) il pericoloso parola chiave era necessario fare cose come questa.Perché non è necessario qui? Questo significa che pure gestito "sicuro" codice non è davvero al sicuro?

È stato utile?

Soluzione

OK, che è brutto ... i pericoli connessi all'uso di un sindacato. Che può funzionare, ma non è una buona idea - Credo che avrei paragonerei alla riflessione (dove si può fare la maggior parte delle cose). Sarei curioso di vedere se questo funziona in un ambiente di accesso vincolato - in caso affermativo, può rappresentare un problema più grande ...


Ho appena provato senza il flag "Full Trust", e il runtime lo respinge:

  

Impossibile caricare il tipo 'MemoryAccess'   dall'assemblaggio 'ConsoleApplication4,   Version = 1.0.0.0, Culture = neutral,   PublicKeyToken = null' perché gli oggetti   sovrapposti all'offset 0 e   montaggio deve essere verificabile.

E per avere questo flag, è già bisogno di fiducia elevato - in modo da poter già fare le cose più brutte. Le stringhe sono un caso un po 'diverso, perché non sono normali oggetti .NET - ma ci sono altri esempi di modi per mutare loro - l'approccio "unione" è interessante, però. Per un altro modo hacky (con abbastanza fiducia):

string orig = "abc   ", copy = orig;
typeof(string).GetMethod("AppendInPlace",
    BindingFlags.NonPublic | BindingFlags.Instance,
    null, new Type[] { typeof(string), typeof(int) }, null)
    .Invoke(orig, new object[] { "def", 3 });
Console.WriteLine(copy); // note we didn't touch "copy", so we have
                         // mutated the same reference

Altri suggerimenti

Ops, ho confuso unsafe con fixed.Ecco una versione corretta:

Il motivo per cui il codice di esempio non richiedono la codifica con il unsafe la parola chiave è che non contengono puntatori (vedi sotto preventivo per perché questo è considerato pericoloso).Si è del tutto corretto:"sicuro" potrebbe essere meglio definito di run-time "amichevole".Per ulteriori informazioni su questo argomento, vi rimando a Don Scatola e Chris Vende Essenziale .NET

Per citare MSDN,

In common language runtime (CLR), il codice unsafe viene indicato come codice non verificabile.Non sicuro di codice in C# non è necessariamente pericolosa;è il codice di cui per la sicurezza non può essere verificato dal CLR.CLR quindi eseguire solo codice unsafe se è in un assembly completamente attendibile.Se si utilizza il codice unsafe, è il tuo responsabilità per garantire che il vostro il codice non presenta rischi per la sicurezza o errori di puntatore.

La differenza tra fisso e pericoloso è che arresti fissi CLR di cose in movimento in memoria, in modo che le cose al di fuori del run-time può accedere in modo sicuro, mentre non sicuri è esattamente il problema opposto:mentre il CLR è in grado di garantire la risoluzione corretta per un dotnet di riferimento, non può farlo per un puntatore.Si possono ricordare i vari Microsofties andando in su come un riferimento, non un puntatore, e questo è il motivo per cui fanno un polverone su una sottile distinzione.

Siete ancora optando fuori del bit 'gestita'. V'è il presupposto di fondo che, se si può fare che poi si sa cosa si sta facendo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top