Seite 1 von 1
Access Violation bei PyRun_File
Verfasst: Donnerstag 24. Oktober 2013, 15:53
von init-0
Hallo,
Ich versuche in C++ eine Python Datei auszuführen, leider bekomme ich bei der Ausführung immer einen Access Violation Error.
Code: Alles auswählen
Py_Initialize();
FILE* main = fopen("H:\\Projects\\PySE\\testFile.py", "r");
PyObject* PyFileObject;
PyFileObject = PyFile_FromFd((int) main, NULL, "r", -1, NULL, NULL, NULL, 1);
PyObject *pGlobal = PyDict_New();
PyDict_SetItemString(pGlobal, "__builtins__", PyEval_GetBuiltins());
PyRun_File(main, "test", Py_file_input, pGlobal, pGlobal);
Py_Finalize();
Mit PyRun_String funktioniert soweit alles, aber Run_File wirft den Fehler. Anscheindend scheint das PyFileObject nicht richtig erzeugt zu werden.
Ich benutze Python3.3 und VS2012.
Re: Access Violation bei PyRun_File
Verfasst: Donnerstag 24. Oktober 2013, 16:14
von BlackJack
@init-0: Wo kommt denn `Py_file_input` her? Habe ja fast den Verdacht das ist gar nicht der Quelltext den Du *tatsächlich* verwendest.
Edit: Es fehlt ja auch jeglicher Test auf Fehler. Wenn also irgendeiner der Funktionsaufrufe fehlschlägt, machst Du trotzdem weiter als wäre nichts gewesen.
Re: Access Violation bei PyRun_File
Verfasst: Donnerstag 24. Oktober 2013, 16:26
von init-0
http://docs.python.org/2/c-api/veryhigh ... file_input
" The available start symbols are Py_eval_input, Py_file_input, and Py_single_input"
Ich versteh die Frage nicht so ganz.
Das einzige was ich weggeschnitten habe ist:
Was soll ich denn noch auf Fehler prüfen und wie? Ich bin nicht so gut in cpp.
Re: Access Violation bei PyRun_File
Verfasst: Donnerstag 24. Oktober 2013, 16:33
von BlackJack
@init-0: Schau in die Dokumentation zu den Python-API-Funktionen wie die jeweils Fehler melden. Die meisten die einen Zeiger zurückgeben tun das durch einen NULL-Pointer als Ergebnis. Und so ein Null-Pointer führt wenn man ihn weiterverwendet auch gerne mal zu einer Zugriffsverletzung wenn man selbst oder eine Funktion versucht den zu dereferenzieren. Vielleicht ist das ja schon das Problem.
Ansonsten könntest Du mal ein minimales aber komplettes Beispiel zeigen, so dass man das einfach selber nachvollziehen kann.
Re: Access Violation bei PyRun_File
Verfasst: Donnerstag 24. Oktober 2013, 17:11
von snafu
Vielleicht das letzte Argument bei `PyFile_FromFd()` (automatisches Schließen des Dateideskriptors) mal versuchsweise auf `0` setzen? Gibt die Funktion denn überhaupt etwas brauchbares zurück oder liefert sie `NULL`?
Und eigentlich sollte man ja `fileno()` benutzen, um an den FD zu kommen...
Re: Access Violation bei PyRun_File
Verfasst: Donnerstag 24. Oktober 2013, 20:19
von init-0
Das hier ist jetzt mein ganzer Code:
Code: Alles auswählen
void executePython()
{
Py_Initialize();
FILE* main = fopen("F:\\Projects\\PySE\\testFile.py", "r");
if (main == NULL){
printf("ERROR ON FILE");
return;
}
//PyFile_NewStdPrinter();
PyObject* PyFileObject;
PyFileObject = PyFile_FromFd(_fileno(main), NULL, "r", -1, NULL, NULL, NULL, 1);
//return;
//PyFileObject = PyFile_FromString("H:\\Projects\\PySE\\testFile.py", "r");
if (PyFileObject == NULL){
printf("ERROR IN PY");
return;
}
PyObject *pGlobal = PyDict_New();
PyDict_SetItemString(pGlobal, "__builtins__", PyEval_GetBuiltins());
//PyDict_SetItemString(pGlobal, "__file__", "__init__.py");
//PyDict_SetItemString(pGlobal, "__name__", "__main__");
PyRun_File(main, "test", 0, pGlobal, pGlobal);
PyErr_Print();
Py_Finalize();
}
Hab so jetzt rausgefunden, dass der Fehler wohl in PyFile_FromFd liegt, kann mir den aber nicht erklären, da ich ja alle Werte auf dem default habe und für closefd 1 und 0 ausprobiert habe. Wo kann der Fehler denn jetzt liegen?
Re: Access Violation bei PyRun_File
Verfasst: Donnerstag 24. Oktober 2013, 20:52
von BlackJack
@init-0: Ich würde ja empfehlen wirklich *alle* Rückgabewerte/Fehlerindikatoren zu prüfen und auch alle Referenzen ordentlich runterzählen und die Funktion nach dem Initialisieren nicht einfach ohne Finalisieren des Interpreters zu verlassen. Das ist mindestens ein Speicherleck, wenn nicht sogar eine Absturzgefahr beim erneuten Aufrufen der Funktion.
Und einen netten Absturz hast Du Dir auch durch den bedingungslosen Aufruf von `PyErr_Print()` eingebaut. Da warnt die Dokumentation ganz ausdrücklich vor.
Wozu brauchst Du `PyFile_FromFd()` überhaupt? Mit dem Ergebnis wird doch nirgends tatsächlich etwas gemacht‽
Ich habe mal den sinnvollen Teil als C-Programm mit durchgehenden Prüfungen und ordentlichem Aufräumen geschrieben:
Code: Alles auswählen
#include "Python.h"
int main(void)
{
char *filename = "test.py";
FILE *source_file;
PyObject *context = NULL, *run_result = NULL;
int result = 0;
source_file = fopen(filename, "rb");
if (source_file == NULL) {
printf("cannot open %s", filename);
return 1;
}
Py_Initialize();
context = PyDict_New();
if (context == NULL) {
result = 1;
goto error;
}
if (
PyDict_SetItemString(context, "__builtins__", PyEval_GetBuiltins())
== -1
) {
result = 1;
goto error;
}
run_result = PyRun_File(
source_file, filename, Py_file_input, context, context
);
if (run_result == NULL) {
result = 1;
goto error;
}
error:
if (result != 0) PyErr_Print();
Py_XDECREF(context);
Py_XDECREF(run_result);
Py_Finalize();
if (source_file) fclose(source_file);
return result;
}
Re: Access Violation bei PyRun_File
Verfasst: Donnerstag 24. Oktober 2013, 21:31
von init-0
Ich dachte der Parameter von PyRun_File müsste ein PyObject, also PyFile_FromFd sein (
http://stackoverflow.com/questions/1105 ... ded-python ). Ich hab jetzt mein Programm so angepasst wie du vorschlägst, das ändert aber immernoch nichts an der Fehlermeldung:
Code: Alles auswählen
void executePython()
{
int result = 0;
PyObject *run_result = NULL;
PyObject *pGlobal = PyDict_New();
Py_Initialize();
FILE* main = fopen("F:\\Projects\\PySE\\testFile.py", "rb");
if (main == NULL){
goto error;
}
if (PyDict_SetItemString(pGlobal, "__builtins__", PyEval_GetBuiltins())==-1){
goto error;
}
run_result = PyRun_File(main, "testFile.py", Py_file_input, pGlobal, pGlobal);
if (run_result == NULL) {
result = 1;
goto error;
}
Py_Finalize();
error:
if (result != 0) PyErr_Print();
Py_XDECREF(run_result);
Py_XDECREF(pGlobal);
Py_Finalize();
if (main) fclose(main);
return;
}
Re: Access Violation bei PyRun_File
Verfasst: Donnerstag 24. Oktober 2013, 22:09
von BlackJack
@init-0: Du hast das PyFileObjekt doch überhaupt gar nicht verwendet. An `PyRun_File()` hast Du doch den FILE*-Wert übergeben. Und das ist laut Dokumentation auch das was die Funktion dort erwartet.
Was jetzt definitiv falsch ist bei Dir ist das erzeugen eines Wörterbuch-Exemplars *bevor* die `Py_Initialize()` aufgerufen wird.
Und nicht in allen Fällen wo etwas auf Python-Seite falsch läuft setzt Du `result`, also wird auch nicht überall `PyErr_Print()` ausgeführt.
Bist Du denn sicher, dass der Fehler nicht ausserhalb liegt? Das ist ja immer noch kein minimales *lauffähiges* Beispiel. Und hat Visual Studio keinen Debugger mit dem Du das mal Zeile für Zeile durch„steppen” kannst?
Edit: Ich habe das `PyDict_New()` nach die Initialisierung verschoben, oben ein ``#include "Python.h"`` und unten
eingefügt.
Den Dateinamen habe ich zu "test.py" umgeändert und die Datei enthält ein simples ``print('Hallo Welt.')``. Das funktioniert bei mir problemlos.
Re: Access Violation bei PyRun_File
Verfasst: Donnerstag 24. Oktober 2013, 22:48
von init-0
Stimmt. Das mit dem PyFileObjekt war wohl irgendwie daneben. Ich hab PyInitialize jetzt davor geschrieben, aber es ändert nichts und wenn ich versuche in PyRun_File einzusteppen bekomme ich "python33.pdb not loaded". Der Fehler trifft definitiv beim PyRun_File auf
Code: Alles auswählen
void executePython()
{
int result = 0;
Py_Initialize();
PyObject *pGlobal = PyDict_New();
PyObject *run_result = NULL;
FILE* main = fopen("F:\\Projects\\PySE\\testFile.py", "rb");
if (main == NULL){
printf("EXCEPTION: opening file\n");
goto error;
}
if (PyDict_SetItemString(pGlobal, "__builtins__", PyEval_GetBuiltins())==-1){
result = 1;
goto error;
}
run_result = PyRun_File(main, "F:\\Projects\\PySE\\testFile.py", Py_file_input, pGlobal, pGlobal);
if (run_result == NULL) {
result = 1;
goto error;
}
Py_Finalize();
error:
if (result != 0) PyErr_Print();
Py_XDECREF(run_result);
Py_XDECREF(pGlobal);
Py_Finalize();
if (main) fclose(main);
return;
}
Wenn ich PyRun_File auskommentiere (und dann darunter result = 1) läuft alles ohne fehler ab, also muss der Fehler in PyRun_File auftreten. Ich habe sowas ähnliches schon mit
Code: Alles auswählen
PyRun_String("import ctypes; ctypes.windll.user32.MessageBoxA(0, 'A', 'A', 1)", Py_file_input, pGlobal, pGlobal);
ausprobiert und das geht Problemlos. Als workaround würde mir einfallen, erst alles aus der Datei zu lesen und dann mit PyRun_String auszuführen, aber irgendwie muss das ja auch mit PyRun_File klappen.