![]() |
EurekaLog causes AccessViolation?
We were contacted by a person who complained that his application was working fine until he added EurekaLog to it. An AccessViolation exception was raised after adding EurekaLog to project. The message was: "Access violation at address 00E15025 in module 'Project.exe'. Read of address 83EC8B69". And the stack was:
The person did not want to provide a reproducible example, but, fortunately, we had access to the source code of the library. The address in the error message (83EC8B69 - e.g. "random") and the short stack may indicate a problem like "execution flow followed a trash pointer and crashed in a random place". Unfortunately, the report did not include the CPU and assembler sections (were disabled in the settings). In this case, diagnostics based on the source code alone would be impossible. Frankly, at first I wanted to answer this way, giving a recommendation to strengthen control over memory. But just such a stack is also possible if the BasePerform is called by the main thread as a procedure queued for Synchronize. Indeed, a search through the source code revealed the following code: function TContosoEventMessage.Perform(AThread: TContosoThread): Boolean; begin FMsgThread := AThread as TContosoEventThread; if FMsgThread.Active then begin if FMsgThread.Options.Synchronize then TContosoThread.Queue(nil, BasePerform) else BasePerform; end; Result := True; end; E.g. the message class has a function to handle/process this message. And if a Synchronize flag is specified in the options of something, then the message processing (BasePerform) will be performed not in the current thread, but will be sent for execution to the main thread - through ![]() And yes, the report also shows this background thread from Contoso that could have executed such code. The method BasePerform itself is just a wrapper around InternalHandle: procedure TContosoEventMessage.BasePerform; begin FMsgThread.InternalHandle(Self); end; And the EurekaLog report shows that the crash occurred on the very first line. What do we have?
E.g. it seems like there is a problem with memory. And by the way, this is the most common "problem" of projects that include EurekaLog. Indeed, consider this code: procedure TForm1.Button1Click(Sender: TObject); var List: TList; begin List := TList.Create; List.Free; List.Clear; // - accesses already deleted object end; Is this a correct code? Of course not. But will it "work"? Yes, it will work correctly with a high probability. This happens for the simple reason that the "freed" memory (and, therefore, the "freed" object) is not actually deleted, but simply marked as free. E.g. their memory remains available unchanged. Of course, if there are many operations between releasing memory/object and re-accessing it, then there is some chance that these operation will change the former memory. But you won't even notice the problem on short runs. Adding EurekaLog to the program changes the situation radically, since EurekaLog enables memory checks by default and actively fights these bugs. Well, let's see if we can have such a situation now. Since FMsgThread comes from a method's argument, let's see who is calling the method BasePerform. A search through the source code suggested the following code (actually, the search highlighted several places, but a specific place was chosen based on the state of the background thread from the report): procedure TContosoThread.Execute; // ... begin // ... for i := 0 to oReceivedMsgs.Count - 1 do begin oMsg := TContosoThreadMsgBase(oReceivedMsgs[i]); try if not oMsg.Perform(Self) then Break; finally oMsg.Destroy; end; // ... end; Oops, here it is. Scenario of what is happening:
In fact, the subclass clearly violated an implicit contract: all function's arguments are valid only for the duration of the function call. E.g. if you store the arguments to a function somewhere where they will be available after the function completes - then you must ensure that the arguments are available. The subclass did not. I suspect that fixing the bug will be replacing Queue with Synchronize. Here is how an investigation turned out - solely on the source code of an unfamiliar library and an incomplete crash report, without having a working example. ![]() ![]() ![]() ![]() ![]() ![]() http://feeds.feedburner.com/~r/EurekaLog/~4/0eTp_BlIUMs ![]() |
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:47 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz