![]() |
Verständnisfrage offene Arrays, move und setlength
Gegeben sei folgendes Konstrukt:
Delphi-Quellcode:
Was passiert genau, wenn ich jetzt etwas mehr oder weniger willkürliches in R per "move" schiebe?
type Tx = packed record
a: integer; b: integer; end; type TY = packed record c: integer; d: integer; end; type TRec = packed record X: array of Tx; Y: array of TY; end; var R: TRec;
Delphi-Quellcode:
Ich vermute, dass der erste Zugriff (R.x[1].a) noch geht, weil sich dieser Wert noch in meinem Speicherbereich befindet, der zweite Zugriff (vx := R.x[lx - 1].a) aber nicht weil die Adresse davon außerhalb meines Speichersegmentes liegt.
procedure TForm1.FormCreate(Sender: TObject);
var x, sr, lx, ly, vx: integer; begin sr := sizeof(R); // 8 x := integer(@x); // irgendeine Adresse move(x, R, 8); lx := length(R.x); // zufällige Zahl, hier ziemlich groß ly := length(R.y); vx := R.x[1].a; // geht vx := R.x[lx - 1].a; // Zugriffsverletzung beim lesen Stimmt das soweit?
Delphi-Quellcode:
Wenn ich jetzt direkt versuche, die Größe des Array zu ändern crasht das ganze wieder. Ich vermute, dass hier Speicher freigegeben würde, der mir nicht gehört. Ist das richtig?lx := length(R.x); // zufällige Zahl // fillchar(R, sizeof(R), 0); // mit fillchar alles ok, ohne Crash setlength(R.x, 100000); Wenn ich mit fillchar meine Variable R aber zuvor auf 0 setze geht wei erwartet alles. Die Frage ist hier: Habe ich in der Zwischenzeit schon irgendeine Verletzung vorgenommen? Sprich wird nur mit der (zugegebenermaßen sinnlosen) Zuordnung
Delphi-Quellcode:
bereits irgendeine Verletzung vorgenommen oder werden da nur die 8 Byte, die für die Variable R reserviert sind, zweimal überschrieben und sonst passiert nichts?
move(x, R, 8);
fillchar(R, sizeof(R), 0); Wird mit dem ersten move schon irgend ein Speicherbereich verändert außer den 8 Byte die zu "R" gehören? Mir geht es rein um das Verständnis, nicht darum, ob der Code sinnvoll ist oder nicht. |
AW: Verständnisfrage offene Arrays, move und setlength
Zitat:
|
AW: Verständnisfrage offene Arrays, move und setlength
Zitat:
|
AW: Verständnisfrage offene Arrays, move und setlength
Zitat:
Anyway: Wenn Du mit Datentypen arbeitest, für die der Compiler die Speicherverwaltung übernimmt soweit es ums Aufräumen geht, lass die Finger von low-level-Funktionen wie Move und Fillchar. Das betrifft die Typen String (Ansi und Unicode), Interfaces, dynamische Arrays, Widestring. Für solche Typen initialisiert der Compiler auch lokale Variablen (auch wenn sie Teil eines Records sind), sorgt bei Kopieroperationen (per Assignment oder Copy bei Arrays) für korrekte Behandlung des reference counts und gibt automatisch den belegten Speicher frei, wenn die Variable out of scope geht. Move und Fillchar umgehen all diese Mechanismen und führen dann zu Speicherlecks und AVs. Lies den Delphi Language Guide! Der ist Teil der Onlinehilfe und enthält alle Infos über die Implementierung der diversen Datentypen die Du brauchst. |
AW: Verständnisfrage offene Arrays, move und setlength
Klar, würde ein FillChar mit 0 wieder ein leeres Array bereitstellen.
Aber wer weiß was bei dir wirklich vor dem Move/FillChar drin stand. Am Ende hast'e im glücklichsten Fall bloß ein Speicherleck, weil DU die automatische Speicherverwaltung der dynamischen Arrays böswillig zerstört hast, ohne zu wissen wie Diese intern funktioniert. (ich verrate besser mal nicht, dass es in System Records für die Verwaltungsdaten von LongStrings und dynamischen Arrays gibt, aber da Diese nicht öffentlich sind, sich Emba behaarlich weigert sie zu veröffentlichen und sie zuletzt auch auf unvorhersehbare Weise diese Arrays veränderten, ist es nicht einfach damit mit einer Kopie davon arbeiten zu wollen) Zitat:
denn "zufällige Zahl, hier ziemlich groß" kann auch schnell irgendwas Anders sein, z.B. eine Zugriffsverlertzunh, wenn es an der Stelle keinen resservierten Speicher gibt. Und wenn du jetzt auch noch irgendwas mit diesem Array machst, dann viel Spaß, wenn dieses "zufällige Zahl, hier ziemlich groß" irgendwas Wichtiges war, was du dabei eventuell überschreibst/zerstörst, ähnlich einem Bufferoverrun. |
AW: Verständnisfrage offene Arrays, move und setlength
Anstatt uns über den Sinn des ganzen im Dunkeln zu lassen, könntest du uns einfach erleuchten und wir finden eine andere Lösung.
Zitat:
Ich würde aber weitergehen, das ist mutwillige Zerstörung von fremden Eigentum und gehört angekreidet. Zum Schluss erkennen dann wieder die Virenscanner alle Delhi Programme als Viren. Nur weil ein Verrückter wild im Speicher rumschreibt. |
AW: Verständnisfrage offene Arrays, move und setlength
emm...
Was willst Du damit erreichen? Mit dem gruseligen Move überträgst Du die Adresse von einer Variablen die auf dem Stack liegt in einen globale Variable. Aber Sizeof(8) hätte dir hier schon einen Hinweis geben müssen, das dies so nicht passt. Ein dynamische Array liegt auf dem Heap und bei -8 liegt die Referenz-Zählung und bei -4 die Länge... Es ist also "nur" ein Pointer im Rekord. Siehe : ![]() Wenn ich Deinen Source richtig verstanden habe... |
AW: Verständnisfrage offene Arrays, move und setlength
Zitat:
Ich vruche es einmal zu erklären wie ich auf das Problem komme. Ich bekomme aus einer externen Quelle, auf die ich keinen Einfluss habe (DLL), Datensätze, die wie folgt (vereinfacht) aufgebaut sind.
Delphi-Quellcode:
In "Beschreibung" sind dann in jedem String im Klartext (ist eben so, kann ich nicht ändern) Untertypen beschreiben, z.B. "R=5; G=7; B=12"; "R=23; G=3; B=44" etc.
type TDatensatz = packed record
Zahl1: integer; Beschreibung1: TStringlist; Zahl2: integer; Beschreibung2: TStringlist; ... end; Um damit weiterarbeiten zu können möchte ich diese Datentypen in die folgende Struktur umwandeln:
Delphi-Quellcode:
Da die Größe einer Stringlist und die Größe eines Array of TUnteryp (im packed Record) jeweils 4 Byte sind war meine Idee eben, die Daten aus TDatensatz zuerst 1:1 (per Move) in eine Veriable vom Typ TMeinDatensatz zu schreiben (sizeof(TMeindatensatz) und sizeo(TDatensatz) sind gleich groß) und dann die Größe von Untertyp1 auf die Anzahl der Strings in der Stringlist (Beschribung) zu setzen und dann im Untertyp die Felder mit einem Parser zu ermitteln. Dass ich nach dem kopieren der Daten nicht direkt auf den Untertyp zugreifen kann ist mir schon klar.
type TUntertyp1 = packed record
R: integer; G: integer; B: integer; end; type TUntertyp1Array = array of TUntertyp1; type TMeinDatensatz = packed record Zahl1: integer; Untertyp1: TUntertyp1Array ... end; Die Frage ist eben, ob ich mit
Delphi-Quellcode:
Irgendwas verbotenes mache oder ob das geht.
var MeinDatensatz: TMeindatensatz;
move(Datensatz, Meindatensatz, sizeof(TMeindatensatz)); fillchar(MeinDatensatz.Untertyp1, 4, 0); setlength(MeinDatensatz.Untertyp1, Datensatz.Beschreibung.count); ... In diesem vereinfachten Besipiel könnte ich natürlich einfach die direkten Zuweisungen machen
Delphi-Quellcode:
In Wicklichkeit sind die Typen aber deutlich umfangreicher so dass mir eben die o.g. Idee als Vereinfachung gekommen ist.
MeinDatensatz.Zahl1 := Datensatz.Zahl1;
setlength(Meindatensatz.Untertyp1; Datensatz.Beschreibung.count); ... |
AW: Verständnisfrage offene Arrays, move und setlength
Und genau sowas macht man eben nicht, vor allem nicht bei gemangeten Typen, welche intern auch noch auf Pointer basieren.
Initialize Finalize := New Dispose InitializeRecord InitializeArray CopyRecord CopyArray MoveRecord MoveArray FinalizeRecord FinalizeArray ... Aber solche Funktionen ruft man eigentlich nicht direkt auf. Und bei der einem Objekt (TStringList) hilft das alles sowieso nicht, da dort nichts managed ist. |
AW: Verständnisfrage offene Arrays, move und setlength
Zitat:
Ich will die vielen 1:1 übertragbaren Werte (integer, boolean etc.) in einem Rutsch in meine Datenstruktur übernehmen und frage mich einfach nur, ob der eine Pointer (der auf einen Speicherberiech zeigen wird, der sehr wahrscheinlich mir nicht gehört) zwischen "move" und "fillchar" irgenwann dereferenziert wird. Also um die Frage auf ein Langwort runterzubrechen:
Delphi-Quellcode:
Ich glaube wenn ich die Zeile "move(p, Dings, 4);" weglasse sollte doch alles in Ordnung sein. Was ich wissen will ist, ob die Zeile "move(p, Dings, 4)" außer der Adresse @Dings .. @Dings + 3 noch einen Speicherbereich anspricht oder nicht.
type TDings = packed record
a: integer; b: integer; end; type TDingsArray = array of TDings; var Dings: TDings; //sizeof(Dings) = 4; var CardVal: Cardial; var p: pointer; p := @Dings; move(Dings, CardVal, 4); // Cardval = 0 move(p, CardVal, 4); // eben die Adresse move(p, Dings, 4); // passiert da jetzt irgendwas mit Speicher der mir nicht gehört? fillchar(Dings, 4, 0); // um den Müll wieder loszuwerden setlegth(Dings, 100); move(Dings, CardVal, 4); // CardVal = Zeiger auf Array of TDings? |
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:24 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz