Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2016-08

rtl-generics: TIStringComparer.Ordinal -> Access violation

10 messages · 3 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

silvioprog

Hello,

Just try it:

var
  list: TDictionary<string, string>;
begin
  list := TDictionary<string, string>.Create(TIStringComparer.Ordinal);

Error:

An unhandled exception occurred at $000000000043A2F8: EAccessViolation: Access violation
$000000000043A2F8
$00000000004084B3 DOADD, line 277 of inc/generics.dictionaries.inc $00000000004099AB main, line 14 of project1.lpr

---

Trace:

#0
GENERICS.DEFAULTS$_$TGORDINALISTRINGCOMPARER$2$CRC09680922_$__$$_GETHASHCODE$ANSISTRING$$LONGWORD at :0
#1 ?? at :0

Silvio Clécio

Reply by email

Maciej Izak
to silvioprog

2016-08-17 7:05 GMT+02:00 silvioprog :

Just try it:

related to

http://bugs.freepascal.org/view.php?id=28911

Sven comment: "I won't change the current implementation for now, because once I'm going to fix this I'm going to fix this correctly for all cases, including packages, everything else is merely a workaround. But for that I first need to finish my work on packages."

btw, already reported: http://bugs.freepascal.org/view.php?id=30433

Best regards, Maciej Izak

Reply by email

silvioprog
to Maciej Izak
Maciej Izak wrote 17 lines
2016-08-17 7:05 GMT+02:00 silvioprog : > Just try it: > related to http://bugs.freepascal.org/view.php?id=28911 Sven comment: "I won't change the current implementation for now, because once I'm going to fix this I'm going to fix this correctly for all cases, including packages, everything else is merely a workaround. But for that I first need to finish my work on packages." btw, already reported: http://bugs.freepascal.org/view.php?id=30433

Indeed. After some debug I found where the exception is raised:

...
function TOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS>.FindBucketIndex(constref
AItems: TArray<TItem>;
  constref AKey: TKey; out AHash: UInt32): SizeInt;
var
  LItem: {TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.}_TItem; // for
workaround Lazarus bug #25613
  LLengthMask: SizeInt;
  i, m: SizeInt;
  LHash: UInt32;
begin
  m := Length(AItems);
  LLengthMask := m - 1;
  LHash := FEqualityComparer.GetHashCode(AKey); // << here
...

but I can't step into FEqualityComparer.GetHashCode to check why it happens, so I'll wait for Sven too. ^^

