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 1,854 other subscribers

Archive for the ‘Delphi’ Category

Delphi use of FS segment: structured exception handling

Posted by jpluimers on 2021/03/16

A while ago, I had to trace through a lot of code in the CPU pane to track down some memory allocation related issues.

I wondered what the use of the FS segment was about, so via [Archive.is] delphi what is fs segment used for – Google Search, I found that it is related to Win32 Structured Exception handling and therefore not limited to Delphi, through these links:

A few disassembly parts to show how the Delphi Win32 compiler uses this for try finally blocks and try except blocks is below. Note that often, there are implicit try finally blocks when having managed method parameters or local variables.

–jeroen

Read the rest of this entry »

Posted in Delphi, Development, Software Development, Undocumented Delphi, Windows Development | Leave a Comment »

GExperts grep search: skipping searching certain files, irrespective of their directory

Posted by jpluimers on 2021/03/11

Especially when including [WayBack] form files (dfm now, but in the past also nfm and xfm) in your search, you might want to exclude one or more of them, for instance when they do not adhere to the form file syntax.

One of such files is for instance [WayBack] jcl/ExceptDlg.CBuilder32.dfm at master · project-jedi/jcl · GitHub. It has the contents is NONE (by intent, just like the corresponding .h and .cpp files, as only the Delphi equivalents .dfm and .pas have been implemented).

Doing this was way easier than I thought: just put ExceptDlg.CBuilder32.dfm in the “Exclude Dirs” field – which also excludes files. How cool is that!

–jeroen

 

Posted in Delphi, Development, GExperts, Software Development | 1 Comment »

Debouncing and Throttling Explained Through Examples | CSS-Tricks

Posted by jpluimers on 2021/03/10

TL;DR of https://css-tricks.com/debouncing-throttling-explained-examples/:

  • debounce: Grouping a sudden burst of events (like keystrokes) into a single one.
  • throttle: Guaranteeing a constant flow of executions every X milliseconds. Like checking every 200ms your scroll position to trigger a CSS animation.
  • requestAnimationFrame: a throttle alternative. When your function recalculates and renders elements on screen and you want to guarantee smooth changes or animations. Note: no IE9 support.

