| Autor |
Beitrag |
Flamefire
      
Beiträge: 1207
Erhaltene Danke: 31
Win 10
Delphi 2009 Pro, C++ (Visual Studio)
|
Verfasst: Di 18.08.09 14:00
Ich habe einen Traffic logger geschrieben, der alle Packete aus einer Anwendung mitschneiden soll (àla WPE Pro aber als Proxy)
Die Packete speichere ich in einem Array, um sie filtern zu können, und zeige sie in einem Listview an.
Das Problem: Wenn ich das Array beim 2. mal freigeben möchte bekomme ich "Ungültige Zeigeroperation" beim SetLength(...,0) oder eine Access Violation beim Freigeben der Einträge im Listview.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45:
| TEntry = record opcode:Word; data:TBytes; direction:Byte; end; var Entry:Array[0..999] of TEntry; procedure TFrameAnalyzer.Add(opcode: Word; direction: Byte; data: pointer;size:word); var i:Integer; begin if(curEntry=1000) then begin for i := 0 to 500 - 1 do SetLength(Entry[i].data,0); Move(Entry[500],Entry[0],SizeOf(TEntry)*500); for i := 500 to 1000 - 1 do Entry[i].data:=nil; curEntry:=500; UpdateListView; end;
Entry[curEntry].opcode := opcode; Setlength(Entry[curEntry].data,size); if(size>0) then Move(data^,Entry[curEntry].data[0],size); Entry[curEntry].direction := direction; Inc(curEntry); end; procedure TFrameAnalyzer.UpdateListView; var i:Integer; begin sListView1.Items.BeginUpdate; sListView1.Items.Clear; for i := 0 to curEntry - 1 do begin if(not ElemBlocked(Entry[i])) then with sListView1.Items.Add do begin Caption:=IntToHex(Entry[i].opcode,4); SubItems.Add(Self.ByteToString(Entry[i])); SubItems.Add(StrDirection[Entry[i].direction]); end; end; sListView1.Items.EndUpdate; end; |
wenn ich "for i := 0 to 500 - 1 do SetLength(Entry[i].data,0);" entferne kommt kein Fehler mehr
edit:
Delphi-Quelltext 1: 2: 3:
| dass hier statt der schleifen funktioniert: for i := 0 to 500 - 1 do Entry[i]:=Entry[i+500]; |
aber warum?
ist ein dynamisches array in einem record nicht einfach ein pointer auf die array structur?
wird es dadurch nicht zum speicherleak? FastMM4 meldet zumindest nichts
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Di 18.08.09 14:18
Bitte mit Finalize(Entry[i]) arbeiten, da das noch ein paar Dinge mehr macht als nur die Länge des Arrays auf 0 zu setzen. Sonst hast Du da u.U. ein Memleak drin.
Aber machst Du nicht einfach folgendes?
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24:
| procedure TFrameAnalyzer.Add(opcode: Word; direction: Byte; data: pointer;size:word); var i:Integer; begin if(curEntry=1000) then begin for i := 0 to 500 - 1 do begin Entry[i] := Entry[i+500]; finalize(Entry[i+500]); end;
curEntry:=500; UpdateListView; end;
Entry[curEntry].opcode := opcode; Setlength(Entry[curEntry].data, size); if size>0 then Move(data^, Entry[curEntry].data[0],size); Entry[curEntry].direction := direction; Inc(curEntry); end; |
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Zuletzt bearbeitet von BenBE am Di 18.08.09 15:19, insgesamt 1-mal bearbeitet
|
|
Flamefire 
      