I need to find the values using case-insensitive keys (I'm using it in a class registry of my app), so unfortunately this bug doesn't let me to use TDictionary on FPC yet. :-(

Silvio Clécio

Reply by email

Sven Barth
to Maciej Izak: 2016-08-17 7:05 GMT+02:00 silvioprog : related to…
"Maciej Izak" wrote 12 lines
2016-08-17 7:05 GMT+02:00 silvioprog : > > Just try it: related to http://bugs.freepascal.org/view.php?id=28911 Sven comment: "I won't change the current implementation for now, because

once I'm going to fix this I'm going to fix this correctly for all cases, including packages, everything else is merely a workaround. But for that I first need to finish my work on packages."

Couldn't you work around for now by using instance instead of class variables? At least then the classes would work instead of everyone asking every second week why they don't...

Regards,
Sven

Reply by email

Maciej Izak
to silvioprog: Indeed. After some debug I found where the exception is raised: ... function…

2016-08-17 16:05 GMT+02:00 silvioprog :

I need to find the values using case-insensitive keys (I'm using it in a class registry of my app), so unfortunately this bug doesn't let me to use TDictionary on FPC yet. :-(

There is simple workaround:

=== begin code ===

function EqualityComparison(constref ALeft, ARight: string): Boolean;
begin
  Result := LowerCase(ALeft) = LowerCase(ARight);
end;
procedure ExtendedHasher(constref AValue: string; AHashList: PUInt32);
begin
  TDefaultHashFactory.GetHashList(Pointer(AValue), Length(AValue) *
SizeOf(Char), AHashList);
end;
var
  list: TDictionary<string, string>;
begin
  list := TDictionary<string,
string>.Create(TEqualityComparer<string>.Construct(EqualityComparison,
ExtendedHasher));

=== end code ===

Best regards, Maciej Izak

Reply by email

Maciej Izak
to Maciej Izak

2016-08-17 17:20 GMT+02:00 Maciej Izak :

Show quoted text 6 lines
procedure ExtendedHasher(constref AValue: string; AHashList: PUInt32); begin TDefaultHashFactory.GetHashList(Pointer(AValue), Length(AValue) * SizeOf(Char), AHashList); end;

there is bug, correct version:

procedure ExtendedHasher(constref AValue: string; AHashList: PUInt32);
var
  temp: string;
begin
  temp := LowerCase(AValue);
  TDefaultHashFactory.GetHashList(Pointer(temp), Length(temp) *
SizeOf(Char), AHashList);
end;
Best regards, Maciej Izak

Reply by email

silvioprog
to Maciej Izak: 2016-08-17 16:05 GMT+02:00 silvioprog : There is simple workaround: === begin code ===…
Maciej Izak wrote 31 lines
2016-08-17 16:05 GMT+02:00 silvioprog : > I need to find the values using case-insensitive keys (I'm using it in a > class registry of my app), so unfortunately this bug doesn't let me to use > TDictionary on FPC yet. :-( There is simple workaround: === begin code === function EqualityComparison(constref ALeft, ARight: string): Boolean; begin Result := LowerCase(ALeft) = LowerCase(ARight); end; procedure ExtendedHasher(constref AValue: string; AHashList: PUInt32); begin TDefaultHashFactory.GetHashList(Pointer(AValue), Length(AValue) * SizeOf(Char), AHashList); end; var list: TDictionary<string, string>; begin list := TDictionary<string, string>.Create(TEqualityCompar er<string>.Construct(EqualityComparison, ExtendedHasher)); === end code ===

I changed it to a function:

  function ExtendedHasher(constref AValue: string): UInt32;
  begin
    TDefaultHashFactory.GetHashList(Pointer(AValue),
      Length(AValue) * SizeOf(Char), @Result);
  end;

because the "Error: Incompatible type for arg no. 2: Got "ExtendedHasher(constref AnsiString;PDWord);", expected "<procedure variable type of function(constref AnsiString):DWord;Register>"".

Anyway, thanks for the workaround, it can fix the FPC version of my tests. :-)

Silvio Clécio

Reply by email

Maciej Izak
to silvioprog

2016-08-17 18:45 GMT+02:00 silvioprog :

Show quoted text 8 lines
I changed it to a function: function ExtendedHasher(constref AValue: string): UInt32; begin TDefaultHashFactory.GetHashList(Pointer(AValue), Length(AValue) * SizeOf(Char), @Result); end;

Still bad implementation (see my previous message). Is highly probable to obtain different hashes for 'foo' and 'Foo'. Usage of GetHashList in that context is also improper, GetHashList is generally dedicated for more complicated structures (for example for cuckoo hashing). The proper code is:

  function MyHasher(constref AValue: string): UInt32;
  var
    temp: string;
  begin
    temp := LowerCase(AValue);
    Result := TDefaultHashFactory.GetHashCode(Pointer(temp), Length(temp) *
SizeOf(Char), 0);
  end;
Show quoted text 5 lines
because the "Error: Incompatible type for arg no. 2: Got "ExtendedHasher(constref AnsiString;PDWord);", expected "<procedure variable type of function(constref AnsiString):DWord;Register>"".

Point for you, that was code from my memory, sorry ;) ExtendedHasher in presented form is dedicated for TExtendedEqualityComparer<T>.Construct(...) which is used for THashMap<K,V> (THashMap is much faster than TDictionary for big data)

Best regards, Maciej Izak

Reply by email

Sven Barth
to Maciej Izak: 2016-08-17 17:15 GMT+02:00 Sven Barth : Yes I think that is possible :P Note: #28911 bug…
"Maciej Izak" wrote 5 lines
2016-08-17 17:15 GMT+02:00 Sven Barth : > > Couldn't you work around for now by using instance instead of class

variables? At least then the classes would work instead of everyone asking every second week why they don't...

Yes I think that is possible :P Note: #28911 bug is most annoying ever

(for generic programmers ;) )

It's also very annoying to fix correctly (for compiler developers :P )

Regards,
Sven

Reply by email