Occasional access violation in FastMM4, DebugGetMem - delphi

I'm trying to track down an access violation. Reproducibility seems non-deterministic, and rare, so I want to check a few of my assumptions before I go any further.
The access violation is raised in FastMM4, version 4.991, in the function DebugGetMem, in the following code:
if (ASize > (MaximumMediumBlockSize - BlockHeaderSize - FullDebugBlockOverhead))
or CheckFreeBlockUnmodified(Result, GetAvailableSpaceInBlock(Result) + BlockHeaderSize, boGetMem) then
begin
{Set the allocation call stack}
GetStackTrace(#PFullDebugBlockHeader(Result).AllocationStackTrace, StackTraceDepth, 1);
{Set the thread ID of the thread that allocated the block}
PFullDebugBlockHeader(Result).AllocatedByThread := GetThreadID; // ** AV Here
{Block is now in use: It was allocated by this routine}
PFullDebugBlockHeader(Result).AllocatedByRoutine := #DebugGetMem;
The exception is:
Project Workstation.exe raised exception class $C0000005 with message 'access violation at 0x01629099: read of address 0x66aed8f8'.
The call stack is usually the same. It's being called from a paint event on the virtual treeview in which I call Format('%s %s %s', [vid, node, GetName()]) though I doubt that is really relevant (other than that Format allocates dynamic memory).
I'm using FullDebugMode (obviously) and CheckHeapForCorruption options.
I've also established the following:
Turning on CatchUseOfFreedInterfaces doesn't show anything new. I still get the same access violation, and no additional diagnostics.
I once reproduced the crash with FullDebugModeScanMemoryPoolBeforeEveryOperation := True, although I can't remember whether CatchUseOfFreedInterfaces was on or off on this occasion.
It isn't a thread concurrency issue; my application is single-threaded. (Actually, this isn't quite true. I'm using Virtual TreeView, which creates a hidden worker thread, but if this really is the cause then the bug is in Virtual TreeView, not my code, which is rather unlikely.)
Am I right in thinking that, despite CheckHeapForCorruption not catching anything, this exception can only be due to my code corrupting the heap? Is there anything else that could cause FastMM4 to crash in this way?
Any suggestions for further diagnostics, or even making the crash more reproducible?

Strange though it may seem, this is normal behaviour. If you switch to the CPU view you will see that the instruction pointer is located inside the FastMM_FullDebugMode.dll module. Some of the debugging functionality of FastMM can, by design, raise access violations. If you continue execution you will find that your application runs correctly.
It can be quite frustrating that debugging sessions are interrupted in this way. I had some discussion with the FastMM author on a related issue. It does seem that the FastMM debug DLL is designed to work this way the conclusion is that there's not a lot that can be done to stop these external exceptions being raised.
If anyone out there recognises this frustration, and has a good solution, I for one would be eternally grateful.

Related

Is there an efficient way to bullet-proof a program without try...except?

I've got a Delphi 6 client-server application where the server is essentially:
initialize;
repeat
try
getInput;
putOutput;
except
on e: exception do writeln(e.message);
end
until false;
During development, bugs (such as a pointer exception) were rare but the server would be able to keep running. Now that it's in production the server seems debugged and it's tempting to remove the try...except because it adds substantial execution overhead to the server, but then if an exception were to occur it would stop the server.
One solution would be to have a parent process simply restart the entire server, and bypassing initialization on restart would effectively reproduce what try...except accomplished, but there wouldn't be any record of what caused the exception, and restarting with or without initialization actually creates a lot of unwanted "state" issues, especially with client connections.
Is there some way to override or amend exception handling so that when the exception happens it's recorded somewhere (such as in the system event log or %errorlevel%) before the programs quits and is restarted or (better:) recovers, but without the overhead of an all-encompassing try...except?
The ideal solution would record the exception but resume execution at the level of the repeat...until. Perhaps by doing something like saving the address of the repeat in some accessible global, then make any exception unwind the call stack and resume at that saved address? (Which I guess is what try..except essentially does, but is there a way to avoid the overhead it imposes when there aren't exceptions?)
Expanding on Serg's suggestion:
repeat
try
repeat
getInput;
putOutput;
until false;
except
on e: exception do writeln(e.message);
end
until false;
Has the same behaviour but moves the try .. except outside the innermost loop.
However, I'd be amazed if this had any discernible impact on performance.
Expanding on David and Sergs suggestions...
If the complexity of your loop is as low as your posted code suggests (or could be reduced to such a level of simplicity) then it may be practical to provide both behaviours, subject to a command line switch to either enable or disable runtime errors via exception handling.
Parse the command line at startup to determine the mode of operation and set an indicator variable accordingly. e.g using an enum:
type
TServerMode = (smHighThroughput, smDiagnostic);
var
ServerMode: TServerMode;
if FindCmdLineSwitch('d') then
ServerMode := smDiagnostic
else
ServerMode := smHighThroughput;
You could of course use a setting in a configuration file or database table if a command line parameter is not desirable or practical for whatever reason.
However you go about it, you provide the ability to run the server in "high throughput" mode or "recoverable diagnostic" mode with a minimum of duplicated syntax:
try
case ServerMode of
smDiagnostic : repeat
try
getInput;
putOutput;
except
on e: Exception do .... // etc
end;
until FALSE;
smHighThroughput : repeat
getInput;
putOutput;
until FALSE;
end;
except
on e: Exception do .... // etc
end;
Note that even in HighThroughput mode the above example captures information about any exception that causes server termination. The Diagnostic mode logs all exceptions but attempts to keep the server running.
You can then default to HighThroughput mode with the option of enabling Diagnostic mode in the event that you need to diagnose a server that seems unusually unstable.
Having said all that, I would try to definitively quantify the impact of the try..except on the loop before going to great lengths to engineer around that impact.
Drop an ApplicationEvents on a central place in your application.
Implement the OnException Event.
Delete the local try...except to remove overhead.
In the exception event you can do anything including log the exception.
If you want to add something special to the exception it is possible to still have a local try..except and modify the E.Message and then call raise. Then the global exception handler will be called with the modified message.

How do I fix this memory leak while using Chromium Embedded?

The GuiDemo code for Chromium Embedded (https://code.google.com/p/delphichromiumembedded/) is leaking few bytes of memory. Not much but it is VERY annoying to get that message from FastMM every time you stop the app. I guess the leak is in the Chromium Interface.
The unit has a Initialization section:
INITIALIZATION
CefCache := 'cache';
CefRegisterCustomSchemes := CefOnRegisterCustomSchemes;
CefRegisterSchemeHandlerFactory('dcef', '', True, TFileScheme);
The log is this:
A memory block has been leaked. The size is: 20
This block was allocated by thread 0x1674, and the stack trace (return addresses) at the time was:
40455E
4050A7
409C1D
405622
4050DC
4F0D7A
406598
406604
40A6C3
4F0E28
764CEE1C [BaseThreadInitThunk]
The block is currently used for an object of class: main$174$ActRec
The allocation number is: 323
--------------------------------2014/10/5 17:11:33--------------------------------
This application has leaked memory. The small block leaks are (excluding expected leaks registered by pointer):
13 - 20 bytes: main$174$ActRec x 1
The thing is that I have no clue who main$174$ActRec is.
The unit that hosts the demo is called indeed 'main.pas'. But there is no other var called 'main'.
main$174$ActRec is associated with the interface used to support an anonymous method. So that should give you a clue as how to look for the leak.
If you included an exception logging suite like madExcept, EurekaLog of JCL, you'd get a meaningful stack trace from FastMM. That also would help you find where the leak originates.
Once you can find what has been leaked then it ought to be possible to find a way to register it as an expected leak. However, if you can identify what has been leaked then I'd suggest trying to find a way not to leak it.
I can't help you identify the leak further because you didn't give any more information. There are many demos for this project and I don't know which one you are running.
The error is telling you that the memory block holds an instance of a main$174$ActRec class, not that the memory was allocated by the main$174$ActRec class. Somewhere in your app, ActRec.Create() is being called, but ActRec.Destroy() was not called. Since you do not know the exact memory address of the object being leaked, or at least the memory address of the variable that points at the object, you cannot register it by address. However, the full version of FastMM has an overloaded RegisterExpectedMemoryLeak() function that accepts a class type and count as input. That allows you to tell FastMM how many instances of the class type are allowed to be leaked before FastMM starts reporting them as leaks. Of course, that means you need access to the class type. If it is something internal to Chromium, you may be out of luck.

FastMM4, how to read the log file?

i'am working on an software,so i have just started using FastMM4 (for real) in my project.
i have found on the net on about how to get the line number in FastMM4,i got the line number but i can figure out what does the other information in the log means?
i have this in the log file
This block was allocated by thread 0x15F8, and the stack trace (return addresses) at the time was:
402E86 [system.pas][System][System.#GetMem][2648]
403A3B [system.pas][System][System.TObject.NewInstance][8824]
403DAA [system.pas][System][System.#ClassCreate][9489]
403A70 [system.pas][System][System.TObject.Create][8839]
46A257 [u_home.pas][u_home][u_home.TForm1.SpeedButton1Click][80] {<-memory leak is here, but what are the Other detections?}
443AAC [Controls.pas][Controls][Controls.TControl.Click][5226]
46958B [Buttons.pas][Buttons][Buttons.TSpeedButton.Click][1211]
46956B [Buttons.pas][Buttons][Buttons.TSpeedButton.MouseUp][1204]
443FB2 [Controls.pas][Controls][Controls.TControl.DoMouseUp][5352]
441BA0 [Controls.pas][Controls][Controls.TControl.SetMouseCapture][4379]
444042 [Controls.pas][Controls][Controls.TControl.WMLButtonUp][5364]
The block is currently used for an object of class: TStringList
The allocation number is: 440
in this the leak is
46A257 [u_home.pas][u_home][u_home.TForm1.SpeedButton1Click][80] {<-memory leak is here, but what are the Other detections?}
my code
procedure TForm1.SpeedButton1Click(Sender: TObject);
var
str : TStringList;
begin
str := TStringList.Create; {<--im not freeing the, so leak}
end;
and here is the call stack
i searched on net but i do not know what are the other detections...
402E86 [system.pas][System][System.#GetMem][2648]
403A3B [system.pas][System][System.TObject.NewInstance][8824]
403DAA [system.pas][System][System.#ClassCreate][9489]
403A70 [system.pas][System][System.TObject.Create][8839]
{Other then this}
46A257 [u_home.pas][u_home][u_home.TForm1.SpeedButton1Click][80] {<-memory leak is here, but what are the Other detections?}
{Other then this}
443AAC [Controls.pas][Controls][Controls.TControl.Click][5226]
46958B [Buttons.pas][Buttons][Buttons.TSpeedButton.Click][1211]
46956B [Buttons.pas][Buttons][Buttons.TSpeedButton.MouseUp][1204]
443FB2 [Controls.pas][Controls][Controls.TControl.DoMouseUp][5352]
441BA0 [Controls.pas][Controls][Controls.TControl.SetMouseCapture][4379]
444042 [Controls.pas][Controls][Controls.TControl.WMLButtonUp][5364]
im using delphi 2006
i have opened and tried the same in delphi 6, delph 7 also
checked
i have found this related to fastMM$ detectiong and registration of some leaks which is already in delphi.
How to track down tricky memory leak with fastMM?
and this for registering the leak but are they bugs?
Using FastMM4, how to register leaked string?
Also FastMM4, Delphi6, Leak of TApplication?
OR are they just the steps leading to the memory leak?
What you have in the log there is the call stack that resulted in the memory allocation that leaked.
You can see how useful it is in the call stack in your question. Imagine that you only had the top line, the call that resulted in the leak
402E86 [system.pas][System][System.#GetMem][2648]
That information on its own is pretty much useless since all heap allocations go through GetMem. It is the call stack that points you to the events that led up to the call to GetMem. And that's what pinpoints what caused the leak.
FastMM has no way to guess the intention behind the code and pinpoint which instruction causing a memory allocation should have a corresponding instruction to free it.
Keep in mind that FastMM only keeps a record of all memory allocation done during the execution of your code.
It does not know why, how or where a leak occurs, just that you have not freed this particular allocation at the time when your application shuts down and everything should be clean.
So when a leak is reported, it is really an allocation that is displayed.
FastMM does not know your application and can only show the whole call-chain that leads to this specific point in code where you allocate memory (usually one of a gazillion GetMem calls).
The meaningful information can be found by going up the ladder until you find the higher level instruction that needed some memory, like a TButton.Create and see if that particular Button was freed or not (leaking all its content), or like a TMyBadButton.Create which creates some AltBitmap but never frees it.
In one case the leak is in the application code creainge a button without freeing it, in the other case, it is in the TMyBadButton component code.
Update:
You may find useful this old CodeRage session Memory Leaks for Dummies

Still get error popup even when ApplyUpdates is inside try...except

Solution found, see my comment below
D5, odbc to mysql database
This code:
with QryCmdPerf do begin
Close;
ParamByName('ACCTID').AsInteger:= AcctId;
ParamByName('FROMDT').AsString:= MySQLDate(FromDt);
ParamByName('TODT').AsString:= MySQLDate(ToDt);
Open;
first;
try
edit;
FieldByName('PnL').AsFloat:= 97979;
ApplyUpdates;
except
close;
end;
end; // with
(specifically the "ApplyUpdates") causes a popup to appear with the text "Update Failed" if the PnL field already has the value 97979, evidently because of this code:
procedure TUpdateSQL.ExecSQL(UpdateKind: TUpdateKind);
begin
with Query[UpdateKind] do
begin
Prepare;
ExecSQL;
if RowsAffected <> 1 then DatabaseError(SUpdateFailed);
end;
end;
in DBTables.pas. Anyway, I want to be able to issue ApplyUpdates, and not have to worry about a popup if it doesn't do any updating. But if "try...except" doesn't work, what will?
TIA
You're confusing the dialog displayed by the debugger with a dialog displayed by your program. Please see this article I wrote a few years ago:
Why do I continue getting error messages even after I have written an exception handler?
It describes several ways to avoid the debugger interfering:
Use "advanced breakpoints" to temporarily disable the debugger around the code that throws exceptions.
Configure the debugger to ignore certain exception types. (Read the debugger's message more carefully to see exactly what exception class you're dealing with.)
Configure the debugger not to interrupt on any exceptions.
Turn off integrated debugger entirely.
The short answer is, you have to set up an eventhandler for OnUpdateError or no amount of "try...except" blocks will block the popup. The long answer is it appears to be a bug with odbc. The repro is here: http://www.codeupload.com/3919 for anyone who wants to take a look at it. You can skip the MySQL stuff, any odbc database will do.
There are two things that can be going wrong here.
Option 1
First, some "very bad code" may be short-circuiting the unwinding of the call stack on exceptions. E.g. ApplyUpdates or one of its child routines may also have a try...except block that calls Application.HandleException directly.
To test this, if you put a breakpoint on QryCmdPerf.Close, do you reach it?
If not, then Application.HandleException (or worse Application.ShowException) has been called directly.
Solving this requires a custom exception handler hooked to the Application.OnException event. You may have to set temporary state to know when this particular exception can be ignored.
Yes it's messy, that why calling Application.HandleException directly, is "very bad code".
Option 2
If you do reach the breakpoint, but the exception is being raised again, then it should be a lot simpler to solve.
The Close method is probably attempting to save any pending changes, so is effectively applying the updates again. Rather than simply closing the data set, call CancelChanges or equivalent.

What is the right tool to detect VMT or heap corruption in Delphi?

I'm a member in a team that use Delphi 2007 for a larger application and we suspect heap corruption because sometimes there are strange bugs that have no other explanation.
I believe that the Rangechecking option for the compiler is only for arrays. I want a tool that give an exception or log when there is a write on a memory address that is not allocated by the application.
Regards
EDIT: The error is of type:
Error: Access violation at address 00404E78 in module 'BoatLogisticsAMCAttracsServer.exe'. Read of address FFFFFFDD
EDIT2: Thanks for all suggestions. Unfortunately I think that the solution is deeper than that. We use a patched version of Bold for Delphi as we own the source. Probably there are some errors introduced in the Bold framwork. Yes we have a log with callstacks that are handled by JCL and also trace messages. So a callstack with the exception can lock like this:
20091210 16:02:29 (2356) [EXCEPTION] Raised EBold: Failed to derive ServerSession.mayDropSession: Boolean
OCL expression: not active and not idle and timeout and (ApplicationKernel.allinstances->first.CurrentSession <> self)
Error: Access violation at address 00404E78 in module 'BoatLogisticsAMCAttracsServer.exe'. Read of address FFFFFFDD. At Location BoldSystem.TBoldMember.CalculateDerivedMemberWithExpression (BoldSystem.pas:4016)
Inner Exception Raised EBold: Failed to derive ServerSession.mayDropSession: Boolean
OCL expression: not active and not idle and timeout and (ApplicationKernel.allinstances->first.CurrentSession <> self)
Error: Access violation at address 00404E78 in module 'BoatLogisticsAMCAttracsServer.exe'. Read of address FFFFFFDD. At Location BoldSystem.TBoldMember.CalculateDerivedMemberWithExpression (BoldSystem.pas:4016)
Inner Exception Call Stack:
[00] System.TObject.InheritsFrom (sys\system.pas:9237)
Call Stack:
[00] BoldSystem.TBoldMember.CalculateDerivedMemberWithExpression (BoldSystem.pas:4016)
[01] BoldSystem.TBoldMember.DeriveMember (BoldSystem.pas:3846)
[02] BoldSystem.TBoldMemberDeriver.DoDeriveAndSubscribe (BoldSystem.pas:7491)
[03] BoldDeriver.TBoldAbstractDeriver.DeriveAndSubscribe (BoldDeriver.pas:180)
[04] BoldDeriver.TBoldAbstractDeriver.SetDeriverState (BoldDeriver.pas:262)
[05] BoldDeriver.TBoldAbstractDeriver.Derive (BoldDeriver.pas:117)
[06] BoldDeriver.TBoldAbstractDeriver.EnsureCurrent (BoldDeriver.pas:196)
[07] BoldSystem.TBoldMember.EnsureContentsCurrent (BoldSystem.pas:4245)
[08] BoldSystem.TBoldAttribute.EnsureNotNull (BoldSystem.pas:4813)
[09] BoldAttributes.TBABoolean.GetAsBoolean (BoldAttributes.pas:3069)
[10] BusinessClasses.TLogonSession._GetMayDropSession (code\BusinessClasses.pas:31854)
[11] DMAttracsTimers.TAttracsTimerDataModule.RemoveDanglingLogonSessions (code\DMAttracsTimers.pas:237)
[12] DMAttracsTimers.TAttracsTimerDataModule.UpdateServerTimeOnTimerTrig (code\DMAttracsTimers.pas:482)
[13] DMAttracsTimers.TAttracsTimerDataModule.TimerKernelWork (code\DMAttracsTimers.pas:551)
[14] DMAttracsTimers.TAttracsTimerDataModule.AttracsTimerTimer (code\DMAttracsTimers.pas:600)
[15] ExtCtrls.TTimer.Timer (ExtCtrls.pas:2281)
[16] Classes.StdWndProc (common\Classes.pas:11583)
The inner exception part is the callstack at the moment an exception is reraised.
EDIT3: The theory right now is that the Virtual Memory Table (VMT) is somehow broken. When this happen there is no indication of it. Only when a method is called an exception is raised (ALWAYS on address FFFFFFDD, -35 decimal) but then it is too late. You don't know the real cause for the error. Any hint of how to catch a bug like this is really appreciated!!! We have tried with SafeMM, but the problem is that the memory consumption is too high even when the 3 GB flag is used. So now I try to give a bounty to the SO community :)
EDIT4: One hint is that according the log there is often (or even always) another exception before this. It can be for example optimistic locking in the database. We have tried to raise exceptions by force but in test environment it just works fine.
EDIT5: Story continues... I did a search on the logs for the last 30 days now. The result:
"Read of address FFFFFFDB" 0
"Read of address FFFFFFDC" 24
"Read of address FFFFFFDD" 270
"Read of address FFFFFFDE" 22
"Read of address FFFFFFDF" 7
"Read of address FFFFFFE0" 20
"Read of address FFFFFFE1" 0
So the current theory is that an enum (there is a lots in Bold) overwrite a pointer. I got 5 hits with different address above. It could mean that the enum holds 5 values where the second one is most used. If there is an exception a rollback should occur for the database and Boldobjects should be destroyed. Maybe there is a chance that not everything is destroyed and a enum still can write to an address location. If this is true maybe it is possible to search the code by a regexpr for an enum with 5 values ?
EDIT6: To summarize, no there is no solution to the problem yet. I realize that I may mislead you a bit with the callstack. Yes there are a timer in that but there are other callstacks without a timer. Sorry for that. But there are 2 common factors.
An exception with Read of address FFFFFFxx.
Top of callstack is System.TObject.InheritsFrom (sys\system.pas:9237)
This convince me that VilleK best describe the problem.
I'm also convinced that the problem is somewhere in the Bold framework.
But the BIG question is, how can problems like this be solved ?
It is not enough to have an Assert like VilleK suggest as the damage has already happened and the callstack is gone at that moment. So to describe my view of what may cause the error:
Somewhere a pointer is assigned a bad value 1, but it can be also 0, 2, 3 etc.
An object is assigned to that pointer.
There is method call in the objects baseclass. This cause method TObject.InheritsForm to be called and an exception appear on address FFFFFFDD.
Those 3 events can be together in the code but they may also be used much later. I think this is true for the last method call.
EDIT7: We work closely with the the author of Bold Jan Norden and he recently found a bug in the OCL-evaluator in Bold framework. When this was fixed these kinds of exceptions decreased a lot but they still occasionally come. But it is a big relief that this is almost solved.
You write that you want there to be an exception if
there is a write on a memory address that is not allocated by the application
but that happens anyway, both the hardware and the OS make sure of that.
If you mean you want to check for invalid memory writes in your application's allocated address range, then there is only so much you can do. You should use FastMM4, and use it with its most verbose and paranoid settings in debug mode of your application. This will catch a lot of invalid writes, accesses to already released memory and such, but it can't catch everything. Consider a dangling pointer that points to another writeable memory location (like the middle of a large string or array of float values) - writing to it will succeed, and it will trash other data, but there's no way for the memory manager to catch such access.
I don't have a solution but there are some clues about that particular error message.
System.TObject.InheritsFrom subtracts the constant vmtParent from the Self-pointer (the class) to get pointer to the adress of the parent class.
In Delphi 2007 vmtParent is defined:
vmtParent = -36;
So the error $FFFFFFDD (-35) sounds like the class pointer is 1 in this case.
Here is a test case to reproduce it:
procedure TForm1.FormCreate(Sender: TObject);
var
I : integer;
O : tobject;
begin
I := 1;
O := #I;
O.InheritsFrom(TObject);
end;
I've tried it in Delphi 2010 and get 'Read of address FFFFFFD1' because the vmtParent is different between Delphi versions.
The problem is that this happens deep inside the Bold framework so you may have trouble guarding against it in your application code.
You can try this on your objects that are used in the DMAttracsTimers-code (which I assume is your application code):
Assert(Integer(Obj.ClassType)<>1,'Corrupt vmt');
It sounds like you have memory corruption of object instance data.
The VMT itself isn't getting corrupted, FWIW: the VMT is (normally) stored in the executable and the pages that map to it are read-only. Rather, as VilleK says, it looks like the first field of the instance data in your case got overwritten with a 32-bit integer with value 1. This is easy enough to verify: check the instance data of the object whose method call failed, and verify that the first dword is 00000001.
If it is indeed the VMT pointer in the instance data that is being corrupted, here's how I'd find the code that corrupts it:
Make sure there is an automated way to reproduce the issue that doesn't require user input. The issue may be only reproducible on a single machine without reboots between reproductions owing to how Windows may choose to lay out memory.
Reproduce the issue and note the address of the instance data whose memory is corrupted.
Rerun and check the second reproduction: make sure that the address of the instance data that was corrupted in the second run is the same as the address from the first run.
Now, step into a third run, put a 4-byte data breakpoint on the section of memory indicated by the previous two runs. The point is to break on every modification to this memory. At least one break should be the TObject.InitInstance call which fills in the VMT pointer; there may be others related to instance construction, such as in the memory allocator; and in the worst case, the relevant instance data may have been recycled memory from previous instances. To cut down on the amount of stepping needed, make the data breakpoint log the call stack, but not actually break. By checking the call stacks after the virtual call fails, you should be able to find the bad write.
mghie is right of course. (fastmm4 calls the flag fulldebugmode or something like that).
Note that that works usually with barriers just before and after an heap allocation that are regularly checked (on every heapmgr access?).
This has two consequences:
the place where fastmm detects the error might deviate from the spot where it happens
a total random write (not overflow of existing allocation) might not be detected.
So here are some other things to think about:
enable runtime checking
review all your compiler's warnings.
Try to compile with a different delphi version or FPC. Other compilers/rtls/heapmanagers have different layouts, and that could lead to the error being caught easier.
If that all yields nothing, try to simplify the application till it goes away. Then investigate the most recent commented/ifdefed parts.
The first thing I would do is add MadExcept to your application and get a stack traceback that prints out the exact calling tree, which will give you some idea what is going on here. Instead of a random exception and a binary/hex memory address, you need to see a calling tree, with the values of all parameters and local variables from the stack.
If I suspect memory corruption in a structure that is key to my application, I will often write extra code to make tracking this bug possible.
For example, in memory structures (class or record types) can be arranged to have a Magic1:Word at the beginning and a Magic2:Word at the end of each record in memory. An integrity check function can check the integrity of those structures by looking to see for each record Magic1 and Magic2 have not been changed from what they were set to in the constructor. The Destructor would change Magic1 and Magic2 to other values such as $FFFF.
I also would consider adding trace-logging to my application. Trace logging in delphi applications often starts with me declaring a TraceForm form, with a TMemo on there, and the TraceForm.Trace(msg:String) function starts out as "Memo1.Lines.Add(msg)". As my application matures, the trace logging facilities are the way I watch running applications for overall patterns in their behaviour, and misbehaviour. Then, when a "random" crash or memory corruption with "no explanation" happens, I have a trace log to go back through and see what has lead to this particular case.
Sometimes it is not memory corruption but simple basic errors (I forgot to check if X is assigned, then I go dereference it: X.DoSomething(...) that assumes X is assigned, but it isn't.
I Noticed that a timer is in the stack trace.
I have seen a lot of strange errors where the cause was the timer event is fired after the form i free'ed.
The reason is that a timer event cound be put on the message que, and noge get processed brfor the destruction of other components.
One way around that problem is disabling the timer as the first entry in the destroy of the form. After disabling the time call Application.processMessages, so any timer events is processed before destroying the components.
Another way is checking if the form is destroying in the timerevent. (csDestroying in componentstate).
Can you post the sourcecode of this procedure?
BoldSystem.TBoldMember.CalculateDerivedMemberWithExpression
(BoldSystem.pas:4016)
So we can see what's happening on line 4016.
And also the CPU view of this function?
(just set a breakpoint on line 4016 of this procedure and run. And copy+paste the CPU view contents if you hit the breakpoint). So we can see which CPU instruction is at address 00404E78.
Could there be a problem with re-entrant code?
Try putting some guard code around the TTimer event handler code:
procedure TAttracsTimerDataModule.AttracsTimerTimer(ASender: TObject);
begin
if FInTimer then
begin
// Let us know there is a problem or log it to a file, or something.
// Even throw an exception
OutputDebugString('Timer called re-entrantly!');
Exit; //======>
end;
FInTimer := True;
try
// method contents
finally
FInTimer := False;
end;
end;
N#
I think there is another possibility: the timer is fired to check if there are "Dangling Logon Sessions". Then, a call is done on a TLogonSession object to check if it may be dropped (_GetMayDropSession), right? But what if the object is destroyed already? Maybe due to thread safety issues or just a .Free call and not a FreeAndNil call (so a variable is still <> nil) etc etc. In the mean time, other objects are created so the memory gets reused. If you try to acces the variable some time later, you can/will get random errors...
An example:
procedure TForm11.Button1Click(Sender: TObject);
var
c: TComponent;
i: Integer;
p: pointer;
begin
//create
c := TComponent.Create(nil);
//get size and memory
i := c.InstanceSize;
p := Pointer(c);
//destroy component
c.Free;
//this call will succeed, object is gone, but memory still "valid"
c.InheritsFrom(TObject);
//overwrite memory
FillChar(p, i, 1);
//CRASH!
c.InheritsFrom(TObject);
end;
Access violation at address 004619D9 in module 'Project10.exe'. Read of address 01010101.
Isn't the problem that "_GetMayDropSession" is referencing a freed session variable?
I have seen this kind of errors before, in TMS where objects were freed and referenced in an onchange etc (only in some situations it gave errors, very difficult/impossible to reproduce, is fixed now by TMS :-) ). Also with RemObjects sessions I got something similar (due to bad programming bug by myself).
I would try to add a dummy variable to the session class and check for it's value:
public variable iMagicNumber: integer;
constructor create: iMagicNumber := 1234567;
destructor destroy: iMagicNumber := -1;
"other procedures": assert(iMagicNumber = 1234567)

Resources