| Autor |
Beitrag |
MrSaint
      
Beiträge: 1033
Erhaltene Danke: 1
WinXP Pro SP2
Delphi 6 Prof.
|
Verfasst: So 16.11.03 22:10
Hi!
Ich hab hier n Programm (soll mal n Proxy-Server werden), welches mir kuriose Fehlermeldungen generiert! Ich benutz die Indy Komponenten (TIdTCPServer, TIdTCPClient TIdThreadMngrDefault) und ich bekomm bei "end." ne AccessViolation!!!!!!!!!!!!!
Also das is so: ich start mein programm, dann ruf ich ne seite im Browser auf. der schickt meinem programm auch korrekt alles zu und mein programm fängt an zu arbeiten. Dann bekommich aber ganz plötzlich hier ne AV:
Delphi-Quelltext 1: 2: 3: 4: 5:
| begin Application.Initialize; Application.CreateForm(TFrmMain, FrmMain); Application.Run; end. |
und ich weiß absolut net, was ich damit anfangen soll... wo is denn jetzt der blöde fehler? und genau die gleiche AV kommt gleich danach wieder. Und dann is sense: mein programm reagiert nemme und ich muss es per Strg+F2 aus Delphi raus abschießen... Wenn ich dann nochmal auf F9 drück und das programm nommal start, dann kommen wirklich die kuriosesten Fehlermeldungen... irgendwo im Source (auch im Indy Source) kommen auf einmal irgendwelche AVs etc. Wenn ich dann Delphi neustart und dann F9 drück, dann kommen wieder nur die 2 AVs von oben (nich die hundert anderen in den Indys). Also irgendwas geht da grande schief...
hab das Problem schon länger und bekomm es einfach nich in den Griff... Hab dann heftige Logging-Funktionen engebaut (bei jeder Procedure die aufgerufen wird werdn die ewichtigsten daten in ne datei ausgegeben) und da is mir aufgefallen, dass (ich glaub) immer diese Funktion als letzter Aufruf vor dem Nicht-mehr-reagieren meines Programms aufgerufen wurde:
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:
| procedure TTCPThread.DeleteFromList; var i:integer; ThreadWorkHelp:PThreadWork; TCPThreadInList:TTCPThread; begin tolog:='TCPThread.DeleteFromList - ID: TCPThread: '+inttostr(ThreadID)+'; AThread: '+inttostr(AThreadClient.ThreadID); Synchronize(log); i:=-1; try with ThreadWork.LockList do begin while (i<Count-1) do begin inc(i); ThreadWorkHelp:=Items[i]; TCPThreadInList:=ThreadWorkHelp.TCPThread; if TCPThreadInList.ThreadID=ThreadID then begin tolog:='TCPThread.DeleteFromList - Deleted Thread #'+inttostr(i)+'; ID: TCPThread: '+inttostr(ThreadID)+'; AThread: '+inttostr(AthreadClient.ThreadID); Synchronize(log); Delete(i); break; end; end; end; finally ThreadWork.UnlockList; end; tolog:='TCPThread.DeleteFromList - ID: TCPThread: '+inttostr(ThreadID)+'; AThread: '+inttostr(AThreadClient.ThreadID)+' DONE'; Synchronize(log); end; |
n bissl erklärung dazu: Diese Procedure löscht einen Eintrag aus der Liste ThreadWork (TThreadList). In ThreadWork sind Pointer auf das hier gespeichert:
Delphi-Quelltext 1: 2: 3: 4:
| TThreadWork=record AThread:TIdPeerThread; TCPThread:TTCPThread; end; |
nun wird da überprüft, welcher der TCPThreads aus der Liste mit dem eigenen (das ganze is ne Funktion aus ner Thread-Klasse) übereinstimmt und der Eintrag wird dann aus der Liste gelöscht.
Also das ganze Prog is Multi-thread-based...
Naja.. und ich weiß jetzt absolut nemme weiter  und hoff, dass ihr mir helfen könnt! In der DeleteFromList kann ich kein Fehler finden! Ich glaub der steigt schon bei dem "with ThreadWork.Locklist" aus... aber: WARUM??? und warum bekomm ich dann ne AV bei "end."?????
MrSaint
Moderiert von Tino: Code- durch Delphi-Tags ersetzt.
_________________ "people knew how to write small, efficient programs [...], a skill that has subsequently been lost"
Andrew S. Tanenbaum - Modern Operating Systems
|
|
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: So 16.11.03 23:08
Die AV tritt bei Applictaion.Run auf. Da läuft was beim Initialisieren falsch.
|
|
MrSaint 
      
Beiträge: 1033
Erhaltene Danke: 1
WinXP Pro SP2
Delphi 6 Prof.
|
Verfasst: So 16.11.03 23:12
beim initialisieren?!?!?
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| procedure TFrmMain.FormCreate(Sender: TObject); begin HandleDisconnect:=true; TCPServer.Active:=True; ThreadWork:=TThreadList.Create; Application.OnException:=ErrorHandler; path:=extractfilepath(application.exename); if path[length(path)]<>'\' then path:=path+'\'; end; |
Was soll da falsch laufen?
MrSaint
Moderiert von Tino: Code- durch Delphi-Tags ersetzt.
_________________ "people knew how to write small, efficient programs [...], a skill that has subsequently been lost"
Andrew S. Tanenbaum - Modern Operating Systems
|
|
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1
|
Verfasst: So 16.11.03 23:25
Keine Ahnung. So spontan wüede ich sagen es liegt an dieser Zeile:
Delphi-Quelltext 1:
| TCPServer.Active:=True; |
Kommentier die mal aus.
|
|
Motzi
      
Beiträge: 2931
XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
|
Verfasst: Mo 17.11.03 10:05
Also wenn ganz am Ende des Progs irgendwelche Fehler auftreten, dann liegt das meistens daran, dass du dir den Stack zerschossen hast oder über irgendwelche Array/Speichergrenzen rausgegangen bist... bei den Compiler-Optionen gibt es eine Möglichkeit diese "Range-Exceptions" einzuschalten (weiß jetzt aber nicht genau wie die heißt), schau mal ob du die findest...
_________________ gringo pussy cats - eef i see you i will pull your tail out by eets roots!
|
|
mstuebner
      
Beiträge: 132
Win2000, XP
D7
|
Verfasst: Mo 17.11.03 14:18
| Motzi hat folgendes geschrieben: | | Also wenn ganz am Ende des Progs irgendwelche Fehler auftreten, dann liegt das meistens daran, dass du dir den Stack zerschossen hast oder über irgendwelche Array/Speichergrenzen rausgegangen bist... bei den Compiler-Optionen gibt es eine Möglichkeit diese "Range-Exceptions" einzuschalten (weiß jetzt aber nicht genau wie die heißt), schau mal ob du die findest... |
Wobei es wesentlich besser ist die Ursache für den Fehler zu beseitigen, als dessen Anzeige. Ein Arzt gibt Dir hoffentlich auch keine lange Hose um Deinen offenen Beinbruch zu kaschieren. 
_________________ mfg Matthias
|
|
Motzi
      
Beiträge: 2931
XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
|
Verfasst: Mo 17.11.03 14:30
Das wollte ich damit auch nicht sagen, ich wollte damit andeuten, dass er diese Option einschalten soll, damit solche Grenz-Überschreitungen schon zur Laufzeit erkannt werden und eine entsprechende Exception ausgelöst wird! Damit kann man dann die entsprechende Fehlerquelle finden und beseitigen..!
_________________ gringo pussy cats - eef i see you i will pull your tail out by eets roots!
|
|
MrSaint 
      
Beiträge: 1033
Erhaltene Danke: 1
WinXP Pro SP2
Delphi 6 Prof.
|
Verfasst: Mo 17.11.03 15:27
hmmm... also ich hab nun die "bereichsprüfung" angeschaltet... jetzt bekomm ich ne "External Exception C000001D". Laut www.delphifaq.com/fq/q1061.shtml heißt das "STATUS_ILLEGAL_INSTRUCTION"...
das is bei dieser Zeile:
Delphi-Quelltext 1:
| TCPClient.WriteLn(request); |
aber ich glaub die zeile is nur zufall... weil ich hab davor genau vor dieser zeile noch ein
Delphi-Quelltext 1:
| repeat until TCPClient.Connected; |
gehabt und da war der Fehler dann bei der Zeile...
Danach bekomm ich dann noch n Fehler im Indy-Source, der aber wohl mit der External Exception was zu tun hat, weil er bei einer Zeile passiert, wo er die TCPServerExecute aufruft (und das WriteLn von vorher steht in der TCPServerExecute)...
Und dann kommen wieder die beiden AVs auf das "end." und dann is wieder aus... reagiert nemme..
und ich glaub ihr habt mich irgendwie n bissl falsch verstanden! Der Fehler passiert net, wenn ich in Delphi auf F9 drückt, also wenn ich das programm start, sondern erst, wenn das Programm was zum Arbeiten (vom Browser) bekommt...
ich versteh das alles net...
MrSaint
_________________ "people knew how to write small, efficient programs [...], a skill that has subsequently been lost"
Andrew S. Tanenbaum - Modern Operating Systems
|
|
Motzi
      
