Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Floating Point Exception oder Access Violation, je nach Schreibweise (https://www.delphipraxis.net/194608-floating-point-exception-oder-access-violation-je-nach-schreibweise.html)

Der schöne Günther 12. Dez 2017 18:04

Delphi-Version: 10 Seattle

Floating Point Exception oder Access Violation, je nach Schreibweise
 
Kann mir jemand folgendes Verhalten erklären?

Delphi-Quellcode:
uses System.Generics.Collections;
Prozedur
Delphi-Quellcode:
p1
wirft eine Access Violation,
Delphi-Quellcode:
p2
hingegen eine Floating point invalid operation. Warum? Da ist doch kein Unterschied!

Delphi-Quellcode:
procedure p1();
type
   TFloat = type Single;
var
   values:   TArray<TFloat>;
begin
   values := [1.0, Single.Nan, 2.0];
   TArray.Sort<TFloat>(values);
end;

procedure p2();
type
   TFloat = Single;
var
   values:   TArray<TFloat>;
begin
   values := [1.0, Single.Nan, 2.0];
   TArray.Sort<TFloat>(values);
end;

Zacherl 12. Dez 2017 18:15

AW: Floating Point Exception oder Access Violation, je nach Schreibweise
 
Doch schon. Mit
Delphi-Quellcode:
X = type Y
deklarierst du ja einen neuen Strong-Type und nicht nur einen Alias. Vergleiche über TypInfo, RTTI, oder eben die Intrinsics im Zusammenhang mit der generischen
Delphi-Quellcode:
TArra<T>.Sort
Methode werden hierbei dann keine Gleichheit mehr ergeben.

Edit:
Die generischen Container haben in Delphi für die meisten Standard-Typen spezifische Behandlungsroutinen. Dadurch, dass der RTL
Delphi-Quellcode:
TFloat
bzw.
Delphi-Quellcode:
type Single
unbekannt ist, wird hier dann vermutlich auf eine Fallbackroutine zurückgegriffen.

himitsu 13. Dez 2017 02:13

AW: Floating Point Exception oder Access Violation, je nach Schreibweise
 
Aber "Zugriffsverletzung" kommt mir dennoch etwas komisch vor. :gruebel:

himitsu 13. Dez 2017 03:00

AW: Floating Point Exception oder Access Violation, je nach Schreibweise
 
Ratet mal, wofür es den Debugger gibt. :angle:

Wie Zacherl bereits erwähnte, gehört dein neuer Typ nicht zu den bekannten "Default"-Typen, für Welche in Delphi passende Comparer existieren,
also wird hier ganz einfach nur auf Type-Size gegangen und der Inhalt "Binär" verglichen.

Delphi-Quellcode:
class procedure TArray.Sort<T>(var Values: array of T);
begin
  QuickSort<T>(Values, TComparer<T>.Default, Low(Values), High(Values));
end;

class function TComparer<T>.Default: IComparer<T>;
begin
  Result := IComparer<T>(_LookupVtableInfo(giComparer, TypeInfo(T), SizeOf(T)));
end;

class procedure TArray.QuickSort<T>(var Values: array of T; const Comparer: IComparer<T>; L, R: Integer);
begin
  ...
      while Comparer.Compare(Values[I], pivot) < 0 do


// Single
function Compare_R4(Inst: Pointer; const Left, Right: Single): Integer;
begin
  if Left < Right then

// type Single
function Compare_U4(Inst: Pointer; const Left, Right: Cardinal): Integer;
begin
  if Left < Right then
Du mußt dir also selber einen Comparer erstellen, für solche Typen.
Delphi-Quellcode:
TArray.Sort<TFloat>(Values, Comparer);


Die Zugriffsverletzung ist aber ein schwerwiegender Bug im QuickSort. :shock:
Ich bin echt erstaunt, daß es nicht öfters knallt.

Mit
Delphi-Quellcode:
Single
knallt es schon im Compare, wegen des NAN und weil die FPU so eingestellt ist.
> Delphi-Referenz durchsuchenSet8087CW Delphi-Referenz durchsuchenSetExceptionMask

Bei
Delphi-Quellcode:
type Single
funktioniert der Vergleich, da "NAN" dort nicht behandelt wird, und es knallt im QuickSort.
Das erste
Delphi-Quellcode:
while Comparer.Compare(Values[I], pivot) < 0 do Inc(I);
findet kein Ende und trifft hier "zufällig" irgendwann auf nicht zugewiesenen Speicher.
Das Selbe wird man auch bei anderen Typen hinbekommen. Der BufferOverflow wird zum Glück abgefangen, da die Array-Grenzen im Anschluss geprüft werden und somit keine Schreibzugriffe außerhalb des Arrays auftreten.
Es knallt also immer wenn im Array und davor oder dahinter auch kein fremder reservierter Speicher mit einem passenden Wert gefunden wird.

Delphi-Quellcode:
class procedure TArray.QuickSort<T>(var Values: array of T; const Comparer: IComparer<T>; L, R: Integer);
var
  I, J: Integer;
  pivot, temp: T;
begin
  if (Length(Values) = 0) or ((R - L) <= 0) then
    Exit;
  repeat
    I := L;
    J := R;
    pivot := Values[L + (R - L) shr 1];
    repeat
      while Comparer.Compare(Values[I], pivot) < 0 do
        Inc(I);
      while Comparer.Compare(Values[J], pivot) > 0 do
        Dec(J);

Sehr eigenartig ist auch, dass in diesem Generic die Bereichsprüfung nicht funktioniert. :freak:
>
Delphi-Quellcode:
{$RANGECHECKS ON}
bzw. in den Projektoptionen aktiviert

himitsu 13. Dez 2017 03:19

AW: Floating Point Exception oder Access Violation, je nach Schreibweise
 
https://quality.embarcadero.com/brow...22quicksort%22

himitsu 14. Dez 2017 21:36

AW: Floating Point Exception oder Access Violation, je nach Schreibweise
 
LOL, grade gefunden.
http://www.delphipraxis.net/182907-d...-overflow.html

Der Witz dabei ist, das du hier schon mit dem Bugfix arbeitest. (neuer Code, der ebenfalls nicht funktioniert)

Stevie 15. Dez 2017 09:41

AW: Floating Point Exception oder Access Violation, je nach Schreibweise
 
Zitat:

Zitat von himitsu (Beitrag 1388648)
Sehr eigenartig ist auch, dass in diesem Generic die Bereichsprüfung nicht funktioniert. :freak:
>
Delphi-Quellcode:
{$RANGECHECKS ON}
bzw. in den Projektoptionen aktiviert

Guck mal ganz oben in System.Generics.Collections ...

Der schöne Günther 15. Dez 2017 09:52

AW: Floating Point Exception oder Access Violation, je nach Schreibweise
 
Danke für die Erklärung, jetzt verstehe ich es zumindest.

Und ja, ein Floating Point-Error wäre mir auf jeden Fall lieber als eine AV.

PS: Dein Kommentar in
https://quality.embarcadero.com/browse/RSP-19091
ist wohl nochmal einen neuen Eintrag wert, die haben das Ticket danach einfach zu gemacht 8-)

himitsu 15. Dez 2017 10:18

AW: Floating Point Exception oder Access Violation, je nach Schreibweise
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1388901)
PS: Dein Kommentar in
https://quality.embarcadero.com/browse/RSP-19091
ist wohl nochmal einen neuen Eintrag wert, die haben das Ticket danach einfach zu gemacht 8-)

Sorry, hatte nur in 'er 10.2 Release 1 geguckt :oops: , aber JIRA is och nich dat Schnellste.
Es gibt 'nen Bugfix ... du mußt ihn dir nur kaufen.

Muß nur nochmal wer Testen, ob's wirklich geht.
Zitat:

List of new features and customer reported issues fixed in RAD Studio 10.2 Tokyo Release 2

RSP-19091
Stackoverflow error in TArray.QuickSort and System.Classes.QuickSort
RTL, RTL\Delphi
http://edn.embarcadero.com/article/44770


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:08 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz