Access Violation bei PyRun_File

Python in C/C++ embedden, C-Module, ctypes, Cython, SWIG, SIP etc sind hier richtig.
Antworten
init-0
User
Beiträge: 38
Registriert: Samstag 22. Januar 2011, 18:46

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.
Zuletzt geändert von Anonymous am Donnerstag 24. Oktober 2013, 16:10, insgesamt 1-mal geändert.
Grund: Quelltext in C++-Code-Tags gesetzt.
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.
init-0
User
Beiträge: 38
Registriert: Samstag 22. Januar 2011, 18:46

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:

Code: Alles auswählen

if (main == NULL){
		return;
	}
Was soll ich denn noch auf Fehler prüfen und wie? Ich bin nicht so gut in cpp.
Zuletzt geändert von init-0 am Donnerstag 24. Oktober 2013, 20:02, insgesamt 1-mal geändert.
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.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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...
init-0
User
Beiträge: 38
Registriert: Samstag 22. Januar 2011, 18:46

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?
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;
}
init-0
User
Beiträge: 38
Registriert: Samstag 22. Januar 2011, 18:46

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:
Bild

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;
}
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

Code: Alles auswählen

int main(void)
{
    executePython();
    return 0;
}
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.
init-0
User
Beiträge: 38
Registriert: Samstag 22. Januar 2011, 18:46

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.
Antworten