Beiträge: 2931
XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
|
Verfasst: Mo 17.11.03 16:14
Arbeitest du irgendwo mit Pointern/dyn. alloziertem Speicher/dyn. Arrays oder ähnlichem?
_________________ gringo pussy cats - eef i see you i will pull your tail out by eets roots!
|
|
MrSaint 
      
Beiträge: 1033
Erhaltene Danke: 1
WinXP Pro SP2
Delphi 6 Prof.
|
Verfasst: Mo 17.11.03 16:17
jo, ne menge.... aber wenn ich net weiß, wo der fehler steckt, dann is das wie ne suche nach der stecknadel im heuhaufen!
MrSaint
_________________ "people knew how to write small, efficient programs [...], a skill that has subsequently been lost"
Andrew S. Tanenbaum - Modern Operating Systems
|
|
Motzi
      
Beiträge: 2931
XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
|
Verfasst: Mo 17.11.03 16:31
Was davo jetzt? Pointer oder dyn. Arrays oder beides? Bei dyn. Arrays hilft dir das "RangeChecking": Projekt-Optionen->Compiler->Runtime errors->Range checking (das ist die Überprüfung die ich oben gemeint hab). Bei Pointern wirds ein bisschen mühsamer... ich hatte auch schon das Problem, dass ich für einen Pointer unabsichtlich zuwenig Speicher reserviert hab und daher über die Grenzen des reservierten Speichers hinausgeschrieben hab. Dieser Fehler hat sich ebenfalls erst beim "end." bemerkbar gemacht. Check mal alle Routinen in denen du dyn. Speicher allozierst ob auch wirklich genug Speicher reserviert wird und dann schau was du so alles in diesen Speicher reinschreibst und ob sich das überhaupt ausgeht...
_________________ gringo pussy cats - eef i see you i will pull your tail out by eets roots!
|
|
MrSaint 
      
Beiträge: 1033
Erhaltene Danke: 1
WinXP Pro SP2
Delphi 6 Prof.
|
Verfasst: Mo 17.11.03 16:34
hmmm... also ich hab halt ne menge pointer drin... keine dyn. arrays... ich guck das dann heut noch durch...
MrSaint
_________________ "people knew how to write small, efficient programs [...], a skill that has subsequently been lost"
Andrew S. Tanenbaum - Modern Operating Systems
|
|
barfuesser
      
Beiträge: 324
|
Verfasst: Mo 17.11.03 17:48
|
|
MrSaint 
      
Beiträge: 1033
Erhaltene Danke: 1
WinXP Pro SP2
Delphi 6 Prof.
|
Verfasst: Mo 17.11.03 17:58
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:
| if not exists then begin TCPClient:=TIdTCPClient.Create(Self); TCPClient.Host:=server; TCPClient.Port:=Port;
TCPThread:=TTCPThread.Create(True); TCPThread.FreeOnTerminate:=true; TCPThread.TCPClient:=TCPClient; TCPThread.AThreadClient:=AThread;
GetMem(ThreadWorkHelp,sizeof(TThreadWork)); ThreadWorkHelp.AThread:=AThread; ThreadWorkHelp.TCPThread:=TCPThread; try with ThreadWork.Locklist do begin Add(ThreadWorkHelp); log('Created new thread #'+inttostr(Count-1)); end; finally ThreadWork.UnlockList; end;
TCPThread.Resume; end else begin TCPThread:=ThreadWorkHelp.TCPThread; TCPClient:=TCPThread.TCPClient; end;
log('REQUEST: '+url+' ['+server+':'+inttostr(Port)+']');
if not TCPClient.Connected then begin TCPClient.Connect; end; TCPClient.WriteLn(request); end; |
exists ist true, wenn der Thread schon existiert. wenn so, dann wird auch der existierende TCPThread und TCPClient genutzt, ansonsten werden die beiden neu erzeugt...
also in der Zeile davor ist ein "TCPCLient.Connect;"... das fällt aber wohl net in meinen "Zuständigkeitsbereich", das sollte Indy machen... und ich glaub net, dass da so ein massiver bug drin is...
MrSaint
_________________ "people knew how to write small, efficient programs [...], a skill that has subsequently been lost"
Andrew S. Tanenbaum - Modern Operating Systems
|
|
barfuesser
      
