Einzelnen Beitrag anzeigen

Benutzerbild von himitsu
himitsu

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

AW: Kleines Weihnachtsgeschenk: DEC V6.00 verfügbar

  Alt 18. Dez 2020, 03:58
Die 130 Zeilen der Copy von Code aus der System.pas kann man "etwas" Kürzen und durch Code ersetzen,
der immer "sicher" funktionieren wird, selbst wenn Embarcadero mal wieder das Interne der LongString-Typen ändern sollte.
(OK, ist selten passiert und die letzten 2 Mal waren um 2009/2010)

Delphi-Quellcode:
// DECUtilRawByteStringHelper.pas

procedure UniqueString(var Str: RawByteString); overload;
begin
  if StringRefCount(Str) <> 1 then
    SetLength(Str, Length(Str));
end;
Da diese Funktion nur einmal verwendet wird und der Code nun nur noch ein Zweizeiler ist, könnte man eigentlich auch gleich die ganze Unit loswerden und den Code direkt einsetzen.
Delphi-Quellcode:
// DECUtil.pas

procedure ProtectString(var Source: RawByteString);
begin
  if Length(Source) > 0 then
  begin
    // UniqueString(Source); cannot be called with a RawByteString as there is
    // no overload for it, so we need to call our own one.
    //DECUtilRawByteStringHelper.UniqueString(Source);
    if StringRefCount(Source) <> 1 then
      SetLength(Source, Length(Source));

    ProtectBuffer(Pointer(Source)^, Length(Source) * SizeOf(Source[Low(Source)]));
    Source := '';
  end;
end;



Was mich nach reichlicher Überlegung aber überrascht hat, ist der Denkfehler von Hagen,
denn das UniqueString ist hier absolut sinnlos, in den ProtectString-Funktionen.

Denn diese Funktion arbeitet nur bei RefCount = 1 korrekt, bzw. sie hat ausschließlich dort die geplante Wirkung.
Und die "geplante" Funktion ist das "sichere Löschen" des Speichers. (überschreiben mit einem Muster)
  • mit RefCount kleiner 0 (genauer -1) ist es eine String-Konstante in schreibgeschütztem Speicher und die lässt sich sowieso nicht löschen
    • weiter siehe "RefCount ungleich größer 1"
  • bei RefCount gleich 1 passt alles
    • es wird nicht kopiert, also der "richtige" Speicher wird überschrieben und anschließend freigegeben
  • bei RefCount größer 1 gibt es mehrere Zeiger auf diesen String
    • da großer/ungleich 1, wird erstmal der ganze String kopiert (Unique in einen neuen Speicher, mit RefCount = 1)
    • dann wird "nur" der neue Speicher gelöscht/überschrieben, den es aber ohne das Kopieren sowieso nicht gegeben hätte
    • am Ende wird die neue Referenz+Speicher freigegeben
    • ABER zurück bleibt der originale String (mit/für die restlichen Referenzen), womit sich rein garnichts änderte und "effektiv" auch nicht gelöscht wurde

Delphi-Quellcode:
procedure ProtectString(var Source: RawByteString); // auch bei String/UnicodeString, AnsiString und WideString
begin
  if (Source <> '') and (StringRefCount(Source) = 1) then
    ProtectBuffer(Pointer(Source)^, Length(Source) * SizeOf(Source[Low(Source)]));
  Source := '';
end;


Und statt Length(Source) * SizeOf(Source[Low(Source)]) könnte man auch Length(Source) * StringElementSize(Source) verwenden,
allerdings weiß ich nicht, wie es im FPC mit Delphi-Referenz durchsuchenStringElementSize und StringRefCount aussieht.

Bzw. weiß ich garnicht, ob im FPC die LongStrings intern überhaupt gleich aufgebaut sind, wie aktuell im Delphi. (mit CodePage und CharSize ElementSize)
Diese beiden Felder wurden 2009 mit der Unicodeumstellung eingefügt. (aber egal ... wenn die Kopie entfent wurde, brauchen wir uns nicht mehr darum zu kümmern)
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu (18. Dez 2020 um 04:13 Uhr)
  Mit Zitat antworten Zitat