Recent

Author Topic: Access violation  (Read 796 times)

smallfreak

  • Newbie
  • Posts: 4
Access violation
« on: January 25, 2025, 10:51:16 am »
I have been a true fan of TurboPascal back in the last millennium. But after version 5.5 I oriented elsewhere.

Now, some 40 years later I found the need to try to debug some code written in FreePascal  8) . Unfortunately the entire Lazarus environment and all the dependency as well as working on Ubuntu 24.10 does not seem as familiar as I thought.  :o

I managed to get the IDE installed and I even managed to compile the project without errors. But as soon as I try to run the program, I get "Memory Access Violation" errors at various places. The debugger is quite useless. I can set a breakpoint and see the variable pointings change to "cannot access memory" too, so this certainly is a systemic problem. But I confess, I'm completely out of my best years solving such problems...

I certainly miss some vital information you might need to help, but I use the Linux *.deb installation files downloaded this week for Lazarus 3.8 and FPC 3.2.2

In particular, this CalcFileCRC32 function drops an exception when calling CRC32()

Code: Pascal  [Select][+][-]
  1. function CalcFileCRC32(AFileName: string): Cardinal;
  2. var
  3.   Buffer : TBytes;
  4. begin
  5.   Result:=CRC32(0,nil,0);
  6.   with TFileStream.Create(AFileName, fmOpenRead or fmShareDenyNone) do
  7.     try
  8.       SetLength(Buffer, Size);
  9.       Read(Buffer,Size);
  10.       Result:=CRC32(Result,@Buffer[0],Size);
  11.     finally
  12.       Free;
  13.     end;
  14. end;
  15.  

The buffer is created, it is initialized with the proper amount of zeroes with SetLength(). The Read() however changes the buffer to be no more accessible to the debugger and the CRC32() function seems to face the same problem. The CPU or OS memory allocation considers the memory address not part of the current application and thus drops an exception.

Probably this is because of a linking problem? Maybe a compiler/linker switch can force the libraries into the same memory block? All libraries seem to be statically linked, as I get just one executable and no dynamic libraries - as expected.

Can someone please set me onto the right track?

Fibonacci

  • Hero Member
  • *****
  • Posts: 650
  • Internal Error Hunter
Re: Access violation
« Reply #1 on: January 25, 2025, 10:54:50 am »
What is Size?

Share full, compilable source code that is causing access violations so we can eliminate it as a potential issue
« Last Edit: January 25, 2025, 11:06:25 am by Fibonacci »

korba812

  • Sr. Member
  • ****
  • Posts: 451
Re: Access violation
« Reply #2 on: January 25, 2025, 11:16:36 am »
You should specify first element of array when loading the data:
Code: Pascal  [Select][+][-]
  1. Read(Buffer[0],Size);
  2.  

What is Size?
This is a property of TStream.

Fibonacci

  • Hero Member
  • *****
  • Posts: 650
  • Internal Error Hunter
Re: Access violation
« Reply #3 on: January 25, 2025, 11:23:58 am »
This is a property of TStream.

