How to force LeakCheck Delphi library to not collect data? - delphi

I use Delphi's LeakCheck library https://bitbucket.org/shadow_cs/delphi-leakcheck.
I know I can disable leak reporting using a construct like this:
{$IFDEF DEBUG}
System.ReportMemoryLeaksOnShutdown := true; // this will enable LeakCheck to display a message on Windows
{$ELSE}
System.ReportMemoryLeaksOnShutdown := false;
{$ENDIF}
But I also need the library to NOT collect any data when compiled in RELEASE mode.
I can easily "hack" the LeakCheck.pas initialization/finalization sections like this:
...
{$IFDEF DEBUG} // <--- Code added by me
initialization
TLeakCheck.Initialize;
finalization
TLeakCheck.Finalize;
{$ENDIF} // <--- Code added by me
end.
Is there any better way? A conditional define I miss or a global property?

I don't use the specific library (LeakCheck) you mention, but I typically do this by only including the unit when the right configuration is defined (in this case, DEBUG). This means that in release it's not even included in the executable.
uses
...,
{$IFDEF Debug}
LeakCheck,
{$ENDIF}
...;
As is pointed out in a comment, LeakCheck has to be the first unit listed in the .dpr's uses clause, which may cause an occasional problem with the IDE; it sometimes ends up breaking due to the {$IFDEF}. I usually don't find this to be a major issue, because once it happens and you've seen what the cause is, it's pretty easy to just go back in and fix it.
If that becomes too much of an issue, there is another workaround - create a new unit that does nothing but use LeakCheck and SysUtils, and add the above {$IFDEF} in that unit. You then include the new unit first in your .dpr. As it's only task is actually to use LeakCheck, it still puts LeakCheck in first-compile order in the .dpr when needed, and does not include it at all when not.

Related

How can I detect from code when FastMM4 is used

I want to show a label on a form when FastMM4 is being used ('Uses' in the project file), so that I don't make the mistake of giving the executable to someone who doesn't have FastMM_FullDebugMode.dll installed.
I tried these, but they have are no effect:
{$ifdef FullDebugMode}
LblFastMM4.Visible := true;
{$endif}
{$ifdef EnableMemoryLeakReporting}
LblFastMM4.Visible := true;
{$endif}
How can I detect FastMM4 at runtime?
Note: I don't 'officially' distribute the app with FastMM4. This is just a reminder to myself when I want to give the alpha version to a non-technical user for a quick look. It's annoying if they then bump into the error.
Your {$ifdef}'s don't work because your own code is not including FastMM4Options.inc directly, so FastMM's conditionals are not defined in scope of your code. They are only defined in scope of FastMM's code. You can't test for conditionals that are {$define}'d in someone else's unit.
However, you can use {$If Declared(...)} to check for public symbols that are in scope from using another unit. In this case, the interface section of FastMM4.pas declares various symbols under certain conditions, for instance TRegisteredMemoryLeak when EnableMemoryLeakReporting is defined, DebugGetMem when FullDebugMode is defined, etc.
{$if declared(DebugGetMem)}
LblFastMM4.Visible := true;
{$endif}
{$if declared(TRegisteredMemoryLeak)}
LblFastMM4.Visible := true;
{$endif}
A lot of options can be configured for FastMM. In your case the option DoNotInstallIfDLLMissing can be of value. A nice application is available for setting options: https://jedqc.blogspot.com/2007/07/new-fastmm4-options-interface.html
try this:
LblFastMM4.Visible := InitializationCodeHasRun;

How to determine dependencies for all units? (Estimate refactoring cost)

