Your New Jekyll Site

home

Interrupts, Exceptions and Errors in high level languages

15 May 2011

Sometimes the distinction between interrupts, exceptions and errors get blurred in high level languages, where they usually are abstracted.

Exception

An exception is an event that shouldn’t´t normally happen during normal operation. If unhandled it can stop your application from running.

There are three types of Exceptions

Hardware / Operating system Exceptions

Most CPUs can perform arithmetic operations as addition and subtraction, and they must comply to both hardware limitations and to standard arithmetic rules.

Arithmetic Overflow

A hardware limitation would be adding to operands, which results in a sum that is so big that it cannot fit into a CPU register. In the x86 architecture, the maximum value of an unsigned integer is 32^2 –1, adding +1 would cause a problem. The rule say, that the value should wrap around, i.e. the result will be 0.

Let’s look at an 8 bit integer. Its maximum value is when all bits are set, as in 11111111, which is 255 in decimal. Let’s add +1. 11111111 + 00000001 = 100000000. The result is a 9 bit number, but only the last 8 bit can be saved.

 
try
{
   int x = int.MaxValue - 10;
   int z = x + 20;
}
catch(OverflowException ex)
{
}

Unfortunately, this particular exception cannot be caught this way. By default this exception is not considered an error. In some algorithms, you count on the overflow. A 256 entry hash table could be implemented by using modulo or by directly using a data type of 8 bit that automatically wraps around. The .Net Exception can actually be used, but then you must use it with the checked keyword

try
{
   checked
   {
      int x = int.MaxValue - 10;
      int z = x + 20;
   }
}
catch(OverflowException ex)
{
}

The keyword checked, tells the .Net runtime to raise the overflow to an exception.

Division by zero

This sort of error is considered serious, because the result is undefined. Consider dividing a number with smaller and smalled numbers. As the dividend get smaller, the result gets bigger. This eventually results in an overflow, since the result can be bigger than what can fit in a register.

4/1.0 = 4
4/0.1 = 40
4/0.0001 = 40000
4/0……………1 = Infinity
4/0  = Illegal

But if the dividend is 0, the result is infinity or unknown, and it results in an exception, which can be caught by the code below.

try
{
   int result = 4 / 0;
}
catch(DivideByZeroException ex)
{
   // Error handling
}

Let’s do a slight modification. Let’s change the int data type to a double.

try
{
   double result = 4.0 / 0.0;
}
catch(DivideByZeroException ex)
{
   // Error handling
}

The exception won’t be caught when using a double data type.

The reason is that floating point arithmetic is often performed in a co-processor, according to IEEE 754. The double data type defines both negative and positive Infinity, so that value will be used in the result. It is still considered an error, but errors are reported with error bits instead of interrupts/exceptions. It is up to the programmer to test for them. The double data type in .Net, don’t do any checking. Neither the checked keyword helps. Instead the Decimal data type should be used.

try
{
   decimal zero = 0;
   decimal result = 4.0 / zero;
}
catch(DivideByZeroException ex)
{
   // Error handling
}

Language Exceptions

The C++ has a small language runtime which exist in both release and debug version. The debug version often contain run-time checks for invalid pointers, initialization of memory, check for memory leakage, etc.

The dot net run-time is much more advanced. C++ runs directly on the hardware, whilst the .Net code is interpreted by the .Net runtime. This makes the code hardware independent. Porting is not an act of porting the applications, but the runtime itself. The Mono project ports the .Net platform to many different platforms. Among the supported platforms are Solaris, Mac, and Linux.

Typically all the exceptions in the .Net runtime are language/run-time exceptions. The implementation of the hardware exceptions are caught using architecture dependent primitives, then they are wrapped and exposed in the language as Class Exceptions.

Program Exceptions

C++ Exceptions

Let’s look at the division by zero example in C++

try
{
   int result = 4 / 0;
}
catch ()
{
   // Error Handling
}

Let’s run it. …… BAM!

Image of windbg

The exception is not caught. As far as C++ is concerned, a C++ exception can only be caused by a throw statement. C++ exceptions is not for hardware exceptions, but for foreseen “unexpected” situations in your program. C++ exceptions are program exceptions, that lets you handle foreseen unexpected events, like invalid user input, missing files, or insufficient user access.

Hardware / Operating system Exceptions – Revisited

SEH – Windows Structured Exception Handling

For catching exceptions thrown by hardware and the operating system, we must use SEH exceptions. These types of exceptions are not part of the C++ standard since they are architecture dependent.

__try
{
   int result = 4 / 0;
}
__except (filter(GetExceptionCode(), GetExceptionInformation())
{
  // Error Handling
}

You have to implement the filter function yourself, in there you should test what type of exception code it is, and if you choose to continue execution, try to recover or exit the application. Try avoiding using SEH Exceptions. They are 10 times more expensive when triggered than if statements.