Full article [WayBackDebouncing and Throttling Explained Through Examples | CSS-Tricks

Delphi implementations:

–jeroen

Posted in Algorithms, Delphi, Development, JavaScript/ECMAScript, Scripting, Software Development | Leave a Comment »

MESSAGE directive Delphi

Posted by jpluimers on 2021/03/09

I totally forgot to queue this, after putting in a draft in 2010. Luckily, nothing has changed since then: the [WayBack] MESSAGE directive Delphi which allows you to emit hint, warning, error (multiple) and fatal (single) messages to the Delphi from Delphi IDE “Messages” pane or to the command-line compiler output:

{$MESSAGE 'Boo!'}                   emits a hint 
{$Message Hint 'Feed the cats'}     emits a hint 
{$messaGe Warn 'Looks like rain.'}  emits a warning 
{$Message Error 'Not implemented'}  emits an error, continues compiling 
{$Message Fatal 'Bang.  Yer dead.'} emits an error, terminates compiler 

You can use it like this to list a TODO, that might get more attention than a TODO comment in the code (earliest on-line documentation in Delphi 2007’s [WayBack] devcommon.pdf and [WayBack] Using To-Do Lists):

{$MESSAGE Hint 'TODO finish some work here'}

The most important thing to remember is do not forget the single quotes around the message.

Example from production code which tests for the permutations of defines related to [WayBack] FastMM4Options.inc:

{$ifdef RELEASE}
//...
{$else}
  {$ifdef DEBUG}
//...
  {$else}
    {$Message Error 'Unsupported FastMM4Options.inc build configuration: supported are RELEASE and DEBUG'}
  {$endif not DEBUG}
{$endif not RELEASE}

{$ifdef NoMessageBoxes}
  {$ifndef UseOutputDebugString}
    {$Message Error 'Unsupported combination: without NoMessageBoxes or UseOutputDebugString, no severe FastMM4 errors are emitted at all.'}
  {$endif not UseOutputDebugString}
{$endif NoMessageBoxes}

--jeroen

Posted in Delphi, Development, Software Development | Leave a Comment »

Short Delphi tip: ensuring RTTI for classes is included

Posted by jpluimers on 2021/03/04

When using RTTI in Delphi, you really want the RTTI to be available.

The compiler includes RTTI for classes, as soon as it found that a class is touched by code that will be executed.

So in order to include RTTI for classes into the executable, you have to ensure you touch the class.

Basically there are two tricks for that.

  1. A small one step process which incurs a tiny bit of string overhead:
    class function TObject.ClassName: string;
    begin
      Result := UTF8ToString(_PShortStr(PPointer(PByte(Self) + vmtClassName)^)^);
    end;
    • Touch the [WayBack] ClassName class function for each class, for instance in an initialization section or registration method, like this:
      TMyClass.ClassName;
      TMyOtherClass.ClassName;
  2. A small two step process
    1. Create a method like this: procedure EnsureRttiIsAvailable(const Classes: array of TClass); begin end;
    2. Pass the classes to it like this:
      EnsureRttiIsAvailable([TMyClass, TMyOtherClass]);

I like the second solution more, as it clearly states the intent.

The first trick is calling a function without using the result. This is a Pascal construct that looks odd, but is perfectly valid to use: basically you discard the result.

–jeroen

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

Delphi: combining intrinsic functions and inline to have no-code checks on concrete generic instantiation

Posted by jpluimers on 2021/03/04

The title might sound like a lot of gibberish, but the mechanism it describes helps solving a problem when using generics: lack of generic constraints in the compiler.

For instance, you cannot constrain on enumeration types (C# could not do this either: you could not do T GetEnumFromString<T>(string valueString, T defaultValue) where T : Enum, but [WayBack] since C# 7.3, you can do ... where T : Enum) unless you [WayBack] did some real hackery.

For Delphi, you still cannot do the constraint, but with some hackery, you can avoid code generation. Spring4d uses this in [WayBack] Spring.pas, from which I copied these fragments:

class function TType.Kind<T>: TTypeKind;
{$IFDEF DELPHIXE7_UP}
begin
  Result := System.GetTypeKind(T);
{$ELSE}
var
  typeInfo: PTypeInfo;
begin
  typeInfo := System.TypeInfo(T);
  if typeInfo = nil then
    Exit(tkUnknown);
  Result := typeInfo.Kind;
{$ENDIF}
end;

class procedure Guard.CheckTypeKind<T>(expectedTypeKind: TTypeKind;
  const argumentName: string);
begin
  if TType.Kind<T> <> expectedTypeKind then
    RaiseArgumentException(TType.Kind<T>, argumentName);
end;

class function TEnum.IsValid<T>(const value: Integer): Boolean;
var
  data: PTypeData;
begin
  Guard.CheckTypeKind<T>(tkEnumeration, 'T');
  data := GetTypeData(TypeInfo(T));
  Result := (value >= data.MinValue) and (value <= data.MaxValue);
end;

When <T> is an enumeration type, any code for that call is eliminated by the compiler.

Related

Concrete versus generic type:

–jeroen

Posted in Delphi, Development, Software Development | Leave a Comment »

Delphi: quickly failing in use-after free scenarios

Posted by jpluimers on 2021/03/03

Two tricks that can help in use-after-free scenarios.

Call ScanMemoryPoolForCorruptions often

One of the scenarios of use after free, is that memory blocks get corrupted.

FastMM4 normall checks this at process end using the CheckBlocksOnShutdown method (in FastMM4.pas when writing this private at line 11156), but you can also do this process manually using the ScanMemoryPoolForCorruptions method (also in FastMM4.pas, but public at line L1356).

You can automate this process by setting the FullDebugModeScanMemoryPoolBeforeEveryOperation flag to True while in FullDebugMode as you see in the quoted code blocks below.

Note that calling ScanMemoryPoolForCorruptions between allocations might reveal wild pointer dereferences between allocations.

  - Added a global variable "FullDebugModeScanMemoryPoolBeforeEveryOperation".
    When this variable is set to true and FullDebugMode is enabled, then the
    entire memory pool is checked for consistency before every GetMem, FreeMem
    and ReallocMem operation. An "Out of Memory" error is raised if a
    corruption is found (and this variable is set to false to prevent recursive
    errors). This obviously incurs a massive performance hit, so enable it only
    when hunting for elusive memory corruption bugs. (Thanks to Marcus Mönnig.)

  {If this variable is set to true and FullDebugMode is enabled, then the
   entire memory pool is checked for consistency before every memory
   operation. Note that this incurs a massive performance hit on top of
   the already significant FullDebugMode overhead, so enable this option
   only when absolutely necessary.}
  FullDebugModeScanMemoryPoolBeforeEveryOperation: Boolean = False;

Call any virtual method on an instance reference

A quick way to test use-after free scenarios is to call a virtual method on an instance.

Virtual methods mean that the Virtual Method Table needs to be used as a starting point, so any nil pointer will get dereferenced.

Two simple methods that you can call, which have no side effects, except for referencing memory, and are virtual on [WayBack] TObject are [WayBack] GetHashCode and [WayBack] ToString. Both methods got added in Delphi 2009, and now support 64-bit and 32-bit compilers are below.

If you use use these in addition to FastMM4 clearing memory, and FastMM4 redirecting virtual methods of freed objects, you have a good chance of catching use-after free.

Without FastMM, they are also of good help, especially when the freed memory has since then been overwritten by new usage. FastMM4 is a lot more strict about this, so definitely recommended.

Calling these two methods help you to quickly fail with an EAccessViolation [WayBack] in use-after-free scenarios.

More on the virtual method table is for instance in [WayBack] Hallvard’s Blog: Method calls compiler implementation.

Read the rest of this entry »

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

JSON or binary stream? Delphi 2010: How to save a whole record to a file? – Stack Overflow

Posted by jpluimers on 2021/03/03

A while back I proposed using JSON in order to [WayBack] Delphi 2010: How to save a whole record to a file? – Stack Overflow.

There is also a native solution using streaming (which by now has moved to [WayBack] GitHub – KrystianBigaj/kblib: Automatically exported from code.google.com/p/kblib with main source file [WayBack] kblib/uKBDynamic.pas), but be aware that unlike JSON:

  • Streams are not fully compatible between Delphi Unicode and Delphi non-Unicode (they are if you limit yourself to AnsiString)
  • Streams are not compatible between x64 and x86 unless you use kdoCPUArchCompatibility and provide additional compatibility (read comments on kdoCPUArchCompatibility)

The main file from my proposed solution has since then move

Which reminds me I still need to fix quite a few links, as per Anyone who knows about http://sourceforge.net/p/radstudiodemos/code/HEAD/tree/branches/RADStudio_Rio ?

–jeroen

Posted in Delphi, Development, Software Development | Leave a Comment »

Delphi XE7 introduced const support for dynamic arrays; prior versions used [] only for sets.

Posted by jpluimers on 2021/03/02

A few things to learn from [WayBack] delphi – Constant array of cardinal produces error ‘Constant expression violates subrange bounds” – Stack Overflow:

  • Delphi XE7 introduced compiler support for const dynamic arrays.
  • Compiler errors can completely put you in the wrong direction.
  • Command-line compilers indicate BDS versions which can confuse you for the exact product versions (thanks Rudy Velthuis for correcting that).

Sets

In this case, Delphi XE6 and below regard the [...] construct for constants as a set of Byte of which the maximum value is 255.

So this already fails with E1012 Constant expression violates subrange bounds, even though 257 perfectly fits the subrange of Cardinal:

const
  CardinalArray: array of Cardinal = [257];

The documentation (which has not changed since Delphi 2007) puts you in a totally different direction: [WayBack] x1012: Constant expression violates subrange bounds

x1012: Constant expression violates subrange bounds

This error message occurs when the compiler can determine that a constant is outside the legal range. This can occur for instance if you assign a constant to a variable of subrange type.

program Produce;
var
  Digit: 1..9;
begin
  Digit := 0;  (*Get message: Constant expression violates subrange bounds*)
end.
program Solve;
var
  Digit: 0..9;
begin
  Digit := 0;
end.

The alternative is to use a non-dynamic array that uses parenthesis instead of square brackets for initialisation:

const
  CardinalArray: array[0..0] of Cardinal = (257);

Dynamic arrays

Const initialisation of dynamic arrays only made a tick mark on the box in [Archive.is] What’s New in Delphi and C++Builder XE7 – RAD Studio: String-Like Operations Supported on Dynamic Arrays, but in fact this code works in Delphi XE7 and up just fine:

program Cardinals;

{$APPTYPE CONSOLE}

uses
  System.SysUtils;

const
  CardinalArray: array of Cardinal = [257]; // fails until Delphi XE6 with "E1012 Constant expression violates subrange bounds"

const
  ANSICOLORS: array of Cardinal = [
    $000000,//0
    $800000,//1, compilation error starts with this value
    $008000,//2
    $808000,//3
    $000080,//4
    $800080,//5
    $008080,//6
    $D0D0D0,//7
    $3F3F3F,//8
    $FF0000,//9
    $00FF00,//A
    $FFFF00,//B
    $0000FF,//C
    $FF00FF,//D
    $00FFFF,//E
    $FFFFFF];//F

var
  AnsiColor: Cardinal;

begin
  try
    for AnsiColor in AnsiColors do
      Writeln(Format('$%6.6x', [AnsiColor]));
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

Output:

$000000
$800000
$008000
$808000
$000080
$800080
$008080
$D0D0D0
$3F3F3F
$FF0000
$00FF00
$FFFF00
$0000FF
$FF00FF
$00FFFF
$FFFFFF

Note that dynamic arrays are unlike regular arrays, which for instance means that nesting them can get you into a different uncharted territory when using multiple dimensions.

Unlike an array, a dynamic array has notice of length. Which means it needs extra memory for it.

So where regular multi-dimensional arrays are blocks of memory. Multi-dimensional dynamic arrays are a dynamic array on each dimension level, which means extra length keeping, and the seemingly odd Copy behaviour described in [WayBack] Things that make you go ‘urgh’… | Delphi Haven:

What’s the flaw in this test code?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
program Project1;
{$APPTYPE CONSOLE}
var
  Arr1, Arr2: array of array of Integer;
  I, J: Integer;
begin
  SetLength(Arr1, 5, 5);
  for I := 0 to 4 do
    for J := 0 to 4 do
      Arr1[I, J] := I * J;
  Arr2 := Copy(Arr1);
  for I := 0 to 4 do
    for J := 0 to 4 do
      if Arr2[I, J] <> Arr1[I, J] then
      begin
        WriteLn('Nope');
        Break;
      end;
  Write('Press ENTER to exit...');
  ReadLn;
end.

with these comments

Rudy Velthuis:

Dynarrays are single-dimensional. One can get the illusion of multi-dimensionality because the Delphi syntax lets you access them using a[5,6] syntax, and SetLength takes more than one dimension parameter, and indeed, the docs even mention multi-dimensional, but that doesn’t change anything. You don’t have a multi-dimensional dynarray, you have a dynarray than contains other dynarrays. Each of these is one-dimensional. IOW, you don’t have one array, you have a cluster of dynarrays.

Copy() handles dynarrays. These are one-dimensional, so it only does one dimension (what else?). IOW, the behaviour is correct and actually well known.

Franćois:

I’m with you Chris. I don’t think this is “well known”, maybe because mono-dimensional dynamic arrays are probably used much more than multidimensional ones.
And also, the documentation is blaringly silent on this behavior. (credit to DelphiBasics to mention it: http://www.delphibasics.co.uk/RTL.asp?Name=Array)
The more visibility it gets, the less bugs we’ll have to deal with.

IMO, I don’t see why “copy” would not behave recursively and copy each sub-array as well. It seems that it is the intuitive behavior people tend to expect in the 1st place. (either nothing at all like Arr1:=Arr2, or a full recursive copy)
But since it’s been like that for some time, I doubt it can change for compatibility reasons (breaking code relying explicitly on this behavior).

Chris:

Thanks for the support! On my reading, the help strongly implies the behaviour I was expecting, and therefore, implies the actual behaviour to be a bug. Specifically, the entry for Copy (http://docwiki.embarcadero.com/VCL/en/System.Copy) includes the line:

Note: When S is a dynamic array, you can omit the Index and Count parameters and Copy copies the entire array.

What could ‘the entire array’ mean? According to Rudy, this can’t mean more than one dimension because dynamic arrays aren’t multidimensional. And yet, the Delphi Language Guide talks of ‘multidimensional dynamic arrays’ quite clearly (http://docwiki.embarcadero.com/RADStudio/en/Structured_Types#Multidimensional_Dynamic_Arrays). See also the docs for SetLength (http://docwiki.embarcadero.com/VCL/en/System.SetLength).

–jeroen

Posted in Delphi, Development, History, Software Development, Undocumented Delphi | Leave a Comment »

Fun with Delphi RTTI – Dump a TRttiType | The Road to Delphi

Posted by jpluimers on 2021/02/25

For my link archive a non-recursive DumpTypeDefinition method:

Here ‘s a sample code of how you can dump the declaration of a TRttiType using the Rtti. Supports classes, records and interfaces. Delphi Use in this way OutPut the output is this the output …

Source: [WayBack] Fun with Delphi RTTI – Dump a TRttiType | The Road to Delphi

–jeroen

Posted in Delphi, Development, Software Development | Leave a Comment »