1. Trang chủ
  2. » Công Nghệ Thông Tin

ebook Addison -Essential CSharp 4.0_9 doc

96 286 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 96
Dung lượng 3,23 MB

Nội dung

ptg Pointers and Addresses 835 If the data is an unmanaged variable type but is not fixed, then use the fixed statement to fix a moveable variable. Fixing Data To retrieve the address of a moveable data item, it is necessary to fix, or pin, the data, as demonstrated in Listing 20.14. Listing 20.14: Fixed Statement byte[] bytes = new byte[24]; fixed (byte* pData = &bytes[0]) // pData = bytes also allowed { // } Within the code block of a fixed statement, the assigned data will not move. In this example, bytes will remain at the same address, at least until the end of the fixed statement. The fixed statement requires the declaration of the pointer variable within its scope. This avoids accessing the variable outside the fixed state- ment, when the data is no longer fixed. However, it is the programmer’s responsibility to ensure that he doesn’t assign the pointer to another vari- able that survives beyond the scope of the fixed statement—possibly in an API call, for example. Similarly, using ref or out parameters will be prob- lematic for data that will not survive beyond the method call. Since a string is an invalid referent type, it would appear invalid to define pointers to strings. However, as in C++, internally a string is a pointer to the first character of an array of characters, and it is possible to declare pointers to characters using char*. Therefore, C# allows declar- ing a pointer of type char* and assigning it to a string within a fixed statement. The fixed statement prevents the movement of the string dur- ing the life of the pointer. Similarly, it allows any moveable type that sup- ports an implicit conversion to a pointer of another type, given a fixed statement. You can replace the verbose assignment of &bytes[0] with the abbrevi- ated bytes, as shown in Listing 20.15. From the Library of Wow! eBook ptg Chapter 20: Platform Interoperability and Unsafe Code836 Listing 20.15: Fixed Statement without Address or Array Indexer byte[] bytes = new byte[24]; fixed (byte* pData = bytes) { // } Depending on the frequency and time to execute, fixed statements have the potential to cause fragmentation in the heap because the garbage col- lector cannot compact fixed objects. To reduce this problem, the best practice is to pin blocks early in the execution and to pin fewer large blocks rather than many small blocks. Unfortunately, this has to be tempered with pinning as little as possible for as short a time as possible, to minimize the chance that a collection will happen during the time that the data is pinned. To some extent, .NET 2.0 reduces the problem, due to some addi- tional fragmentation-aware code. Allocating on the Stack You should use the fixed statement on an array to prevent the garbage col- lector from moving the data. However, an alternative is to allocate the array on the call stack. Stack allocated data is not subject to garbage collec- tion or to the finalizer patterns that accompany it. Like referent types, the requirement is that the stackalloc data is an array of unmanaged types. For example, instead of allocating an array of bytes on the heap, you can place it onto the call stack, as shown in Listing 20.16. Listing 20.16: Allocating Data on the Call Stack byte* bytes = stackalloc byte[42];} Because the data type is an array of unmanaged types, it is possible for the runtime to allocate a fixed buffer size for the array and then to restore that buffer once the pointer goes out of scope. Specifically, it allocates sizeof(T) * E, where E is the array size and T is the referent type. Given the requirement of using stackalloc only on an array of unmanaged types, the runtime restores the buffer back to the system simply by unwinding the stack, eliminating the complexities of iterating over the f-reachable queue (see Garbage Collection and Finalization in Chapter 9) and compacting reachable data. Therefore, there is no way to explicitly free stackalloc data. From the Library of Wow! eBook ptg Pointers and Addresses 837 Note that the stack is a precious resource and, although small, running out of stack space will result in a program crashing; every effort should be taken to avoid running out. If a program does run out of stack space, the best thing that can happen is for the program to shut down/crash immediately. Gener- ally, programs have less than 1MB of stack space (possibly a lot less). There- fore, take great care to avoid allocating arbitrarily sized buffers on the stack. Dereferencing a Pointer Accessing the data stored in a variable of a type referred to by a pointer requires that you dereference the pointer, placing the indirection operator prior to the expression. byte data = *pData;, for example, dereferences the location of the byte referred to by pData and returns the single byte at that location. Using this principle in unsafe code allows the unorthodox behavior of modifying the “immutable” string, as shown in Listing 20.17. In no way is this recommended, but it does expose the potential of low-level memory manipulation. Listing 20.17: Modifying an Immutable String string text = "S5280ft"; Console.Write("{0} = ", text); unsafe // Requires /unsafe switch. { fixed (char* pText = text) { char* p = pText; *++p = 'm'; *++p = 'i'; *++p = 'l'; *++p = 'e'; *++p = ' '; *++p = ' '; } } Console.WriteLine(text); The results of Listing 20.17 appear in Output 20.2. OUTPUT 20.2: S5280ft = Smile From the Library of Wow! eBook ptg Chapter 20: Platform Interoperability and Unsafe Code838 In this case, you take the original address and increment it by the size of the referent type (sizeof(char)), using the preincrement operator. Next, you dereference the address using the indirection operator and then assign the location with a different character. Similarly, using the + and – operators on a pointer changes the address by the * sizeof(T) operand, where T is the referent type. Similarly, the comparison operators (==, !=, <, >, <=, and =>) work to compare pointers translating effectively to the comparison of address location values. One restriction on the dereferencing operator is the inability to derefer- ence a void*. The void* data type represents a pointer to an unknown type. Since the data type is unknown, it can’t be dereferenced to another type. Instead, to access the data referenced by a void*, you must convert it to any other pointer type variable and then dereference the later type, for example. You can achieve the same behavior as Listing 20.17 by using the index operator rather than the indirection operator (see Listing 20.18). Listing 20.18: Modifying an Immutable with the Index Operator in Unsafe Code string text; text = "S5280ft"; Console.Write("{0} = ", text); Unsafe // Requires /unsafe switch. { fixed (char* pText = text) { pText[1] = 'm'; pText[2] = 'i'; pText[3] = 'l'; pText[4] = 'e'; pText[5] = ' '; pText[6] = ' '; } } Console.WriteLine(text); The results of Listing 20.18 appear in Output 20.3. OUTPUT 20.3: S5280ft = Smile From the Library of Wow! eBook ptg Summary 839 Modifications such as those in Listing 20.17 and Listing 20.18 lead to unexpected behavior. For example, if you reassigned text to "S5280ft" following the Console.WriteLine() statement and then redisplayed text, the output would still be Smile because the address of two equal string literals is optimized to one string literal referenced by both variables. In spite of the apparent assignment text = "S5280ft"; after the unsafe code in Listing 20.17, the internals of the string assignment are an address assignment of the modified "S5280ft" location, so text is never set to the intended value. Accessing the Member of a Referent Type Dereferencing a pointer makes it possible for code to access the members of the referent type. However, this is possible without the indirection oper- ator (&). As Listing 20.19 shows, it is possible to directly access a referent type’s members using the -> operator (that is, a->b is shorthand for (*a).b). Listing 20.19: Directly Accessing a Referent Type’s Members unsafe { Angle angle = new Angle(30, 18, 0); Angle* pAngle = &angle; System.Console.WriteLine("{0}° {1}' {2}\"", } The results of Listing 20.19 appear in Output 20.4. SUMMARY This chapter’s introduction outlined the low-level access to the underlying operating system that C# exposes. To summarize this, consider the Main() pAngle->Hours, pAngle->Minutes, pAngle->Seconds); OUTPUT 20.4: 30° 18' 0 From the Library of Wow! eBook ptg Chapter 20: Platform Interoperability and Unsafe Code840 function listing for determining whether execution is with a virtual com- puter (see Listing 20.20). Listing 20.20: Designating a Block for Unsafe Code using System.Runtime.InteropServices; class Program { unsafe static int Main(string[] args) { // Assign redpill byte[] redpill = { 0x0f, 0x01, 0x0d, // asm SIDT instruction 0x00, 0x00, 0x00, 0x00, // placeholder for an address 0xc3}; // asm return instruction fixed (byte* matrix = new byte[6], redpillPtr = redpill) { // Move the address of matrix immediately // following the SIDT instruction of memory. *(uint*)&redpillPtr[3] = (uint)&matrix[0]; using (VirtualMemoryPtr codeBytesPtr = new VirtualMemoryPtr(redpill.Length)) { Marshal.Copy( redpill, 0, codeBytesPtr, redpill.Length); MethodInvoker method = (MethodInvoker)Marshal.GetDelegateForFunctionPointer( codeBytesPtr, typeof(MethodInvoker)); method(); } if (matrix[5] > 0xd0) { Console.WriteLine("Inside Matrix!\n"); return 1; } else { Console.WriteLine("Not in Matrix.\n"); return 0; } unsafe { From the Library of Wow! eBook ptg Summary 841 } // fixed } } The results of Listing 20.20 appear in Output 20.5. In this case, you use a delegate to trigger execution of the assembler code. The delegate is declared as follows: delegate void MethodInvoker(); This book has demonstrated the power, flexibility, consistency, and fantastic structure of C#. This chapter demonstrated the ability, in spite of such high-level programming capabilities, to perform very low-level oper- ations as well. Before I end the book, the next chapter briefly describes the underlying execution platform and shifts the focus from the C# language to the broader platform in which C# programs execute. } // unsafe OUTPUT 20.5: Inside Matrix! From the Library of Wow! eBook ptg This page intentionally left blank From the Library of Wow! eBook ptg 843 21 The Common Language Infrastructure NE OF THE FIRST ITEMS that C# programmers encounter beyond the syntax is the context under which a C# program executes. This chap- ter discusses the underpinnings of how C# handles memory allocation and deallocation, type checking, interoperability with other languages, cross- platform execution, and support for programming metadata. In other words, this chapter investigates the Common Language Infrastructure (CLI) on which C# relies both at compile time and during execution. It cov- ers the execution engine that governs a C# program at runtime and how C# fits into a broader set of languages that are governed by the same execution O Common Language Infrastructure 1 What Is the CLI? Base Class Library Common Language Specification Common Type System Common Intermediate Language 2 CLI Implementations 3 C# Compilation Runtime 4 Garbage Collection Type Safety Code Access Security Platform Portability Performance 5 Components Metadata Application Domains Assemblies Manifests Modules From the Library of Wow! eBook ptg Chapter 21: The Common Language Infrastructure844 engine. Because of C#’s close ties with this infrastructure, most of the features that come with the infrastructure are made available to C#. Defining the Common Language Infrastructure (CLI) Instead of generating instructions that a processor can interpret directly, the C# compiler generates instructions in an intermediate language, the Common Intermediate Language (CIL). A second compilation step occurs, generally at execution time, converting the CIL to machine code that the processor can understand. Conversion to machine code is still not sufficient for code execution, however. It is also necessary for a C# pro- gram to execute under the context of an agent. The agent responsible for managing the execution of a C# program is the Virtual Execution System (VES), generally more casually referred to as the runtime. (Note that the runtime in this context does not refer to a time, such as execution time; rather, the runtime—the Virtual Execution System—is an agent responsi- ble for managing the execution of a C# program.) The runtime is responsi- ble for loading and running programs and providing additional services (security, garbage collection, and so on) to the program as it executes. The specification for the CIL and the runtime is contained within an international standard known as the Common Language Infrastructure (CLI). This is a key specification for understanding the context in which a C# program executes and how it can seamlessly interact with other programs and libraries, even when they are written in alternate languages. Note that the CLI does not prescribe the implementation for the standard, but rather identifies the requirements for how a CLI platform should behave once it conforms to the standard. This provides CLI implementers with the flexibility to innovate where necessary, while still providing enough structure that programs created by one platform can execute on a different CLI implementation, and even on a different operating system. NOTE Note the similarity between these two acronyms and the names they stand for. Take care to understand these upfront to avoid confusion later on. From the Library of Wow! eBook [...]... late binding, determining what code to execute at execution time rather than at compile time Reflection can even be used for generating documentation by iterating through metadata and copying it into a help document of some kind (see Chapter 17) From the Library of Wow! eBook 862 Chapter 21: The Common Language Infrastructure SUMMARY This chapter described many new terms and acronyms that are important... development, and a host of others VES (runtime) Virtual Execution System An agent that manages the execution of a program that is compiled for the CLI From the Library of Wow! eBook This page intentionally left blank From the Library of Wow! eBook A Downloading and Installing the C# Compiler and the CLI Platform T O COMPILE AND RUN C# programs, it is necessary to install a version of the compiler and the CLI... execution of the runtime using mono.exe, as shown in Output A.3 OUTPUT A.3: C:\SAMPLES>mono.exe HelloWorld.exe Hello My name is Inigo Montoya From the Library of Wow! eBook This page intentionally left blank From the Library of Wow! eBook B Full Source Code Listings M in this book have source code spread over multiple listings When listings are large, this makes the code difficult to follow This appendix... dword ptr 00000022 75F9C9E0 ecx,dword dword ptr [ebp-4],0 [ebp-0Ch],0 ds:[001833E0h],0 ptr ds:[01C31418h] ds: [03C8E854h] esp,ebp ebp Figure 21.1: Compiling C# to Machine Code From the Library of Wow! eBook Runtime 849 NGEN at installation (or at any time prior to execution) is that you can reduce the need for the jitter to run at startup, thereby decreasing startup time Runtime Even after the runtime... automated system for doing this Without the garbage collector, programmers must remember to always free any memory allocations they make Forgetting to do so, or doing so repeatedly From the Library of Wow! eBook 850 Chapter 21: The Common Language Infrastructure for the same memory allocation, introduces memory leaks or corruption into the program, something exacerbated by long-running programs such as web... This conforms to the general pattern of memory allocation that objects that have been around longer will continue to outlive objects that have only recently been instantiated From the Library of Wow! eBook Runtime 851 Additionally, the NET garbage collector uses a mark-and-sweep algorithm During each garbage collection execution, it marks objects that are to be de-allocated and compacts together the... data Methods marked as “private,” for example, are accessible only by the containing type 3 Assuming you are not the unscrupulous type that is looking for such vulnerabilities From the Library of Wow! eBook 852 Chapter 21: The Common Language Infrastructure ADVANCED TOPIC Circumventing Encapsulation and Access Modifiers Given appropriate permissions, it is possible to circumvent encapsulation and access... rather than the application developer The restriction is, of course, that no platform-specific APIs are used Because of this restriction, many developers forgo CLI platform-neutral From the Library of Wow! eBook Runtime 853 code in favor of accessing the underlying platform functionality, rather than writing it all from scratch The platform portability offered by NET, DotGNU, Rotor, and Mono varies depending... performance gains than the complexities of a low-level development platform In the climate of security holes caused by buffer overruns, managed execution is even more compelling From the Library of Wow! eBook 854 Chapter 21: The Common Language Infrastructure Undoubtedly, certain development scenarios (device drivers, for example) may not yet fit with managed execution However, as managed execution increases... managed development will be the predominant means of writing applications for its Windows platform in the future, even those applications that integrate with the operating system From the Library of Wow! eBook Assemblies, Manifests, and Modules 855 between application domains, so static constructors run for each application domain, and assuming a single thread per application domain, there is no need to . HelloWorld::Main 00 000 000 push ebp 00 000 001 mov ebp,esp 00 000 003 sub esp,28h 00 000 006 mov dword ptr [ebp -4] ,0 00 000 00d mov dword ptr [ebp-0Ch] ,0 00 000 0 14 cmp dword ptr ds: [00 1833E0h] ,0 00 000 01b je 00 000 022. 00 000 01b je 00 000 022 00 000 01d call 75F9C9E0 00 000 022 mov ecx,dword ptr ds: [01 C3 141 8h] 00 000 028 call dword ptr ds: [03 C8E854h] 00 000 02e nop 00 000 02f mov esp,ebp 00 000 031 pop ebp 00 000 032 ret Machine. args) { // Assign redpill byte[] redpill = { 0x0f, 0x01, 0x0d, // asm SIDT instruction 0x 00, 0x 00, 0x 00, 0x 00, // placeholder for an address 0xc3}; // asm return instruction fixed (byte*

Ngày đăng: 18/06/2014, 17:20