Unfortunately I have inherited a piece of unlucky design based on a {$IFDEF} "hell".
What I have roughly looks like this (where MyDbSystemB is what I want to add)
unit MyTable;
interface
uses
// ...
{$IFDEF MyDbSystemA}
DbSystemA ,
{$ENDIF}
{$IFDEF MyDbSystemB}
DbSystemB ,
{$ENDIF}
type
TMyTable = class(
{$IFDEF MyDbSystemA}
TSystemATable
{$ENDIF}
{$IFDEF MyDbSystemB}
TSystemBTable
{$ENDIF}
)
// A public interface implementation
end;
implementation
// ...
end.
A number of units reference TMyTable, but rely on specific functions provided with TSystemATable:
unit oldUnit;
interface
uses MyDbTable;
type
TXy = class(TXyz)
public
procedure Foo();
end;
implementation
procedure TXy.Foo();
var
table : TMyTable;
begin
table := TMyTable.Create();
table.SomeSystemASpecificFunction;
end;
I'd like to find all of these references within a single reference/syntax check. But as I read here that's apparently not really possible
Find all compilation errors in a Delphi project.
What would be the best strategy to go for finding these files to estimate the efforts of porting?
A plain file grep over all *.pas files (there may be a lot of either dead code, or just poorly decoupled stuff)?
I'm also able to provide a surrogate implementation of
TMyTable = class( { ... like above } )
{$IFDEF MyDbSystemB}
public
procedure SomeSystemASpecificFunction; deprecated;
{$ENDIF}
end;
with the implementation of TMyTable, but I'd need to estimate the refactoring cost to do that properly anyways.
Regarding that I also could add a deprecated attribute along with the SomeSystemASpecificFunction surrogate, that will at least give me warnings.
If you know the names of the members of TMyTableA that code takes a dependency on then use Find in Files... (or your favorite alternative grep-like tool) to identify references to those members in the files in your project.
This is likely to be more reliable than any compilation based check anyway.
Any tool which claims to find "all compilation errors in a project" is more often than not lying to you since there is no reliable way to discriminate between errors that have not arisen as a result of some other error earlier in the compilation.
e.g. in a C# solution it is quite common for a simple change to result in dozens if not hundreds of compilation errors which are fixed by resolving only the first error.
i.e. the compiler reports (e.g.) 224 errors when in fact there is only 1 error with 223 errors as a side-effect.
For the same reason, you cannot be sure that the list of errors contains all of the genuine errors you might eventually uncover. In some cases the compiler might yet be defeated to the point of not even attempting to compile some code that contains the errors you are looking for, as a consequence of those side-effect errors.
Certainly, in the list of dozens or hundreds of errors you might then be able to grep to find ones that appear to be candidates for the "genuine" errors you are looking for (i.e. that reference the specific members you know to be involved in your change). But all that does is change the data set you are searching for to locate those references. i.e. the compilation error list rather than your project sources.

Finalization of a log unit called too early

I am running a ISAPI service which runs with IdHTTPWebBrokerBridge (for debugging as standalone EXE) as well as in Apache with mod_isapi (in productive enviroment).
While logging some stuff at the destruction of the web module, I found following problem:
unit LogFactory;
...
initialization
GlobalLogFactory := TMyLogFactory.Create;
finalization
FreeAndNil(GlobalLogFactory);
end.
-
unit MyWebModuleUnit;
...
uses LogFactory;
procedure TMyWebModule.WebModuleDestroy(Sender: TObject);
begin
Assert(Assigned(GlobalLogFactory)); // <-- failure
GlobalLogFactory.GetLogger('D:\test.txt').LogLine('test'); // <-- Nullpointer Exception
end;
LogFactory.pas creates the object GlobalLogFactory on its initialization and destroys it on its finalization.
But LogFactory.pas:finalization gets called BEFORE TMyWebModule.WebModuleDestroy , since it was included by this unit only, and so the finalization will be done in reverse order.
How can I ensure that my GlobalLogFactory will be correctly freed (i.e. FastMM will not warn about a memory leak), but at the same time, I want to give all destruction/finalization-procedures the chance to log something?
One Workaround would be to include LogFactory.pas explicitely in the DPR file as the first unit. But I don't like that very much, since this Log-Unit should be used in many projects and it should be useable by simply including it in the unit where you need to log something. Putting this log unit in every DPR which might want to log something in future, is a big effort and forgetting it might cause problems for the developers who are not knowing what I did/require.
Instad of using a class instance in a global variable use an interface and a function to get that.
unit LogFactory;
interface
type
ILogFactory = interface
[{GUID}]
function GetLogger(...) : TLogger;
...
end;
TLogFactory = class( TInterfacedObject, ILogFactory )
function GetLogger(...) : TLogger;
end;
function GlobalLogFactory : ILogFactory;
implementation
var
_LogFactory : ILogFactory;
function GlobalLogFactory : ILogFactory;
begin
if not Assigned( _LogFactory ) then
_LogFactory := TLogFactory.Create;
Result := _LogFactory;
end;
{ TLogFactory Implementation }
initialization
// nothing needed
finalization
// nothing needed
end.
There is no need for any initialization or finalization at all.
If you want
Any unit in your program to be able to log, and
Logging to be available during finalization, and
The logging code to require tidy up,
then you don't have many options. One option is to include the log unit very early in the .dpr file. I don't know why you regard that to be a problem. It's the standard way to achieve your goals. It's the technique used by external memory managers for example. Delphi developers are familiar with the concept. You tell the developers what they need to do, and if they don't follow your instructions, the program does not work. That is their problem.
If you still cannot face doing it this way then I see one alternative. Arrange for the logger initialization to happen before any other initialization in your code. And the finalization after all other finalization. You can do that by putting the logger implementation into an external module that is linked with load time linking.

