The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 2,431 other followers

Archive for the ‘Conference Topics’ Category

“Unexpected Memory Leak” after “MyTestApplication.exe: Memory Leak Detected”

Posted by jpluimers on 2021/07/28

Sometimes after a regular FastMM memory leak test report you get a dialog like this:

---------------------------
Unexpected Memory Leak
---------------------------
An unexpected memory leak has occurred. The unexpected small block leaks are:

61 - 68 bytes: Unknown x 1
---------------------------
OK   
---------------------------

The normal FastMM memory leak reporting dialog looks like this:

---------------------------
MyTestApplication.exe: Memory Leak Detected
---------------------------
...
Note: Memory leak detail is logged to a text file in the same folder as this application. To disable this memory leak check, undefine "EnableMemoryLeakReporting".
---------------------------
OK   
---------------------------

Searching for “Unexpected Memory Leak” in RTL or FastMM code did not reveal results, but that might be me not doing a proper search.

One big problem is that the regular memory leak dialog is being suppressed by setting SuppressMessageBoxes to True (see for instance my blog post Application shutdown: wait for all threads to terminate or not? or [WayBack] delphi – Generating a FASTMM report WITHOUT the shutdown dialog – Stack Overflow).

However the “Unexpected Memory Leak” message box is always shown.

Research

Location of the error message caption

  • GETMEM.INC has an identifier LeakMessageTitle:
    LeakMessageTitle: _PAnsiChr = 'Unexpected Memory Leak';
  • Unlike FastMM4.pas, GETMEM.INC does not take into account SuppressMessageBoxes.
  • Like FastMM4.pas, GETMEM.INC does take into account ReportMemoryLeaksOnShutdown.

More on GETMEM.INC: [WayBack] delphi – Reporting memory leaks on shutdown with a console application – Stack Overflow

Versioned FastMM4.pas.

Complicating the hunt

Not all allocations go via the memory manager. A complicating factor is that:

  • ALL TMonitor.Create allocations go through SysAllocMem:
class function TMonitor.Create: PMonitor;
begin
  if CacheLineSize = 0 then
    AtomicExchange(CacheLineSize, GetCacheLineSize);
  if (CPUCount > 1) and (FDefaultSpinCount = 0) then
    AtomicExchange(FDefaultSpinCount, 1000);
  if CacheLineSize > SizeOf(Result^) then
    Result := SysAllocMem(CacheLineSize)
  else
    Result := SysAllocMem(SizeOf(Result^));
  Result.FSpinCount := FDefaultSpinCount;
end;
  • ALL TMonitor.Destroy deallocations go through SysFreeMem:
procedure TMonitor.Destroy;
begin
  if (MonitorSupport <> nil) and (FLockEvent <> nil) then
    MonitorSupport.FreeSyncObject(FLockEvent);
  SysFreeMem(@Self);
end;

Debugging this is easiest to set a breakpoint in the FastMM4.pas finalization section enabling a breakpoint group that has breakpoints on these methods inside GETMEM.INC:

  • function SysGetMem(Size: NativeInt): Pointer;
  • function SysFreeMem(P: Pointer): Integer;
  • function SysReallocMem(P: Pointer; Size: NativeInt): Pointer;
  • function SysAllocMem(Size: NativeInt): Pointer;

For inspecting for instance an asm construct like TSmallPoolBlockPoolHeader[edx], use a conversion PSmallBlockPoolHeader(Pointer(EDX))^,r

Poor mans shotgun approach

This will hide all the SysAllocMem related leaks:

unit FastMM4WrapperUnit;

interface

{$ifdef UseFastMM4}
uses
  FastMM4,
  FastMM4Messages;
{$endif UseFastMM4}

implementation

initialization
//
finalization
// Disable GETMEM.INC reports that neglect SuppressMessageBoxes and NoErrMsg; this will effectively hide the leak as GETMEM.INC also does not write the leaks to a log file
{$ifdef UseFastMM4}
  if SuppressMessageBoxes then
  begin
    {$WARN SYMBOL_PLATFORM OFF} NoErrMsg := True {$WARN SYMBOL_PLATFORM ON}; // no ShowMessage from the RTL (except for memory leaks)
    ReportMemoryLeaksOnShutdown := False; // No ShowMessage from the RTL in the GETMEM.INC teardown
  end;
{$endif UseFastMM4}
end.

IsConsole: needs linker option

Note that I tried embedding this in the then portion, but enabling IsConsole fails:

    IsConsole := True; // can only force run-time error messages to be written to the console if the "Project/Options/Linking/Generate console application" is set.

The reason is that this does not allocate a console handle, so you really need to ensure the linker has allocated a console for you by enabling Project/Options/Linking/Generate console application (or option DCC_ConsoleTarget in the .dproj file)

For more details, see my post console – When is System.IsConsole true in Delphi? – Stack Overflow.

–jeroen

Posted in Conference Topics, Conferences, Delphi, Development, Event, FastMM, Software Development | Leave a Comment »

console – When is System.IsConsole true in Delphi? – Stack Overflow

Posted by jpluimers on 2021/07/22

Some highlights from [WayBack] console – When is System.IsConsole true in Delphi? – Stack Overflow:

  • Project/Options/Linking/Generate console application and {$APPTYPE CONSOLE} are two separate things. – [WayBack] Andreas Rejbrand.
  • The -cc commandline parameter for dcc32.exe (which could be in your ProjectX.cfg file!) is equivalent to “Generate console application):

    Found it: the executable has been created using dcc32.exe and the dpr / cfg file, the cfg contains a line

    -cc

    which creates a console application. – [WayBack] mjn

  • Note that in Delphi XE2, OSX applications can not use this variable as it is always true. See QC Entry 98956 and Why Does My OSX FireMonkey App Think It Is a Console App ? – [WayBack] mjn

A few notes I have found out myself

The linker option Project/Options/Linking/Generate console application” is the same as “DCC_ConsoleTarget” in the .dproj file:

    <PropertyGroup Condition="'$(Base_Win32)'!=''">
        <DCC_ConsoleTarget>true</DCC_ConsoleTarget>
    </PropertyGroup>

Even setting IsConsole to True does not allocate a new console, so the STD_OUTPUT_HANDLE handle does not work!

The below method in the System unit, then does not show output:

procedure WriteErrorMessage;
{$IFDEF MSWINDOWS}
var
  Dummy: Cardinal;
begin
  if IsConsole then
  begin
    with TTextRec(Output) do
    begin
      if (Mode = fmOutput) and (BufPos > 0) then
        TTextIOFunc(InOutFunc)(TTextRec(Output));  // flush out text buffer
    end;
    // Leave #0 off end of runErrMsg
    WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), @runErrMsg, Sizeof(runErrMsg) - 1, Dummy, nil);
    WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), @sLineBreak[1], 2, Dummy, nil);
  end
  else if not NoErrMsg then
    MessageBoxA(0, runErrMsg, errCaption, 0);
end;

For console output, you have to enable the linker option DCC_ConsoleTarget allocates a console (if not yet allocated), enables the “STD_OUTPUT_HANDLE” handle, and sets IsConsole to True.

–jeroen

Posted in Conference Topics, Conferences, Delphi, Development, Event, Software Development | Leave a Comment »

Filezilla: figuring out the cause of “Connection timed out after 20 seconds of inactivity”

Posted by jpluimers on 2021/07/21

On one of my Raspberry Pi boxes, somehow I could not access files over SFTP (SSH File Transfer Protocol) via FileZilla.

I would consistently get this error:

"Connection timed out after 20 seconds of inactivity"

Figuring the exact cause took a while.

TL;DR: SFTP uses an interactive non-login shell, then interprets the output from that shell. For that kind of shell, ensure few or none scripts run that output text.

These links finally got me to the cause

These helped me solve the cause

This solved my problem

This is what my /etc/bash.bashrc.local looked like:

