2010-12-23 10 views
5

Betrachten Sie den folgenden Code ein:Sollte der Inhalt eines solchen Strings eine Ausnahme verursachen?

using System; 
using System.Runtime.InteropServices; 

namespace Demo 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      const string test = "ABCDEF"; // Strings are immutable, right? 
      char[] chars = new StringToChar{str=test}.chr; 
      chars[0] = 'X'; 

      // On an x32 release or debug build or on an x64 debug build, 
      // the following prints "XBCDEF". 
      // On an x64 release build, it prints "ABXDEF". 
      // In both cases, we have changed the contents of 'test' without using 
      // any 'unsafe' code... 

      Console.WriteLine(test); 
     } 
    } 

    [StructLayout(LayoutKind.Explicit)] 
    public struct StringToChar 
    { 
     [FieldOffset(0)] 
     public string str; 
     [FieldOffset(0)] 
     public char[] chr; 
    } 
} 

Durch diesen Code ausgeführt wird, sind wir in der Lage, den Inhalt eines Strings ohne Ausnahme auftritt zu ändern. Wir mussten dazu keinen unsicheren Code deklarieren. Dieser Code ist eindeutig sehr fragwürdig!

Meine Frage ist einfach das: Denken Sie, dass eine Ausnahme durch den obigen Code ausgelöst werden sollte?

[EDIT1: Beachten Sie, dass andere Leute das für mich haben versucht, und einige Leute unterschiedliche Ergebnisse erhalten - was auch nicht die nastyness gegebenes Suprising, was ich tue ...;)]

[ EDIT2: Beachten sie, dass ich Visual Studio 2010 auf Windows 7 Ultimate 64 Bit]

[EDIT3 bin mit: Aus dem Test-String const, es einfach zu machen, noch mehr zwielichtige]

+2

Duplikat einer [Frage, die ich bereits gestellt habe] (http://stackoverflow.com/questions/792735/why-does-this-code-work-without-the-unsafef-keyword) :-) –

+0

Sehr interessant! Sieht so aus, als ob das ein bekanntes Problem ist. –

Antwort

3

Meine Stimme ist auf Herstellung FieldOffset unsicher! .

+0

Ja, das scheint völlig angemessen zu sein! –

5

Der SSCLI20-Quellcode für clr/src/vm/class.cpp, MethodTableBuilder :: HandleExplicitLayout kann einige Einblicke liefern. Es ist ungewöhnlich stark kommentiert dieser Kommentar die Regeln (edited zur besseren Lesbarkeit) beschreibt:

// go through each field and look for invalid layout 
// (note that we are more permissive than what Ecma allows. We only disallow 
// the minimum set necessary to close security holes.) 
// 
// This is what we implement: 
// 
// 1. Verify that every OREF is on a valid alignment 
// 2. Verify that OREFs only overlap with other OREFs. 
// 3. If an OREF does overlap with another OREF, the class is marked unverifiable. 
// 4. If an overlap of any kind occurs, the class will be marked NotTightlyPacked (affects ValueType.Equals()). 

Regel 1 sorgt dafür, dass eine Referenzzuordnung Atom bleibt. Regel 2 sagt, warum Sie tun können, was Sie getan haben, jede Objekttypreferenz kann sich überlappen. Eine Überlappung mit einem Werttyp Wert ist nicht zulässig, was den Garbage Collector vermasselt. Regel 3 besagt die Konsequenz, es nur macht den Typ nicht nachprüfbar.

Es ist sonst nicht die einzige Möglichkeit, eine Zeichenfolge ohne das unsichere Schlüsselwort zu vermasseln. Markieren Sie einfach eine Funktion, die die Zeichenfolge stampft. Es wird ein Zeiger auf den Inhalt der Zeichenfolge auf dem Heap oder Loader-Heap (interned strings) von GC abgerufen, es wird keine Kopie erstellt. Das ist auch nicht verifizierbarer Code und in einer Sandbox genauso unbenutzbar.

Fahren Sie den Punkt nach Hause: das C# unsichere Schlüsselwort ist überhaupt nicht verwandt mit dem, was die CLR als überprüfbar und somit als tatsächlich sicheren Code betrachtet. Es kümmert sich um die eklatanten Fälle, mit Zeigern oder benutzerdefinierten Werttypen (behoben). Ob das ein Leck in der C# -Sprachspezifikation ist, ist fraglich. Pinvoke ist der offensichtliche Randfall. Eine Betriebssystemfunktion zu pinieren ist ziemlich sicher. Eine C-Bibliothek von Drittanbietern pinvokieren ist dies nicht.

Aber ich muss @fej zustimmen, [FieldOffset] sollte die "bist du sicher" -Behandlung erhalten haben. Schade, dass es dafür keine Syntax gibt. Zugegebenermaßen habe ich noch nicht herausgefunden, warum dies tatsächlich das gehandhabte Layout beeinflussen musste. Es würde viel mehr Sinn machen, dass dieses Attribut nur für das Marshalling-Layout gelten würde. Seltsam, jemand, der in den frühen Tagen vielleicht ein Ass im Ärmel hat.

Verwandte Themen