Beiträge: 1207
Erhaltene Danke: 31
Win 10
Delphi 2009 Pro, C++ (Visual Studio)
|
Verfasst: Di 18.08.09 14:59
ich glaube bei dir ist beim zitieren was schief gegangen
erstmal: Deine Lösung funktioniert ebenfalls, danke dafür
würde es nur gern verstehen:
1) was macht Finalize?
2) warum Finalize auf entry[i+500]?
wenn das array tatsächlich ein pointer auf die array structur ist, dann würde entry[x]:=entry[y] den inhalt des records kopieren. vermutlich macht der noch intern eine überprüfung bevor das array in x überschrieben wird (der hat ja einen referenzzähler drin. wenn der 0 ist gibt der das array frei, zumindest soweit ich das im debugger gesehen habe)
finalize auf entry[i+500] müsste mir doch dann das array, dess pointer ich nach entry[i] kopiert habe freigeben, wodurch es auf einmal fehlt, oder?
3) warum hat das mit dem Move nicht funktioniert?
PS: So weit ich das gesehen habe, wird finalize von setlength aufgerufen
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Di 18.08.09 15:29
Flamefire hat folgendes geschrieben : | ich glaube bei dir ist beim zitieren was schief gegangen  |
Nope, hatte beim Posten vergessen, überflüssige Teile deines Posts zu eliminieren
Flamefire hat folgendes geschrieben : | | erstmal: Deine Lösung funktioniert ebenfalls, danke dafür |
Als ob jemals Source von mir nicht funktioniert hätte
Flamefire hat folgendes geschrieben : | würde es nur gern verstehen:
1) was macht Finalize? |
F1, da werden Sie geHOLFEn
Flamefire hat folgendes geschrieben : | | 2) warum Finalize auf entry[i+500]? |
Die Zuweisung in der Zeile zuvor erzeugt eine Kopie des Eintrags und inkrementiert somit den Referenzzählers im Array. Um diese Kopie des Arrays freizugeben - also Delphi bescheid zu geben, dass dieser Eintrag gelöscht werden soll - muss der Aufruf dort hin. Danach findet sich an dieser Stelle ein blanker, uninitialisierter Eintrag, den SetLength beim Beschreiben korrekterweise als leer erkennt und somit wieder korrekt Speicher zuordnen kann.
Flamefire hat folgendes geschrieben : | | wenn das array tatsächlich ein pointer auf die array structur ist, dann würde entry[x]:=entry[y] den inhalt des records kopieren. vermutlich macht der noch intern eine überprüfung bevor das array in x überschrieben wird (der hat ja einen referenzzähler drin. wenn der 0 ist gibt der das array frei, zumindest soweit ich das im debugger gesehen habe) |
Die Zuweisung macht eine ganze Menge Compiler Magic intern. Intern wird für [X] einmal Finalize aufgerufen, danach folgt ein Move, gefolgt von einem Update der Referenzzähler ALLER Member der Struktur, die dies benötigen.
Flamefire hat folgendes geschrieben : | | finalize auf entry[i+500] müsste mir doch dann das array, dess pointer ich nach entry[i] kopiert habe freigeben, wodurch es auf einmal fehlt, oder? |
Nope. Siehe Erklärung, was diese Zuweisung intern macht ...
Flamefire hat folgendes geschrieben : | | 3) warum hat das mit dem Move nicht funktioniert? |
Weil Move die Referenzzähler nicht aktualisiert und du damit auf freigegebenen Speicher zugegriffen hast (daher die Exception mit der ungültigen Zeiger-Operation).
Flamefire hat folgendes geschrieben : | | PS: So weit ich das gesehen habe, wird finalize von setlength aufgerufen |
Korrekt. SetLength macht aber intern noch ne ganze Menge mehr. u.a. eine Initialisierung des zugewiesenen Speichers mit 0-Bytes.
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Flamefire 
      
Beiträge: 1207
Erhaltene Danke: 31
Win 10
Delphi 2009 Pro, C++ (Visual Studio)
|
Verfasst: Di 18.08.09 17:06
gut soweit.
nochmal zu dem move:
ich brauche doch den referenzzähler nicht verändern
wenn ich das so mache(was ich zumindest vorhatte):
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7:
| a,b:ptr; New(a);New(b); a:=iwas; b:=iwas; Free(a); a:=b; b:=nil; |
dann sollte in der theorie doch alles i.o. sein, oder?
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Di 18.08.09 17:59
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Flamefire 
      
Beiträge: 1207
Erhaltene Danke: 31
Win 10
Delphi 2009 Pro, C++ (Visual Studio)
|
Verfasst: Di 18.08.09 18:18
ich habe aber doch kein a[500] mehr nach:
Delphi-Quelltext 1: 2: 3: 4: 5:
| for i := 0 to 500 - 1 do SetLength(Entry[i].data,0); Move(Entry[500],Entry[0],SizeOf(TEntry)*500); for i := 500 to 1000 - 1 do Entry[i].data:=nil; |
danach habe ich ein ordentliches array in a[0] und ein nil statt eines arrays in 500
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Di 18.08.09 18:44
In a[0] steht dann aber ein finalisiertes Array, weil der Compiler die Referenz freigegeben hat. nil zuweisen bei einem Array führt implizit ein Finalize aus ...
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Flamefire 
      
Beiträge: 1207
Erhaltene Danke: 31
Win 10
Delphi 2009 Pro, C++ (Visual Studio)
|
Verfasst: Di 18.08.09 18:50
|
|
|