2010-12-23 6 views
5

다음 코드를 고려하십시오이와 같이 문자열의 내용을 변경하면 예외가 발생해야합니까?

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

이 코드를 실행함으로써을, 우리는 예외로 발생하지 않고 문자열의 내용을 변경 할 수 있습니다. 안전하지 않은 코드를 선언 할 필요가 없었습니다. 이 코드는 분명히 매우 위험합니다!

제 질문은 단순히 다음과 같습니다. 위 코드에서 예외를 발생시켜야한다고 생각합니까?

[EDIT1 참고 : 다른 사람들은 날 위해 시도하고, 어떤 사람들은 다른 결과를 얻을 - 너무 ... 내가 뭘하는지의 nastyness 주어 놀라운 일하지 않는)]

을 [ EDIT2 : 나는 윈도우 7 얼티밋 64 비주얼 스튜디오 2010을 사용하고 있습니다 비트]

[EDIT3 : 테스트 문자열 CONST 그냥 만들기 위해 만들어진 것이 더 사기]

+2

[질문에 이미 질문했습니다] (http://stackoverflow.com/questions/792735/why-does-this-code-work-without-the-unsafe-keyword) :-) –

+0

매우 흥미 롭습니다! 이것은 잘 알려진 문제인 것처럼 보입니다. –

답변

3

FieldOffset 안전하지 않은 만들기에 내 투표의! .

+0

네, 그건 완전히 적절한 것 같습니다! –

5

clr/src/vm/class.cpp에 대한 SSCLI20 소스 코드 인 MethodTableBuilder :: HandleExplicitLayout을 사용하면 통찰력을 얻을 수 있습니다. 비정상적으로 많이 (읽기 쉽도록 편집)이 댓글이 규칙을 설명, 주석 :

// 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()). 

규칙 1은 기준 할당 원자 유지되도록합니다. 규칙 2는 왜 당신이 한 일을 할 수 있는지, 어떤 객체 유형 참조도 겹칠 수 있다고 말한다. 값 유형 값으로 중첩되지 않으면 가비지 컬렉터가 망가집니다. 규칙 3은 그 결과를 나타내며, 만이 유형을 확인할 수 없게 만듭니다.

안전하지 않은 키워드가 없으면 문자열을 고정시키는 유일한 방법은 아닙니다. 그냥 문자열을 stomps 함수를 pinvoke. GC 힙 또는 로더 힙 (내부 문자열)의 문자열 내용에 대한 포인터를 가져오고 복사본이 만들어지지 않습니다. 이는 검증 할 수없는 코드이기도하며 샌드 박스에서 실행될 때도 악용 될 수 없습니다.

포인트를 집으로 운전 : C# 안전하지 않은 키워드는 CLR이 검증 할 수있는 것으로 간주하므로 실제로 안전한 코드와 관련이 없습니다. 포인터 또는 사용자 정의 값 유형 (고정 값)을 사용하여 뻔뻔스러운 사례를 처리합니다. C# 언어 사양의 누수인지 여부는 논쟁의 여지가 있습니다. Pinvoke가 더 확실한 경우입니다. 운영체제 기능을 Pinvoking하는 것은 꽤 쉽습니다. 제 3 자 C 라이브러리를 Pinvoking하지 않습니다.

하지만 저는 @fej에 동의해야합니다, [FieldOffset]은 "당신이 확실합니까?"치료를 받아야합니다. 너무 나쁘다는 구문이 없습니다. 틀림없이, 실제로 이것이 왜 실제로 레이아웃에 영향을 줄 필요가 있는지 알지 못했습니다. 은이 속성이 마샬링 된 레이아웃에만 적용된다는 의미가됩니다. 이상한, 초기에 그의 소매를 에이스로 잡고있는 누군가.