Can't catch access violation

We have a Delphi app that has been running for a few years and now suddenly we get weird access violations. We used Eurekalog to trace where it comes from and this is even more weird. They are so far all on the Free call of an object, but inside a try except block. One of them is even in 2 try except blocks and still when the Access Violation occurs it jumps totally out of the program and ignores the try excepts, nothing excepts EurekaLog catches it at the end. Really confused on why this is suddenly happening (both instances are old code that has not been touched for years and also other codes changes is not related to it).
A example of the code is
try
if Assigned(ClientCommunication) then begin
if ClientCommunication.isConnected then begin
if ClientCommunication.closeServerConnection then begin
try
ClientCommunication.Free;
ClientCommunication := nil;
Except
on e:Exception do begin
ClientCommunication := nil; //suppress weird AV error.. get read for new object
end
end;
Now the last try except was added later to try and suppress the AV as we just want the object cleared to be restarted if required, but this is mostly called when closing the app. But it still just jumps out of that and I can’t catch it at all.
It works on our developers PCs and not at the client.
If this line: ClientCommunication.Free; is causing an exception.
There are a few things you can do here.
FreeAndNil
Replace calls to AObject.free with calls to freeandnil(AObject).
If you just do the free, the old pointer will still have a non-nil reference and Assigned(AObject) will not be able to tell a freed and active object apart.
Beware of clones
Another mistake you may make is that you've cloned the object like so:
Object1:= TObject1.Create;
//.... lots of code
Object2:= Object1;
//.... lots of code
FreeAndNil(Object2); <<-- freeing the clone-reference is a mistake
//.... lots of code
Object1.Free; <<-- exception: it's already freed
FastMM4 options
Download the latest FastMM4 from http://sourceforge.net/projects/fastmm/
It has a few extra bells and whistles from the one included with Delphi.(*)
Among those whistles is an extra diagnostic mode that makes your program dead slow, but also catches out a lot of those heap corruption bugs you seem to be suffering from.
Open up defines.inc and change this:
{$ifdef DEBUG}
{.$define EnableMemoryLeakReporting}
{.$define FullDebugMode}
{.$define RawStackTraces}
{$endif DEBUG}
Into this
{$ifdef DEBUG}
{$define EnableMemoryLeakReporting}
{$define FullDebugMode}
{$define RawStackTraces}
{$define CatchUseOfFreedInterfaces} <<-- very useful
{$define LogMemoryLeakDetailToFile}
{$define LogErrorsToFile}
{$define CheckHeapForCorruption} <<-- :-)
{$endif}
There's a nice article here: http://wiert.me/2009/07/29/delphi-fastmm-using-fastmm4-for-debugging-your-memory-allocations-part-1-introduction/
If you don't feel like mucking about with the inc file, there a little utility that will do it for you at: http://jedqc.blogspot.com/2007/07/new-fastmm4-options-interface.html
(*) I think the Delphi one has most of the debug stuff as well, but not 100% sure. Regardless can't hurt to get the latest (greatest) version.
Or buffer overflow
If your ClientCommunication object has some internal structure free will do extra work.
Imagine the following code:
TUnrelatedObject = class
buffer: array[0..99] of integer;
procedure DoWork;
end;
TUnrelatedObject.DoWork;
var
i: integer;
begin
for i:= 0 to 100 do buffer[i]:= maxint; <<-- buffer overrun
end;
Imagine that ClientCommunication is right next to UnrelatedObject in the heap.
The call to DoWork will overwrite data of ClientCommunication as well.
This may or may not trigger an access violation in DoWork. If it doesn't then the error will be very hard to trace, because it will show up in a different and totally unrelated places.
Enable range checking {$R+} in your application.
Warning
Remember to not ship the debug version to your clients.
With all the debugging your program will be dead slow.