Beiträge: 324
|
Verfasst: Mo 17.11.03 18:08
Falls TCPThread schon auf einen laufenden Thread verweist, dann weistTCPThread:=ThreadWorkHelp.TCPThread;diesem Zeiger einen neuen Thread zu. Keine Ahnung ob so etwas überhaupt funktionieren kann, aber ich halte dies zumindest für äußerst gewagt.
barfuesser
|
|
MrSaint 
      
Beiträge: 1033
Erhaltene Danke: 1
WinXP Pro SP2
Delphi 6 Prof.
|
Verfasst: Mo 17.11.03 18:14
TCPThread is ne lokale Variable, die immer gesetzt werden muss (das da oben is n Auszug aus der TCPServerExecute)... ich muss TCPThread setzen, damit ich auf den Thread zugreifen kann (auch wenn der schon im Hintergrund läuft)... und in einer schleife vorher setz ich das ThreadWorkHelp, falls der Thread schon existiert => TCPThread:=ThreadWorkHelp.TCPThread macht den Thread, der im Hintergrund schon laüft und dessen Pointer in ThreadWorkHelp.TCPThread steckt nur für diese procedure (TCPServerExecute) zugänglich...
MrSaint
_________________ "people knew how to write small, efficient programs [...], a skill that has subsequently been lost"
Andrew S. Tanenbaum - Modern Operating Systems
|
|
barfuesser
      
Beiträge: 324
|
Verfasst: Mo 17.11.03 18:19
Also exists heißt dann nicht TCPThread existiert sondern ThreadWorkHelp.TCPThread existiert? Ist das so richtig?
barfuesser
|
|
MrSaint 
      