# /etc/bash.bashrc.local for SUSE Linux
#
# PLEASE DO NOT CHANGE /etc/bash.bashrc There are chances that your changes
# will be lost during system upgrades.  Instead use /etc/bash.bashrc.local
# for bash or /etc/ksh.kshrc.local for ksh or /etc/zsh.zshrc.local for the
# zsh or /etc/ash.ashrc.local for the plain ash bourne shell  for your local
# settings, favourite global aliases, VISUAL and EDITOR variables, etc ...

. /etc/bash.aliases/_load-aliases.sh

#
# End of /etc/bash.bashrc.local
#

This is what it looks like now:

# /etc/bash.bashrc.local for SUSE Linux
#
# PLEASE DO NOT CHANGE /etc/bash.bashrc There are chances that your changes
# will be lost during system upgrades.  Instead use /etc/bash.bashrc.local
# for bash or /etc/ksh.kshrc.local for ksh or /etc/zsh.zshrc.local for the
# zsh or /etc/ash.ashrc.local for the plain ash bourne shell  for your local
# settings, favourite global aliases, VISUAL and EDITOR variables, etc ...

if [ "$SSH_TTY" ]
then
   source /etc/bash.aliases/_load-aliases.sh
fi

#
# End of /etc/bash.bashrc.local
#

–jeroen

Read the rest of this entry »

Posted in *nix, Communications Development, Conference Topics, Conferences, Development, Event, Internet protocol suite, Power User, SFTP, Software Development, SSH, TCP | Leave a Comment »

Some links for detecting memory leaks from individual DUnit test methods

Posted by jpluimers on 2021/07/20

–jeroen

Posted in Conference Topics, Conferences, Delphi, Development, DUnit, Event, FastMM, Software Development | Leave a Comment »

Delphi interface generic function – Is there a work around? – Stack Overflow

Posted by jpluimers on 2021/06/30

The documentation simply states “no”, without explaining why.

Luckily, there is [WayBack] David Heffernan at [WayBack] Delphi interface generic function – Is there a work around? – Stack Overflow

Interfaces do not support generic parameterized methods, as the compiler says.

There is no workaround because it’s a fundamental limitation. Parameterized methods in classes are implemented by adding one method per instantiation to the class. That works for classes since they are concrete, but is not viable for interfaces. That’s because interfaces are a table of functions and the size of that table cannot vary depending on which generic method instantiations happen to be present elsewhere in the code. For similar reasons, generic methods cannot be virtual or dynamic.

In any case, it’s not possible. One option is to use a class instead. I agree that this is a bind.

If you want to do it in an interface, the best you can do is:

function CastAs(const IID: TGUID): IInterface;

But you’d have to call it like this:

MyIntf := ProxyIntf.CastAs(IMyIntf) as IMyIntf;

which feels somewhat foul.

Choose your poison!

In the background, for every distinct use of generic method parameters, the compiler generates an overloaded concrete version of the method. That is possible for classes and records, but not for interfaces.

In practice, I either go for the last option, or have the interface expose a record or class type that can have the required generic method (so the compiler can generate the overloads at run-time).

All options feel somewhat ugly, so I like the comment by [WayBack] Jason:

Wish I could “Program into Your Language, Not in it” programmers.stackexchange.com/questions/2777/…

Which leads to Code Complete

[WayBack] What are the key points of Code Complete? – Software Engineering Stack Exchange answer by [WayBack] limist:

Code Complete is about software craftsmanship; it is an advanced-beginner/intermediate-level book, written for the working programmer, but it would still be very useful to someone who’s been programming for at least a year.

