Unsafe Coding: Pointers in .NET

Abstract
 
In .NET, unsafe code really means potentially unsafe code, that is code or memory that exists outside the normal boundary. This article digs into the details of legacy C programming pointer implementation in the .NET Framework. We however will seldom need to use pointer types. Unsafe code can access unmanaged memory resources, that are outside the realm of the CLR. You can access unmanaged memory with raw pointers, that are only available to unsafe code. Finally, the use of pointers is very risky and prone to abuse because we need to manually manage the memory-related subtle tasks.
 
Unsafe Coding
 
In unsafe coding, developers can access raw legacy pointers in the .NET Framework environment. You can use pointer operators, such as & and *. As in the semantic of perfect programming practices, pointers should be avoided to make your code safer because they interrupt the normal operations of the Garbage Collector and they point to a fixed location in unmanaged memory whereas reference types point to a movable location is managed memory. But the question arises if pointers are so dangerous then why we are practicing unsafe coding? Why does the .NET Framework allow pointers? Use of unsafe coding or pointers is however sometimes necessary, for example porting C/C++ algorithms that heavily rely on pointers is very beneficial. There are certain circumstances in which unsafe is recommended.
  • Calling an unmanaged function that requires a function pointer as a parameter.
  • Unmanaged pointers no doubt improve performance and efficiency.
  • Pointers might be easier and more convenient when working with binary and memory-resident data structures.
Safe Coding
 
Improper pointer management causes many common problems, including memory leaks, accessing invalid memory, and deleting bad pointers. Safe coding is limited to accessing the managed heap. The managed heap is managed by the Garbage Collector, which is an essential component of the common language runtime. Code restricted to the managed heap is intrinsically safer than code that accesses unmanaged memory. The CLR automatically releases unused objects, conducts type verification, and performs other checks on managed memory. So, all this is not done automatically for unmanaged code, instead, the developer is responsible for these tasks. With managed coding, the developer can only focus on core application development instead of various administrative tasks such as memory management.
 
Note: Code in an unmanaged section is considered unsafe and not accessible to the CLR. Therefore, no code verification or stack tracing is done on the unmanaged code.
 
Pointers Implementation
 
Managed applications that include unsafe code must be compiled with the unsafe option. The C# compiler option is simply "/unsafe". In the Visual Studio 2010 IDE, this option is found under solution properties, in the build tab. You just need to check this option in order to compile the unsafe code that is leveraged with pointers.
 
Note: Unsafe coding and pointer implementation require some background of C++ pointer manipulation.
 
allow unsafe code
 
The unsafe Keyword
 
The unsafe keyword specifies the location of the unsafe code. When this keyword is applied to a type, all the members of that type are considered unsafe as well because the code inside the target is considered unsafe. When you wish to work with pointers in C#, you must specifically declare a block of unsafe code using the unsafe keyword. The following code segment depicts an overview of an unsafe code block;
  1. class Program  
  2. {  
  3.       static void Main(string[] args)  
  4.       {  
  5.             //// pointers won't work here  
  6.             unsafe  
  7.             {  
  8.                   // pointer manipulation (&, *)  
  9.             }  
  10.       }  
  11. }  
We can also mark classes, methods, structures, variables, and parameters with the unsafe keyword as in the following:
  1. public unsafe class test  
  2. {  
  3.       unsafe int x = 10;  
  4.   
  5.       unsafe void myMethod(int* x)  
  6.       {  
  7.       }  
  8. }  
The following sample does some math calculations using a pointer and eventually produces a square root:
  1. using System;  
  2.   
  3. namespace unsafePro  
  4. {  
  5.     class Program  
  6.     {  
  7.         static void Main(string[] args)  
  8.         {  
  9.             unsafe  
  10.             {  
  11.                 double x = 10;  
  12.                 sqrt(&x);  
  13.             }  
  14.   
  15.             Console.ReadKey();    
  16.         }  
  17.   
  18.         unsafe static void sqrt(double* i)  
  19.         {  
  20.             Console.WriteLine("Square Root is={0}",Math.Sqrt(*i));    
  21.         }  
  22.     }  
  23. }  
The important point to remember here is that the calling of an unsafe method must happen from the unsafe block, otherwise, the compiler will issue an error. The following implementation produces a compile-time error because we are calling the sqrt method from outside the unsafe block:
  1. static void Main(string[] args)  
  2. {   
  3.       unsafe  
  4.       {  
  5.             double x = 10;  
  6.             sqrt(&x);  
  7.       }  
  8.   
  9.       int y = 5;  
  10.   
  11.       sqrt(&y); //compile time error  
  12. }  
We can avoid the hassle of an unsafe block by putting the unsafe keyword prefix over than the main method as in the following:
  1. unsafe static void Main(string[] args)  
  2. {   
  3.       double x = 10;  
  4.       sqrt(&x);  
  5. }  
Pointers declaration and syntax
 
C# does not expose pointers automatically. Exposing a pointer requires an unsafe context. Pointers normally are abstract using a reference in C#. The reference abstracts a pointer to memory on the managed heap. The reference and related memory are managed by the GC. Here is the syntax for declaring a pointer.
  1. unmanagedtype* identifier;  
  2.   
  3. int* x,y;  
  4.   
  5. int *x, *y;      // Wrong Syntax error  
Here the asterisk symbol has two purposes. The first is to declare a new pointer variable and the second is to dereference a pointer.
 
The (->) Operator
 
Arrow notation (->) dereference members of a pointer type found at a memory location. For instance, you can access members of a structure type using arrow notation and pointer as in the following:
  1. namespace unsafePro  
  2. {  
  3.     public struct xyz  
  4.     {  
  5.         public int x;  
  6.         public int y;  
  7.     }  
  8.     class Program  
  9.     {  
  10.         static void Main(string[] args)  
  11.         {  
  12.             unsafe  
  13.             {  
  14.                 xyz obj = new xyz();  
  15.                 xyz* aa = &obj;  
  16.                 aa->x = 200;  
  17.                 aa->y = 400;  
  18.                 Console.WriteLine("X is={0}", aa->x);  
  19.                 Console.WriteLine("Y is={0}", aa->y);  
  20.             }  
  21.   
  22.             Console.ReadKey();  
  23.         }  
  24.     }  
  25. }  
The sizeof keyword
 
As in C++, the sizeof keyword is used to obtain the size in bytes of a value type and it may only be used within an unsafe context.
  1. static void Main(string[] args)  
  2. {        
  3.       unsafe  
  4.       {  
  5.             Console.WriteLine("Int   size is={0}"sizeof(int));  
  6.             Console.WriteLine("Int16 size is={0}"sizeof(Int16));  
  7.             Console.WriteLine("Int32 size is={0}"sizeof(Int32));  
  8.             Console.WriteLine("Int64 size is={0}"sizeof(Int64));    
  9.       }  
  10.   
  11. }  
After compiling this program, it produces the size of each integer type as in the following:
 
program outout
 
The stackalloc keyword
 
In the unsafe context, we can declare a local variable that allocates memory directly from the call stack. To do so, C# provides the stackalloc keyword, which is the C# equivalent to the _alloca function of the C runtime library.
  1. unsafe static string data()  
  2. {  
  3.     char* buffer = stackalloc char[5];  
  4.     for (int i = 0; i < 5; i++)  
  5.     {  
  6.          buffer[i] = 'a';  
  7.     }  
  8.     return new string(buffer);  
  9. }  
Synopsis
 
The purpose of this article was to investigate one of the advanced concepts of the pointer implementation under the CLR context. We got a deep understanding of unsafe and safe programming. We learn how to implement pointers using C #. Finally, we spent our time by examining small sets of pointer-related keywords such as unsafe, sizeof, stackalloc.


Similar Articles