Right :-[

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10811
  • Debugger - SynEdit - and more
    • wiki
Re: Access violation
« Reply #4 on: January 25, 2025, 11:44:13 am »
But as soon as I try to run the program, I get "Memory Access Violation" errors at various places. The debugger is quite useless. I can set a breakpoint and see the variable pointings change to "cannot access memory" too, so this certainly is a systemic problem. But I confess, I'm completely out of my best years solving such problems...

Do you have the exact line where the variable changes? Or does it happen while you "step over" maybe some function? (And it happens somewhere in that function?)

If the variable is a field, then it may be that the object got destroyed, and you have a dangling pointer to the (old) memory of that object. But that is just a guess.


As for the debugger showing "cannot access memory" => unfortunately it does not currently tell you what address that memory is (sometimes knowing that invalid address can help). If needed add a watch (menu: view > debug windows > Watches) with the watch-expression:  pointer(yourvariable)

If the issue happens while stepping over, and you want to know where exactly:
- add a watch, with the watch expression: yourvariable
- right click the watch and "Create Data/Watch Breakpoint"
- step over

Now when the variable changes (for an object that is just the address of the object, but not its fields / but in your case that is likely what you need // same for a pointer, just the pointer, not the pointed to data) the debugger will stop.
Now it may stop deep in the rtl (somewhere in code freeing memory). Open the stack window => menu view > debug windows > stack. And go through the stack for hints (like "Destroy" when an object is destroyed).

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10811
  • Debugger - SynEdit - and more
    • wiki
Re: Access violation
« Reply #5 on: January 25, 2025, 11:46:45 am »
OK, forget the above - still valid, but korba812 has the answer.

Buffer is an dynamic array, essentially a pointer. So it has (on a 64 bit maching) 8 bytes. Those 8 bytes point to some other memory that can hold the content.


   Read(Buffer...

Will read "Size" bites (more than 8 ) into the 8 bytes that are the pointer.


   Read(Buffer[0]
means to read to the memory of the first byte of the content (and then consecutive bytes)
« Last Edit: January 25, 2025, 11:49:06 am by Martin_fr »

Nimbus

  • Newbie
  • Posts: 1
Re: Access violation
« Reply #6 on: January 25, 2025, 12:08:19 pm »
Just a quick suggestion, this could be slightly less prone to errors with TBytesStream, which can handle the loading (LoadFromFile method) and the buffer (Bytes property) on its own, e. g.

Code: Pascal  [Select][+][-]
  1. function CalcFileCRC32(AFileName: string): Cardinal;
  2. begin
  3.   Result := CRC32(0, nil, 0);
  4.   with TBytesStream.Create(nil) do
  5.     try
  6.       LoadFromFile(AFileName);
  7.       Result := CRC32(Result, @Bytes[0], Size);
  8.     finally
  9.       Free;
  10.     end;
  11. end;    


ASerge

  • Hero Member
  • *****
  • Posts: 2379
Re: Access violation
« Reply #7 on: January 25, 2025, 02:26:41 pm »
Just a quick suggestion, this could be slightly less prone to errors with TBytesStream, which can handle the loading (LoadFromFile method) and the buffer (Bytes property) on its own, e. g.
In case the compilation is done with R+ and the file size is zero:
Code: Pascal  [Select][+][-]
  1. if Size > 0 then // <- added this
  2.   Result := CRC32(Result, @Bytes[0], Size);

smallfreak

  • Newbie
  • Posts: 4
Re: Access violation
« Reply #8 on: January 25, 2025, 03:52:19 pm »
Woha! You are quite quick and you are most helpful too.  ;D

You should specify first element of array when loading the data:
Code: Pascal  [Select][+][-]
  1. Read(Buffer[0],Size);
  2.  

This indeed got rid of the problem.

What is Size?
This is a property of TStream.

I asked myself the same question and came to the same conclusion. The "with" construction allows for abbreviated syntax later, disguising the origin.

I must declare that this is not my source code, but some other from a project on GitHub. This function is in effect for quite some release now, so I must assume it does compile correctly working versions with suitable settings. The entire Lazarus project is part of the repository, so one might assume, it's a mere copy and run. Which it was not.  :-X

I usually try to replicate the known good behavior before I start "enhancing" other peoples code. If something breaks when using the original code, then i first assume a problem on my side - which usually is the correct assumption.

I have been spolied by relying on CLR compilers and VisualStudio for a few decades about what a compiler and a debugger can do about strongly (or weakly) typed objects.  %)

Can you imagine a setting, where the original code is expected to work as written? A discrepancy in the complier or library version? The project relies on standard, supplied libraries only with additional "LazUtils" and "indylaz".

I have another code line that did not work out as expected:

Code: Pascal  [Select][+][-]
  1. var
  2.   LPointer: PChar;
  3.   LUnicode: Cardinal;
  4.  
  5. begin
  6.  ...
  7.   LUnicode:=UTF8CodepointToUnicode(LPointer,LCPLen);
  8.   case Integer(LUnicode.Words[0]) of
  9.      ...
  10.   end
  11.  

It's line 8, the "case" line, where the Cardinal type gets read as record of Word. Since Cardinal is an alias to LongWord and that type has no structure, this must fail.

Is there a version where cardinal CAN be split with this syntax? I changed this to

Code: Pascal  [Select][+][-]
  1. Integer(word(LUnicode))

as this should give me the lower word of a LongInteger. But I'm still uncertain, what causes the discrepancy in an obviously working Lazarus project. Just not working unaltered at my system.

At last there is a piece of code where an object derived directly from TFPHTTPServer is assumed to have parameters like "ThreadMode", "KeepConnections" and "KeepConnectionTimeout", which are not documented in the library - and indeed are not availale.

On the other hand I DID find these parameters in a WIKI page describing them for just this FCL object.

So I'm quite confused. Has there been any breaking change in the libraries? Do these things refer to way outdated version or maybe to upcoming releases? Even if I assume that setting up Lazarus/freepascal on Linux might be a bit different than with Windows - the code base and the compiled executables should be pretty much compatible.

And the published binaries for all versions of this project DO work.

 :-\

 

TinyPortal © 2005-2018