Thus the key points of Code Complete (2nd ed.) are nicely summarized in its Chapter 34, Themes in Software Craftsmanship. As paraphrased from my notes:

  1. Conquer Complexity: reduce the cognitive load on your mind via discipline, conventions, and abstraction.
  2. Pick Your Process: be conscious of quality from start (requirements) to finish (deployment) and beyond (maintenance).
  3. Write Programs for People First, Computers Second: code readability is hugely important for comprehensibility, review-ability, error-rate, error-correction, modifiability, and the consequent development time and quality.
  4. Program into Your Language, Not in it: think of the What? and Why? before the How?
  5. Focus Your Attention with the Help of Conventions: conventions manage complexity by providing structure where it’s needed, so that the ultimate resource – your attention – can be effectively used.
  6. Program in Terms of the Problem Domain: work at the highest level of abstraction possible; top-level code should describe the problem being solved. Distinguish OS level, programming language level, low-level implementation structures, low-level problem domain terms, and finally, high-level problem-domain terms that would make total sense to the (non-coder) user.
  7. Watch for Falling Rocks: as programming merges art and science, good judgement is vital, including heeding warning signs.
  8. Iterate, Repeatedly, Again and Again: iterate requirements, design, estimates, code, code tuning.
  9. Thou Shalt Render Software and Religion Asunder: be eclectic and willing to experiment. Don’t be an inflexible zealot, it precludes curiosity and learning. Go beyond having just a hammer in your toolbox.

But the most important take-aways are in Chapter 33, Personal Character: once you consciously seek to improve as a coder, you can and will. The fastest way to do so is to take on the the attitudes of master coders(humility, curiosity, intellectual honesty, discipline, creativity), while also practicing their habits (many good habits are listed in the book, e.g. choosing good variable/value names).

Also, the book makes clear that the gap between average and excellent in software is immense; that fact alone should drive the conscientious coder to better himself.

That’s the short of it; the long version is in the book. :) I can also send you my not-so-long, not-so-short notes if you want more details. But the book is certainly money and time well-spent, even if the writing style is tiresome at times.

Beyond Code Complete, I’d highly recommend The Pragmatic Programmer. It’s for intermediate-level programmers, nicely-written and a great mix of high, medium, and low-level advice.

There are more limitations on generics in Delphi

The documentation on limitations has not changed much since Delphi 2009.

Delphi 2009

[WayBack] Overview of Generics: Platform Requirements and Differences

Generics are supported by the Delphi for Win32 compiler.

Runtime type identification (RTTI)

In Win32, generics and methods do not have RTTI, but instantiated types do have RTTI. An instantiated type is the combination of a generic with a set of parameters.

Interface GUID

In Win32, an instantiated interface type does not have an interface GUID.

Parameterized method in interface

A parameterized method (method declared with type parameters) cannot be declared in an interface.

Instantiation timing

Instantiation is processed by the compiler. All instantiated objects are emitted into .obj files.

Dynamic instantiation

Dynamic instantiation at runtime is not supported.

Interface constraints

The Win32 interface is not a “light” interface. This means all type parameters with interface constraints always support the COM IUnknown methods _AddRef_Release and QueryInterface or inherit from TInterfacedObject. Record types cannot specify an interface constraint parameter.

Delphi 10.3 Rio

[WayBack] Overview of Generics – RAD Studio: Platform Requirements and Differences

Generics are supported by the Delphi compilers.

Run-time type identification

In Win32, generics and methods do not have run-time type information (RTTI), but instantiated types do have RTTI. An instantiated type is the combination of a generic with a set of parameters. The RTTI for methods of a class is a subset of the RTTI for that class as a whole. If a non-generic class has a generic method, that method will not be included in the RTTI generated for the class because generics are instantiated at compile time, not at run time.

Interface GUID

In Win32, an instantiated interface type does not have an interface GUID.

Parameterized method in interface

A parameterized method (method declared with type parameters) cannot be declared in an interface.

Instantiation timing

Generic types are instantiated at compile time and emitted into executables and relocatable files. Instance variables of a generic type are instantiated at run time for classes and at compile time for generic records. The RTTI for generic classes is only generated when the classes are instantiated. RTTI for instantiated classes follows just as for non-generic classes. If the generic class has a generic method, then the instantiated generic class will not have RTTI for that generic method.

Dynamic instantiation

Dynamic instantiation at run time is not supported.

Interface constraints

The Win32 interface is not a “light” interface. This means all type parameters with interface constraints always support the COM IUnknown methods _AddRef_Release, and QueryInterface or inherit from TInterfacedObject. Record types cannot specify an interface constraint parameter.

–jeroen

Posted in Conference Topics, Conferences, Delphi, Development, Event, Software Development | Leave a Comment »

 
%d bloggers like this: