python bricht ab, debugging

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
hypnoticum
User
Beiträge: 132
Registriert: Dienstag 15. März 2011, 15:43

Hallo
bei mir stürzt Python ab: "python.exe has encountered a problem and needs to close ..."
und ich weiss nicht wie ich die Ursache dafür finden soll.

Wenn ich das Script schrittweise ausführe stürzt es bei der zweiten Iteration immer an der selben Stelle ab, lasse ich es normal laufen schafft es fünf Iterationen.
Ich kann erstmal so ohne weiteres leider kein Minimalbeispiel erstellen, da das Script mehrere Dateien und Extensions in einer bestimmten Verzeichnisstruktur benutzt.

Hat jemand eine Idee, wie man die Absturzursache lokalisiert?

Nachtrag: Es scheint wieder mit falsch freigegebenen Objekten zusammenzuhängen ("PyDECREF()").
Wenn ich alle auskommentiere läuft das Script.
Ich dachte nicht, dass ich mit den unten stehenden Funktionen bestehende Referenzen lösche.
Weiß jemand warum welche Referenzen nicht gelöscht werden dürfen?

Code: Alles auswählen

// assign the parameter-strings given in the 'floatParamDict' to their corresponding values
// and log them to the measurement-result-file
PyObject *SetFloatParam(PyObject* PyDict, int n_floatParam, floatTypePrm floatParam[], FILE* ResultFile){
	PyObject *PyList = NULL, *PyKey = NULL;
	char* key;
	int i, j, size;

	PyList = PyDict_Keys(PyDict);
	size = PyList_GET_SIZE(PyList);
	for (j = 0; j < size; j++){
		PyKey = PyList_GetItem(PyList, j);
		key = PyString_AsString(PyKey);
		for (i = 0; i < n_floatParam; i++){
			if (strcmp(key, floatParam[i].name) == 0){
				*floatParam[i].value = ViReal64FromDict(PyDict, key);
				fprintf(ResultFile, "\t%s = %f\n", key, (float)*floatParam[i].value);
				PyDict_DelItem(PyDict, PyKey);
				break;
			}
		}
		//Py_DECREF(PyKey);
	}
	//Py_DECREF(PyList);
	fprintf (ResultFile, "\n");

	return PyDict;
}

void CheckForRest(PyObject *PyRetDict){
	PyObject *PyList = NULL, *PyKey = NULL;
	char* key;
	int i, size;

	PyList = PyDict_Keys(PyRetDict);
	size = PyList_GET_SIZE(PyList);
	for (i = 0; i < size; i++){
		PyKey = PyList_GetItem(PyList, i);
		key = PyString_AsString(PyKey);
		PyObject_CallMethod(MsgDia(), "dispConfirm", "(ssi)", key, "Wrong or Unused Parameter", 0);
		//Py_DECREF(PyKey);
	}
	PyDict_Clear(PyRetDict);
	//Py_DECREF(PyList);
}
Zuletzt geändert von Anonymous am Donnerstag 26. Mai 2011, 00:22, insgesamt 1-mal geändert.
Grund: Quelltexttyp in C geändert.
Dauerbaustelle
User
Beiträge: 996
Registriert: Mittwoch 9. Januar 2008, 13:48

Probier's doch einfach aus?! `PyKey` darf nicht gelöscht werden, weil `PyList_GetItem` den Refcount NICHT erhöht.
BlackJack

@hypnoticum: Da ist ein bisschen wenig Fehlerbehandlung drin. Im Grunde gar keine. Das ist in Python-Quelltext kein Problem weil bei Fehlern eine Ausnahme generiert wird und dem Benutzer/Programmierer ein hilfreicher Stacktrace geliefert wird, aber bei C-Code stürzt das Programm dann einfach kommentarlos ab, oder der Fehler wird scheinbar ignoriert und führt dann an ganz anderen Stellen zu Problemen.

Die Verarbeitung in `SetFloatParam()` ist auch nicht besonders elegant mit den doppelt verschachtelten Schleifen. Wenn man statt der Schlüssel des Dictionaries die Namen in `floatParam` durchgehen würde, bräuchte man nur eine Schleife und hätte lineare statt quadratischer Laufzeit.

Den Schlüssel in `CheckForRest()` erst in eine Zeichenkette umzuwandeln um die dann beim Methodenaufruf wieder in ein Pyton-`str`-Objekt umzuwandeln, ist ein unnötiger Zwischenschritt.
hypnoticum
User
Beiträge: 132
Registriert: Dienstag 15. März 2011, 15:43

@BlackJack:
Das mit der Zeichenkette hätte ich auch gern umgangen, aber ich habe keine andere Lösung gefunden.
Fehlermeldungen generieren versuch ich ja schon zB. dient gerade 'CheckforRest' einer Überprüfung.
alle Typen erst zu überprüfen bevor ich die Funktionen anwende spar ich mir aus Zeitgründen - wär zwar schöner ...
BlackJack

@hypnoticum: `PyKey` ist ein `PyObject`, und natürlich bietet `PyObject_CallMethod()` auch die Möglichkeit Argumente von Typ `PyObject` zu übergeben.

Eine ordentliche Fehlerbehandlung ist hier keine Frage der Schönheit sondern ob das Programm ordentlich oder kaputt ist. An anderer Stelle fragst Du wie man Fehler in einer C-Erweiterung finden kann, wenn das Programm mit einer Speicherzugriffsverletzung abstürzt, und hier erklärst die Fehlerbehandlung die genau so etwas verhindern kann zur Schönheitsfrage!? Das passt irgendwie nicht zusammen.

Falls Du mit Zeitgründen die Zeit meinst, welche die Programmierung der Fehlerbehandlung in Anspruch nimmt, dann musst Du die auch gegen die Zeit bei der Fehlersuche bei Abstürzen verrechnen.
hypnoticum
User
Beiträge: 132
Registriert: Dienstag 15. März 2011, 15:43

@BlackJack:
Ok, hast ja recht: die Fehlersuche erleichtert man sich durch Fehlbehandlung und spart so effektiv mehr Zeit.
Nur braucht es wohl auch Erfahrung abzuschätzen, wann häufig Fehler enstehen und welche Fehler abgefangen werden sollen.
Man kann da - glaube ich - beliebig viel Aufwand treiben.
BlackJack

@hypnoticum: Man sollte einfach überall wo etwas schief gehen könnte, Fehler entsprechend behandeln. Dafür ist nicht beliebig viel Aufwand nötig, denn diese Stellen sind in der Anzahl ja begrenzt. Das ist eigentlich recht einfach. Man muss es nur tun.
Antworten