Does Delphi compiler perform optimization?

I am using Delphi 7 IDE. Does Delphi compiler optimize codes, just like what the C++ compiler is doing in this following link?
http://msdn.microsoft.com/en-us/library/aa366877(VS.85).aspx
WCHAR szPassword[MAX_PATH];
// Retrieve the password
if (GetPasswordFromUser(szPassword, MAX_PATH))
UsePassword(szPassword);
// Clear the password from memory
SecureZeroMemory(szPassword, sizeof(szPassword));
If ZeroMemory were called in this example instead of SecureZeroMemory, the compiler could optimize the call because the szPassword buffer is not read from before it goes out of scope. The password would remain on the application stack where it could be captured in a crash dump or probed by a malicious application.
Yes, of course Delphi performs optimizations. However, it does not perform the optimization that the SecureZeroMemory function is meant to circumvent. There is no need to use that function in Delphi; just use plain old ZeroMemory, or even FillChar. They're not macros, and they don't do anything that Delphi recognizes as being unused assignment statements that could get optimized out.
Delphi performs code optimization by default, you can disable it in Project > Options > Compiler.
The Delphi help provide a few tips of what type of optimizations are used:
The $O directive controls code optimization. In the {$O+} state, the compiler performs a number of code optimizations, such as placing variables in CPU registers, eliminating common subexpressions, and generating induction variables.
It also states that "the compiler performs no "unsafe" optimizations", but in the sense that they won't alter the execution path, not from a security point of view.
Delphi certainly optimizes code (it is a modern, and excellent, compiler). Another example of optimization deleting lines is:
SomeFunction(); // Set breakpoint here, then step (F10)
myInt := 7; // Next line will not hit this...
myInt := 13; // ...but will instead skip to here
I like to ensure optimization is in the correct state (and not accidentally left switched on or off) by adding {$I MyProjectOptions.inc} in every .pas file in my project. This goes just below the unit name (right at the top of the file). In "MyProjectOptions.inc" you simply add this code:
// Is this a debug or non-debug build?
{$IF Defined(DEBUG)}
{$O-} // Turn optimization off
{$ELSEIF Defined(NDEBUG)}
{$O+} // Ensure optimisation is on
{$IFEND}
Finally, ensure you have defined "DEBUG" and "NDEBUG" (or your equivalent in older versions of Delphi) in the Conditional defines section of Project > Options > Diectories/Conditionals.
I don't believe the compiler will ever eliminate apparently dead code like this. I have never had trouble setting breakpoints on code that could have been eliminated as redundant.
For some scenarios, the compiler can detect if the code is unreachable and eliminate the code.
For instance, the compiler correctly eliminates the "unreachable" portion of the code below.
It will not generate code for that line so:
So there are no blue bullets indicating there is code
Breakpoints put on that line will be marked visually as 'not reachable'
Just tested in Delphi XE, but older Delphi versions have similar behaviour.
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils;
procedure Test;
begin
if (True = False) then
Writeln('Unreachable')
else
Writeln('Reachable');
end;
begin
try
Test();
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
It takes quite some while to learn when (or when not) the optimizer on code level and liker level kicks in.
For instance: When you have optimizations turned on, the compiler will also eliminate variables as soon as they are not used.
Sometimes, it even eliminates global symbols.
Danny Thorpe (former Delphi Compiler engineer and Chief Scientist) once wrote a magic method Touch that prevents this.
Just call this Touch method at the end of your method to fool the optimizer during debugging:
procedure Touch(var arg);
begin
end;
--jeroen

Resources