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, 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 in 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 requires some background of C++ pointer manipulation.

allow unsafe code

The unsafe Keyword

The unsafe keyword specifies the location of unsafe code. When this keyword is applied to a type, all the members of that type are considered unsafe as well because 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 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. First, is to declare a new pointer variable and 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.

 

Up Next
    Ebook Download
    View all
    Learn
    View all