0

I've got a specific Exception class I'm wanting to throw from a class method and catch from it's calling code in the main() function.

However when I run it, I get the following error: Unhandled exception at 0x775915ee in OpenHashTable.exe: 0xC0000005: Access violation. as if it isn't being handled. I can't see why this is happeing. Here's the involved code:

main() {
    ......
        case 'i':   
        {
                cout << "Enter the positive integer you wish to insert: ";
                    //Input Validation.  
                if (!(cin >> number))
                {
                    cout << "Please enter a valid positive integer...\n\n";
                    cin.clear();
                    cin.ignore(numeric_limits<streamsize>::max(), '\n'); //Taken from http://stackoverflow.com/questions/2075898/good-input-validation-loop-using-cin-c
                    break;
                }
                try
                {
                    hashTable.add(abs(number)); //Add positive only integer
                }
                catch (FullTableException& fte)
                {
                    cout << "HashTable is full!" << endl;
                    break;
                }
                catch (DuplicateElementException& dee) //NOT BEING CAUGHT?
                {
                    cout << "HashTable already contains that element." << endl;     
                    break;
                }
                cout << abs(number) << " added!\n\n";
                break;
        }
     .......
}

Here's the exception being thrown in the HashTable::add() method

    //Adds an element into the appropriate index
bool OpenHashTable::add(int toAdd) throw(FullTableException, DuplicateElementException)
{
  int index = hash(toAdd);

  //Check for duplicate
  if (search(toAdd))
      throw DuplicateElementException();  //NOT ACTUALLY THROWING??

  if (arr[index] != 0) //If element is occupied   //GET AN ACCESS VIOLATION HERE
  {
      int j = 0;

      //Linear Probing...
      for ( unsigned int i = index + 1; j < 100; i = ((i+1) % 100) )
      {
          if (arr[i] != 0 && arr[i] != -1) //If element is occupied
          {
              j++;          //Keep count of how many tries, for full array
              continue;
          }
          else
          {
              arr[i] = toAdd;   //Add to array
              size++;           //Increment size
              break;
          }

      }
      if (j == 100) //We've checked all possible elements
          throw FullTableException();   //No spaces
  }
  else
  {
      arr[index] = toAdd;   //Add to array straight away
      size++;               //Increment size
  }
  return true;  //Successfully added

}

EDIT: search() method:

    bool OpenHashTable::search(int toSearch)
{
    int index = hash(toSearch);

if (arr[index] == toSearch)
    return true;    //Found at index
else
{
    int j = 0;
        //Linear search for value
    for ( unsigned int i = index + 1; j < 100; i = ((i+1) % 100) )
    {
        if (arr[i] == toSearch)
            return true;    //found
        else if (arr[i] == 0)
            return false;   //Not in HashTable
        else 
            continue;   //Probe next element
    }
    if (j == 100)
        return false;   //Not in HashTable
}
return true;
}

EDIT: _try..._except() Call Stack:

    ntdll.dll!775915ee()    
[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll] 
ntdll.dll!775915ee()    
ntdll.dll!7761852f()    
ntdll.dll!776372ec()    
ntdll.dll!7760063e()    
ntdll.dll!775fabf9()    
ntdll.dll!77580143()    
KernelBase.dll!75c5b9bc()   
KernelBase.dll!75c5b9bc()   
KernelBase.dll!75c5b9bc()   
msvcr100d.dll!_CxxThrowException(void * pExceptionObject, const _s__ThrowInfo * pThrowInfo)  Line 157   C++
OpenHashTable.exe!OpenHashTable::add(int toAdd)  Line 100   //THIS IS "throw DuplicateElementException()"

OpenHashTable.exe!main()  Line 267    //THIS IS "hashTable.add(abs(number));"

EDIT: DuplicateElementException:

//Just an empty class
class DuplicateElementException : public exception
{
private:
public:
    DuplicateElementException();   //Constructor
    ~DuplicateElementException();   //Destructor
};
//empty constructor and destructor definitions...

Any help is much appreciated.

Thanks

Calum

Calum Murray
  • 1,102
  • 3
  • 12
  • 20

4 Answers4

5

The exception thrown is a SEH exception "Access violation", which means that you read or write from an invalid address. It's probably a bug in search or hash. and your program doesn't get to the line where you throw DuplicateElementException.

Besides, exception specification (the throw after the function prototype) are deprecated, so don't use them.

Yakov Galka
  • 70,775
  • 16
  • 139
  • 220
  • Most compilers do not implement exception specifications in a standard conforming way, but Are they officially deprecated? – Alok Save Oct 23 '11 at 17:04
  • Thanks for that update.It was about time they got rid of those :) – Alok Save Oct 23 '11 at 17:09
  • search() method added, can't see a bug. In debugging, it seems like it does step inside the `if (search(toAdd))` and fails on the `throw` statement. Ah I wasn't aware of the deprecation, thanks. – Calum Murray Oct 23 '11 at 17:18
  • @CalumMurray: given the information we have, it sounds impossible. So either you misunderstand what you see and give us the wrong information, or something is really broken on the low-level. I can only suggest you debugging the generated assembly to pin-down the real problem. This is what I would have done. – Yakov Galka Oct 23 '11 at 19:06
4

The Access violation exception being thrown is an SEH exception and will not be caught by a C++ catch block. You're most likely writing beyond the bounds of some array, which is causing the exception to be thrown.

To debug the problem, surround everything within the code inside main in a __try block and place breakpoints within the accompanying __except block. Details of how to do this can be found in the MSDN docs. You can use the code in there almost verbatim. Run your program in Debug mode and when the breakpoint is hit inspect the call stack to figure out what line the SEH exception is being thrown at.

Also, unless you have a very compelling reason to be using a C array, you should be using an std::array (if the size of the array is fixed) or an std::vector for the hash table. On Visual Studio operator[] for both of these will perform range checks in Debug mode and throw an std::out_of_range exception if your index is out of bounds. You can also use the at() member function with both to have them perform bounds checking in Release mode also. In either case, it is a lot easier to debug than having to mess with the SEH stuff.

EDIT:
A little bit of code refactoring will be required to debug the problem using __try - __except because you cannot surround code containing C++ object destruction with __try.

To get around this, create a function called int mainHelper() and move all the code from within main to this function. Now, your code should look like this:

int mainHelper()
{
  /* All your code from main goes here */
}

int main()
{
  __try {
    return mainHelper();

  } __except( filter(GetExceptionCode(), GetExceptionInformation()) ) {
    puts("in except");

  }
}
Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • 1
    Btw, SEH can be caught with `catch(...)` when compiled with /EHa. – Yakov Galka Oct 23 '11 at 17:11
  • 1
    @ybungalobill It can, but I remember reading somewhere that that option is not very desirable to have set. Unfortunately, I don't remember the reasons that were stated. – Praetorian Oct 23 '11 at 17:16
  • Thanks. I'm not sure what to put as the expression in the `__except(expression)` statement. I'm only using an index of 3 in an array of size 100, so I can't see where I would be generating an array out of bounds error. – Calum Murray Oct 23 '11 at 17:27
  • 2
    @CalumMurray Copy paste the `filter()` function exactly as shown above `main` and put `filter(GetExceptionCode(), GetExceptionInformation())` in the `__except` expression. You don't have to use the inner `__try` - `__finally` construct shown in that example. Everything else can remain the same. Put a breakpoint on the line `puts("in except");` – Praetorian Oct 23 '11 at 17:34
  • Oh yeah, thanks. I'm getting `Cannot use __try in functions that require object unwinding`, when I wrap all my code in the main() function. – Calum Murray Oct 23 '11 at 17:42
  • @CalumMurray Sorry, I forgot about that limitation. I've updated the answer. – Praetorian Oct 23 '11 at 17:49
0

It seems like index is out of bound of the array arr. It makes your process read from memory that isn't allocated to it and crash. This is not a C++ exception but something the OS tells your program.

selalerer
  • 3,766
  • 2
  • 23
  • 33
  • I don't see how i can be accessing out of bounds. I'm testing it with an index of 3 and the array is size 100. – Calum Murray Oct 23 '11 at 17:19
  • @CalumMurray You have two lines of code: int index = hash(toSearch); if (arr[index] == toSearch) You should check what hash(toSearch) returns before you access arr[index]. – selalerer Oct 23 '11 at 19:31
  • How are you declaring arr with size 100? (I can't see it in the code you have pasted) – doctorlove Jun 21 '13 at 14:36
-2

There is a very easy way to catch any kind of exception (division by zero, access violation, etc.) in Visual Studio using try -> catch (...) block. A minor project tweaking is enough. Just enable /EHa option in project settings. See Project Properties -> C/C++ -> Code Generation -> Modify the Enable C++ Exceptions to "Yes With SEH Exceptions". That's it!

See details here: http://msdn.microsoft.com/en-us/library/1deeycx5(v=vs.80).aspx

Volodymyr Frytskyy
  • 1,233
  • 11
  • 15
  • 1
    You are providing a possibly dangerous solution without saying a word of its drawbacks. – Steed May 04 '12 at 07:14
  • I'm not a ware of drawbacks. If you know any, why don't you tell? For me this solution is just perfect, much better then these which are voted higher here. – Volodymyr Frytskyy May 04 '12 at 13:16
  • `/EHa` can lead to your program muddling onward confusedly with corrupt state after an out-of-bounds memory access, divide-by-zero, or other asynchronous (SEH) exception. – LThode Nov 17 '14 at 21:59