Beiträge: 1033
Erhaltene Danke: 1
WinXP Pro SP2
Delphi 6 Prof.
|
Verfasst: Mo 17.11.03 18:28
ich hätt vielleicht gleich den code von der ganzen procedure posten sollen:
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: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114:
| procedure TFrmMain.TCPServerExecute(AThread: TIdPeerThread); var buf:TStrings; server,url,request,hlp:string; port,r,i:integer; TCPClient:TIdTCPClient; TCPThread:TTCPThread; ThreadWorkHelp:PThreadWork; exists:boolean; List:TList; begin if AThread.Terminated or (not AThread.Connection.Connected) then exit; log('TCPServer.Execute'); buf:=TStringList.Create; request:=''; AThread.Connection.ReadStrings(buf,1); repeat request:=request+buf[0]+#13+#10; buf.Clear; AThread.Connection.ReadStrings(buf,1); until length(buf[0])=0; request:=request+#13+#10+#13+#10; buf.Free; url:=copy(request,pos(' ',request)+1,length(request)); url:=copy(url,0,pos(' ',url)-1); if lowercase(copy(url,0,7))<>'http://' then begin send_error(AThread,'<b>PROXY ERROR:</b> Es wird nur das HTTP Protokoll unterstützt!'); AThread.Connection.Disconnect; exit; end; server:=copy(url,8,length(url)); if pos('/',server)<>0 then server:=copy(server,0,pos('/',server)-1); if pos(':',server)<>0 then begin hlp:=copy(server,pos(':',server)+1,length(server)); val(hlp,port,r); log('Port: '+hlp); if r<>0 then begin send_error(AThread,'<b>PROXY ERROR:</b> Port-Fehler!'); AThread.Connection.Disconnect; exit; end; server:=copy(server,0,pos(':',server)-1); end else port:=80; if not IsIPAddr(server) then server:=GetIPFromHost(server);
exists:=false; i:=-1; try with ThreadWork.LockList do begin while (i<Count-1) do begin inc(i); ThreadWorkHelp:=Items[i]; if ThreadWorkHelp.AThread=AThread then begin log('Reusing Thread #'+inttostr(i)); exists:=true; break; end; end; end; finally ThreadWork.UnlockList; end;
if not exists then begin TCPClient:=TIdTCPClient.Create(Self); TCPClient.Host:=server; TCPClient.Port:=Port;
TCPThread:=TTCPThread.Create(True); TCPThread.FreeOnTerminate:=true; TCPThread.TCPClient:=TCPClient; TCPThread.AThreadClient:=AThread;
GetMem(ThreadWorkHelp,sizeof(TThreadWork)); ThreadWorkHelp.AThread:=AThread; ThreadWorkHelp.TCPThread:=TCPThread; try with ThreadWork.Locklist do begin Add(ThreadWorkHelp); log('Created new thread #'+inttostr(Count-1)); end; finally ThreadWork.UnlockList; end;
TCPThread.Resume; end else begin TCPThread:=ThreadWorkHelp.TCPThread; TCPClient:=TCPThread.TCPClient; end;
log('REQUEST: '+url+' ['+server+':'+inttostr(Port)+']');
if not TCPClient.Connected then begin TCPClient.Connect; end; TCPClient.WriteLn(request); end; |
(den teil von "HIER UNINTERESSANT" bis "HIER WIRDS WIEDER INTERESSANNT" könnt ihr überspringen... da wird nur der request vom browser auseinanderklamausert...)
Also exists bedeuted, dass der AThread (der ja der Proceudre TCPServerExecute von indy her übergeben wir) existiert....
mein Porgramm acht das so:
Browser ==> TCPServer (AThread) -> TCPClient (TCPThread) ==> Webserver
und in der Funktion TCPServerExecute hab ich ja erst mal bloß das AThread gegeben. also guck ich, ob solch ein AThread schon in meiner Liste is. Wenn ja weiß ich, dass der AThread schon existiert und dann auch ein dazugehöriger TCPThread (es komm immer 1 TCPThread auf 1 AThread). Den weis ich dann zu. Und dieser TCPThread hat ne property "TCPClient" in der der Pointer für den zugehörigen TCPClient hält. Den weis ich dann auch noch zu und dann wird die Message (request) gesendet....
MrSaint
P.S.: sorry, dass ich mich hier a bissl blöd angestellt hab mit dem posten... hätte gleich die ganze procedure posten sollen 
_________________ "people knew how to write small, efficient programs [...], a skill that has subsequently been lost"
Andrew S. Tanenbaum - Modern Operating Systems
|
|
Motzi
      
Beiträge: 2931
XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
|
Verfasst: Mo 17.11.03 21:06
Und der Fehler tritt nur auf wenn diese Routine durchlaufen wird..? Wie ist TThreadWork deklariert?
_________________ gringo pussy cats - eef i see you i will pull your tail out by eets roots!
|
|
MrSaint 
      
Beiträge: 1033
Erhaltene Danke: 1
WinXP Pro SP2
Delphi 6 Prof.
|
Verfasst: Mo 17.11.03 21:19
| MrSaint hat folgendes geschrieben: | Delphi-Quelltext 1: 2: 3: 4:
| TThreadWork=record AThread:TIdPeerThread; TCPThread:TTCPThread; end; |
|
Ja, also es passiert zumindest net, wenn ich das programm einfach nur starte... und wenn ich dann ne seite im browser aufruf (mein programm also daten an den TCPServer geschickt bekommt, dann wird die Methode aufgerufen, ja! da das alles multi-threaded is eiß ich eben net genau ob da der fehler liegt, aber wie ich ja schon geschrieben hab: der debugger packt mich da bei der External Exception hin! Für das durchgucken wegen dem "über den Speicherbereich rausschreiben" muss ich noch gucken, aber eigentlich kann ich's mir net vorstellen... ich reservier eigentlich bloß einmal per hand speicher und das is, wenn ich n neuen eintrag in die ThreadWork reinschreib.. und das mach ich so, wie oben in dem Quelltext drin steht (da mit dem GetMem)... das is alles...
Moment! mir kommt da gerade ein Gedanke! wenn ich den Speicher per GetMem reservier sollte ich den Speicher doch, wenn ich den eintrag aus der liste rauslösche auch wieder freigeben, oder?  Ich test das mal...
MrSaint
_________________ "people knew how to write small, efficient programs [...], a skill that has subsequently been lost"
Andrew S. Tanenbaum - Modern Operating Systems
|
|