views:

444

answers:

5

This seems like the simplest thing in the world and I'm ready to pull my hair out over it.

I have a unit that looks like this ;

Unit  myUnit;
// ...
//normal declarations
//...
Public
//bunch of procedures including
Procedure myProcedure;

const
//bunch of constants

var
//bunch of vars including
myCounter:integer;

Implementation
Uses //(all my uses)

// All of my procedures including

Procedure myProcedure;
   try
     // load items from file to TListBox - this all works
   except
   on EReadError do begin
     // handle exception
     end;
   end; //try



   myCounter:=0;  //  <--  ACCESS VIOLATION HERE
   while myCounter //...etc

It's a simple assignment of a variable and I have no idea why it is doing this. I've tried declaring the variable local to the unit, to the procedure, globally - no matter where I try to do it I can't assign a value of zero to an integer, declared anywhere, within this procedure without it throwing an access violation. I'm totally stumped.

I'm calling the procedure from inside a button OnClick handler from within the same unit, but no matter where I call it from it throws the exception. The crazy thing is that I do the exact same thing in a dozen other places in units all over the program without problems. Why here? I'm at a total loss.

A: 

Move MyCounter up to the top of the var list, and see if it still happens. If the problem goes away, look at the vars declared above where you have it now - you may find something interesting, such as an array that is growing past its boundary.

Chris Thornton
That won't cause an access violation for accessing a simple variable.
Loren Pechtel
No, no arrays, and moving the var around doesn't help. It's a rather large and very stable application which works fine until I add in this little snippet.
Justin
@Loren - thanks, yes you're right. I helped a co-worker troubleshoot what seemed to be the exact same thing last week, but now that I think about it, the array was overwriting a pointer, not a simple var. Interestingly, that was cool because the array was declared BELOW the pointer, but he "underflowed" by using element [0] when the array was declared [1..5]. oops!
Chris Thornton
+2  A: 

I don't think your error means anything like what it appears to. When you get an access violation from a piece of code like this that has no sane way of producing an access violation you're looking at trashed memory in some fashion.

Step through the offending code in the CPU window and see what's really happening.

Loren Pechtel
Fair point. The fine toothed comb is always a last resort, I was hoping I'd done something obviously wrong which may have been apparent. I'll give it a go and if nothing else I suppose I'll just build a new unit rather than adding into an old one. Can't say I'm eager to spend more time than I've wasted already tracing through CPU registers solving a helloWorld problem.
Justin
Another option: Set a breakpoint where the variable is originally calculated. Verify that the correct number is being stored and then set a memory-modified breakpoint on the pointer. (Beware that I've had these go off in the OS itself. It can be pretty ugly.)
Loren Pechtel
+1  A: 

You are using with statements and are looking at a different myCounter?

Some part of your code is writing in memory it shouldn't or freeing while it shouldn't and that by accident it results in AV's when accessing that specific local variable?

Lars Truijens
Hilarious - some people are so quick to blame "with" that they even accuse it of causing problems in code that doesn't even involve it. Though we should be careful ... maybe a GOTO statement is responsible in this case. ;)
Deltics
@Deltics - As OP is not showing everything, although far fetched, this is as good of a guess as anything else.
Lieven
@Lieven: Simply not true. This guess wasn't as good as the guesses that were 100% accurate (given that this one was 0% accurate). :)
Deltics
@Deltics - fine, you have the last word. :)
Lieven
+1  A: 

The assignment myCounter := 0 throwing an access violation suggests that either the data segment that the global vars are stored in has been removed from memory, or that the registers are hosed in your myProcedure routine.

Use the CPU view to see what registers are used to access the global var, and then work backward from there to see where that/those registers go awry.

dthorpe
+6  A: 

Read of address 00000008 means that you're reading a variable at an offset of 8 bytes from a nil pointer. That doesn't fit what you're trying to do here at all, since you're writing, not reading, and you're writing a constant, not a variable read from somewhere.

Are you sure that this is the actual line that's triggering the exception? Have you put a breakpoint on this line? Have you tried moving this line to the top of the procedure?

It's hard to be sure without your actual code in front of me, but if I had to guess, I'd say that the line before this is causing the exception, and then the instruction pointer has already incremented so Delphi highlights the next line.

Mason Wheeler
Good point. Hardware exceptions often happen after the instruction point has moved on to the next instruction/statement. Look in the rear view mirror to see what you ran over. ;>
dthorpe
I'd just discovered this after doing a CPU trace, but you're right - I was clearing (with xx.Clear method) a TIdEmailAddressList (Indy component) which was causing the problems. Juggling things around and accessing it later also was throwing exceptions. **edit - actually, it was the TListBox that was being cleared. Just the same, problem solved.Thanks to everyone for good ideas. Premature baldness will have to wait for another day. Cheers.
Justin