2009-04-27 10 views
19

In an answer zu seinem eigenen controversial question, Mash hat veranschaulicht, dass Sie nicht das Schlüsselwort "unsafe" zum Lesen und Schreiben direkt auf die Bytes von einer beliebigen .NET-Objektinstanz benötigen. Sie können die folgenden Typen deklarieren:Warum funktioniert dieser Code ohne das unsichere Schlüsselwort?

[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; 
    } 

Und dann können Sie Dinge wie eine "unveränderliche" Zeichenfolge ändern. Der folgende Code druckt „bar“ auf meinem Rechner:

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); 

Sie können auch eine AccessViolationException auslösen, indem Objektreferenzen mit der gleichen Technik korrumpieren.

Frage: Ich dachte, dass (in reinem verwaltetem C# -Code) das Schlüsselwort unsafe notwendig war, um solche Dinge zu tun. Warum ist es hier nicht nötig? Bedeutet dies, dass reiner verwalteter "sicherer" Code überhaupt nicht sicher ist?

+0

Danke für die Änderung einer Art, die gleiche Frage zu stellen. Vorheriger Thread wurde überflammt. – Mash

+0

@Mash: Kein Problem. Hoffentlich wird das mehr auf Ihre ursprüngliche Frage lenken. –

+0

@wcoenen: Es ist nicht wirklich wichtig, auch wenn ich darüber nachdenke - meine Frage ist Gemeinschaftsinhalt und ich verdiene nichts daraus. Das einzig Wichtige ist eine positive Diskussion. Und scheint Ihre Frage sieht besser aus :) – Mash

Antwort

12

OK, das ist unangenehm ... die Gefahren einer Union. Das mag funktionieren, ist aber keine sehr gute Idee - ich denke, ich vergleiche es mit Reflektion (wo man die meisten Dinge machen kann). Ich würde mich interessieren zu sehen, ob dies in einer eingeschränkten Zugriffsumgebung funktioniert - wenn dies der Fall, kann es ein größeres Problem darstellen ...


Ich habe es getestet, ohne die „Full Trust“ Flagge und die Laufzeit lehnt sie ab:

Typ konnte nicht 'MemoryAccess' von Assembly 'ConsoleApplication4, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null' geladen werden, da Objekte überlappt bei Offset 0 und die Montage muss nachprüfbar sein.

Und um diese Flagge zu haben, brauchen Sie bereits hohes Vertrauen - so können Sie schon mehr böse Dinge tun. Strings sind ein etwas anderer Fall, weil sie keine normalen .NET-Objekte sind - aber es gibt andere Beispiele, wie sie mutiert werden können - der "Union" -Ansatz ist jedoch ein interessanter. Für einen anderen hacky Weg (mit genug Vertrauen):

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 
+0

@Marc: Könnten Sie bitte auf die anderen Methoden der Mutation Saiten, die Sie im Sinn haben, bitte? – Brann

+0

Dieser Code funktioniert ohne unsafe Flag. Aber es erfordert zunächst volles Vertrauen und die Verwendung von CAS für das Setzen von Berechtigungen, die nicht helfen (indem man Dinge davon abhält, ähnlich zu sein). Könnten Sie ein Beispiel geben, das den String-Inhalt ändert und keine unsicheren Blöcke verwendet? – Mash

+0

Bearbeitet, ob es die unsichere Flagge oder das volle Vertrauen ist - ich änderte verschiedene Dinge, so habe ich vielleicht den Überblick verloren ... Re "ändert Zeichenketteninhalt" - nicht von der Spitze meines Kopfes. Sehr schäbig; -p –

0

Sie sind immer noch aus dem "verwalteten" Bit. Es gibt die zugrunde liegende Annahme, dass, wenn Sie das tun können, Sie wissen, was Sie tun.

5

Whoops, ich habe unsafe mit fixed verwechselt. Hier ist eine korrigierte Version:

Der Grund, dass der Beispielcode nicht mit dem unsafe Schlüsselwort Tagging erfordert, ist, dass es nicht Zeiger enthält (siehe unten Zitat warum diese als unsicher angesehen wird). Sie haben recht: "Sicher" könnte besser als "Laufzeitfreundlich" bezeichnet werden. Weitere Informationen zu diesem Thema ich Sie Don Box und Chris Sells siehe Wesentliche .NET

MSDN zu zitieren,

In der Common Language Runtime (CLR) wird unsicherer Code bezeichnet als nicht verifizierbarer Code.Unsicherer Code in C# ist nicht unbedingt gefährlich; es ist nur Code, dessen Sicherheit nicht von der CLR verifiziert werden kann. Die CLR wird daher nur unsicheren Code ausführen, wenn es in einer vollständig vertrauenswürdigen Assembly ist. Wenn Sie unsicheren Code verwenden, ist es Ihre Verantwortung sicherzustellen, dass Ihr Code keine Sicherheitsrisiken oder Zeigerfehler einführt.

Die Differenz zwischen festen und unsicher, dass festgelegt wird, um die CLR-Stationen von den Dinge um in Erinnerung zu bewegen, so dass sie die Dinge außerhalb der Laufzeit sicher auf sie zugreifen können, während etwa genau das entgegengesetzte Problem unsicher ist: während die CLR kann eine korrekte Auflösung für eine Dotnet-Referenz garantieren, für einen Zeiger ist dies nicht möglich. Sie erinnern sich vielleicht an verschiedene Microsofties, die darüber reden, dass eine Referenz kein Zeiger ist, und deshalb machen sie so viel Aufhebens um eine subtile Unterscheidung.

+0

+1 Ah, das macht Sinn. Dies verdeutlicht, was "sicher" bedeutet. –

+0

Dieser Code ermöglicht es Ihnen tatsächlich, die Objektgrenzen zu verlassen und jeden Teil des prozesszugänglichen Speichers zu ändern. Sie können Synchronisationsblöcke rekonstruieren und den Deskriptor beliebiger Objekte eingeben, gehen Sie in GC-Daten. Was eigentlich unsichere gibt mehr als? – Mash

+0

Davon reden wir. Dieser Code weist keine Anzeichen dafür auf, dass CLR seine Sicherheit nicht überprüfen kann (was tatsächlich nicht möglich ist). Jedes Objekt in .NET verwendet intern unsicheren Code, aber das führt nicht zu der Fähigkeit, als sicher deklarierten Code zu konstruieren, der als unsicher auf Daten zugreifen und diese ändern kann. – Mash