Speicherverwaltung
-
Aloha,
ich habe von einem ausscheidenden Kollegen eine DLL geerbt, die ich künftig weiter pflegen soll. Die DLL exportiert eine Funktion, die wie folgt definiert ist:
char * holeEWODaten(char * anf) { struct Anfrage an ; Antwort ret[2] ; [...] return ret[0].ptr; }
Antwort wiederum ist wie folgt deklariert:
struct Einwohner{ char eworc[1]; char hinweis[80]; char ewo_gkz[3]; char pkz[17]; char u_version[1]; char anrede[2]; und noch viele char - Arrays ... }; struct HostAntwort{ char sysMeld[80]; char treffer[2]; Einwohner einw[10]; char abschluszeichen[8]; }; union Antwort{ char ptr[sizeof (HostAntwort)]; HostAntwort ha; };
Mich wundert nun, daß beim Aufrufer der DLL tatsächlich vernünftige, lesbare Daten ankommen. Da ret doch nur lokal definiert ist, und offensichtlich nirgendwo Speicher allokiert wird, hätte ich erwartet, daß beim Aufrufer nur Müll ankommt.
Warum also funktioniert das überhaupt?Gruß,
Guido Belligoi
-
Belli schrieb:
Da ret doch nur lokal definiert ist, und offensichtlich nirgendwo Speicher allokiert wird, hätte ich erwartet, daß beim Aufrufer nur Müll ankommt.
Warum also funktioniert das überhaupt?Gegenfrage: Wo im Standard steht, dass an der Adresse eines nicht mehr existierenden Arrays Müll stehen muss und wo definiert der Standard, was "Müll" ist?
Genau: Nirgends und nirgends. Im Standard steht nur, wann ein Programm gültig ist und wie es sich dann verhalten soll. Im Standard steht nicht, wie sich ein ungültiges Programm verhalten soll. Sprich: Das Ergebnis ist undefiniert.
-
Ja LordJaxoum, da hast Du natürlich recht.
Mich wundert einfach, wenn mir hier meine Annahme bestätigt wird - so wie von Dir - daß nämlich das Ergebnis undefiniert (von mir ursprünglich Müll genannt) ist, und wir (meine Firma) diese DLL seit Jahren im produktiven Einsatz haben, ohne daß es entsprechende Anwenderbeschwerden gegeben hat.
Deshalb hatte ich die vage Idee, daß ich vielleicht falsch liege und es eben doch ein definiertes Ergebnis gibt und suchte nach einem Hinweis, was ich übersehen habe.Hinzu kommt, daß ich keine Lösung dafür parat hätte, wie evtl. zu allokierender Speicher wieder freizugeben wäre; die aufrufende Anwendung ist eine Fremdanwendung, auf die wir hier keinen Einfluß haben ...
-
oaloh,
wie ist struct Anfrage deklariert ?
nicht überall wo ptr drannesteht, ist auch pointer drin
-
bajuffe schrieb:
oaloh,
wie ist struct Anfrage deklariert ?
nicht überall wo ptr drannesteht, ist auch pointer drinAnfrage ist ähnlich wie Einwohner definiert: Einfach ein paar char - Arrays - - aber ... Anfrage spielt doch überhaupt keine Rolle bei meinem 'Problem'.
Frage:
Kann ich dieses "undefinierte Ergebnis", das ich da zurückgebe, evtl. einfach dadurch zu einem definierten machen, daß ich Antwort ret[2] aus der Funktion herausnehme und ausserhalb der Funktion global definiere?
Ich bin mir im Moment nicht sicher, ob die Ergebnisse dann noch alle korrekt sind, wenn verschiedene User (die Anwendung läuft auf einem Server) die DLL nutzen ...
-
Belli schrieb:
Frage:
Kann ich dieses "undefinierte Ergebnis", das ich da zurückgebe, evtl. einfach dadurch zu einem definierten machen, daß ich Antwort ret[2] aus der Funktion herausnehme und ausserhalb der Funktion global definiere?
Ich bin mir im Moment nicht sicher, ob die Ergebnisse dann noch alle korrekt sind, wenn verschiedene User (die Anwendung läuft auf einem Server) die DLL nutzen ...Wenn Antwort ret[2] nur gelesen wird, mag das gehen, ansonsten ist das nicht mehr Threadsafe.
Sind das konstante Zeichenketten für die Antworten, die sich nicht ändern ?
Dann könntest du ja sowas hier machen:char* antwort[] = { "hallo", "echo" }; char* hole_daten() { int i; //... i = 1; // warum auch immer return antwort[1]; }
-
proggingmania schrieb:
Belli schrieb:
Frage:
Kann ich dieses "undefinierte Ergebnis", das ich da zurückgebe, evtl. einfach dadurch zu einem definierten machen, daß ich Antwort ret[2] aus der Funktion herausnehme und ausserhalb der Funktion global definiere?
Ich bin mir im Moment nicht sicher, ob die Ergebnisse dann noch alle korrekt sind, wenn verschiedene User (die Anwendung läuft auf einem Server) die DLL nutzen ...Wenn Antwort ret[2] nur gelesen wird, mag das gehen, ansonsten ist das nicht mehr Threadsafe.
Sind das konstante Zeichenketten für die Antworten, die sich nicht ändern ?Nö, die Antwort wird bei jedem Aufruf der Funktion abhängig vom Inhalt des Übergabeparameters neu ermittelt/aufgebaut ...
Das sinnvollste wäre natürlich, wenn der Aufrufer den Speicherbereich für die Antwort zur Verfügung stellen und einen Zeiger darauf übergeben würde, aber wie schon erwähnt ist das eine Fremdanwendung, auf die wir keinen Einfluß (zumindest nicht ohne erheblichen finanziellen Aufwand) haben ...
Deshalb suche ich verzweifelt nach einer anderen Möglichkeit, obwohl das ganze Zeug im Moment ja erstaunlicherweise noch funktioniert, aber ich möchte mich darauf nur ungern verlassen ...
-
Wie wäre es, wenn ich mir den Speicher für die Antwort vom Heap hole, bevor ich den Zeiger darauf zurückgebe, einen Thread starte, dem ich auch diesen Zeiger mitgebe und in dem Thread ein bißchen - sagen wir mal 5 Sekunden - warte, und dann dort den Speicher wieder freigebe.
Nicht besonders elegant, und es müsste natürlich eine Wartezeit gewählt werden, die sicherstellt, daß der Aufrufer die Daten abgearbeitet hat - aber so könnte es doch funktionieren, ohne daß man beim Aufrufer eingreifen muß, oder?
-
Kannst du nicht einfach static verwenden oder übersehe ich hier etwas?
-
feigling schrieb:
Kannst du nicht einfach static verwenden oder übersehe ich hier etwas?
Ich bin mir nicht sicher, ob das nicht genau so wenig threadsafe ist, wie wenn ich Antwort ret[2] global, also außerhalb der Funktion deklariere ...
Es arbeiten ja theoretisch verschiedene Clients zur gleichen Zeit mit dieser Funktion.
-
proggingmania schrieb:
Belli schrieb:
Frage:
Kann ich dieses "undefinierte Ergebnis", das ich da zurückgebe, evtl. einfach dadurch zu einem definierten machen, daß ich Antwort ret[2] aus der Funktion herausnehme und ausserhalb der Funktion global definiere?
Ich bin mir im Moment nicht sicher, ob die Ergebnisse dann noch alle korrekt sind, wenn verschiedene User (die Anwendung läuft auf einem Server) die DLL nutzen ...Wenn Antwort ret[2] nur gelesen wird, mag das gehen, ansonsten ist das nicht mehr Threadsafe.
Ich frage mich gerade, ob das überhaupt threadsafe sein muß
Wenn ich Charles Petzold in "Windowsprogrammierung" 5. Auflage auf Seite 1150 richtig verstehe, dann wird die DLL für jeden aufrufenden Prozeß in den Adreßraum des Aufrufers abgebildet.
Wenn ich das nicht mißinterpretiere, sollten sich verschiedene Aufrufer nicht ins Gehege kommen können, solange sie nicht selbst jeweils Threads abspalten, die ihrerseits wieder die DLL nutzen. Und das würde ich nach meinem jetzigen Informationsstand ausschließen ...
-
Belli schrieb:
Kann ich dieses "undefinierte Ergebnis", das ich da zurückgebe, evtl. einfach dadurch zu einem definierten machen, daß ich Antwort ret[2] aus der Funktion herausnehme und ausserhalb der Funktion global definiere?
Ich bin mir im Moment nicht sicher, ob die Ergebnisse dann noch alle korrekt sind, wenn verschiedene User (die Anwendung läuft auf einem Server) die DLL nutzen ...Bin nicht Windows- sicher,
aber gib' der holeEWODaten() intern den Speicher über malloc() statt per lokaler array- Definition, dann ist der Speicher auch außerhalb nicht undefiniert, der Aufrufer muß ihn halt free()en, was sich bei DLLs verbieten mag und als schlechterStil gilt.Alternativ gib ihr einen Pointer im Parameterteil mit, auf den schon der Speicher reserviert ist und in den die Antwort geschrieben werden muß. Dann eröffnet der Aufrufer den Speicher und macht ihn auch selbst wieder frei, gilt als sauberer.
In beiden Fällen mußt Du zwar auch den Aufrufer modifizieren, aber ich sehe nix Böses an weiteren Codepfuschereien, die Du Dir dafür einhandeln würdest. Strukturell dürftest Du damit die Kiste geringstmöglich ändern.
Und statisch ist halt einfach dödelig, da kömma ja gleich wieder mit BASIC anfangen
-
pointercrash() schrieb:
[...]
Alternativ gib ihr einen Pointer im Parameterteil mit, auf den schon der Speicher reserviert ist und in den die Antwort geschrieben werden muß. Dann eröffnet der Aufrufer den Speicher und macht ihn auch selbst wieder frei, gilt als sauberer.
[...]
DAS wäre meine Lösung ... WÄRE, aber wie schon erwähnt, handelt es sich bei dem Aufrufer um Fremdsoftware, die ich nicht ändern KANN ...
Ich werde mir aber jetzt gleich ein Testszenario schaffen, um feststellen zu können, ob Threadsicherheit erforderlich ist, wenn jeder aufrufende Prozeß die DLL nur aus einem einzigen Thread heraus aufruft ...
-
Belli schrieb:
Ich werde mir aber jetzt gleich ein Testszenario schaffen, um feststellen zu können, ob Threadsicherheit erforderlich ist, wenn jeder aufrufende Prozeß die DLL nur aus einem einzigen Thread heraus aufruft ...
Wenn die Prozesse keine eigenen Threads starten, die auf deine globalen dll- Daten zugreifen, kannst du dir das Testen auch schenken.