Einzelnen Beitrag anzeigen

Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.152 Beiträge
 
Delphi 12 Athens
 
#4

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

  Alt 13. Dez 2017, 03:00
Ratet mal, wofür es den Debugger gibt.

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.
TArray.Sort<TFloat>(Values, Comparer);

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

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

Bei type Single funktioniert der Vergleich, da "NAN" dort nicht behandelt wird, und es knallt im QuickSort.
Das erste 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.
> {$RANGECHECKS ON} bzw. in den Projektoptionen aktiviert
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat