C6011 in C++ and Python project - python

I am in my third CS class online and I have done ok until now but I am really struggling with this. My code runs fine through the menu and input validation just fine but then as soon as I call a function from the python file I get the dereferencing null pointer message as follows " EXCEPTION UNHANDLED: Unhandled exception at 0x1DD09F27 (python36.dll) in moduleSixCppAndPython.exe: 0xC0000005: Access violation reading location 0x00000004. occurred".
I'm going to try to include my c++ code so forgive me if i mess this it up.. this is my first time using stackoverflow. the sections underlined in my IDE are the line as follows:
pFunc = PyDict_GetItemString(pDict, procname); // this one get like a red X next to it
...
Py_DECREF(pValue); // this line is underlined
all issues are coming from the "int callIntFunc(string proc, int param)" funtion
main is not really finished yet so i'm not super concerned with that unless that's where my problem is coming from...
any guidance at all would be very greatly appreciated!
#include <Python.h>
#include <iostream>
#include <Windows.h>
#include <cmath>
#include <string>
#include <conio.h>
using namespace std;
bool CONTINUE_RUN = true;
int displayMenu() {
int userInput = 0;
while (true) {
cout << "1: Display a Multiplication Table" << endl;
cout << "2: Double a Value" << endl;
cout << "3: Exit" << endl;
cout << "Enter your selection as a number 1, 2, or 3." << endl;
while (!(cin >> userInput)) {
system("cls");
cout << "ERROR: Please enter 1, 2, or 3" << endl;
cout << "1: Display a Multiplication Table" << endl;
cout << "2: Double a Value" << endl;
cout << "3: Exit" << endl;
cout << "Enter your selection as a number 1, 2, or 3." << endl;
cin.clear();
cin.ignore(123, '\n');
}
if (userInput == 1) {
break;
}
if (userInput == 2) {
break;
}
if (userInput == 3) {
CONTINUE_RUN = false;
break;
}
else {
system("cls");
cout << "ERROR: Please enter 1, 2, or 3" << endl;
continue;
}
}
return userInput;
}
int userData() {
int pickNum;
system("cls");
cout << "Please enter an integer: " << endl;
while (!(cin >> pickNum)) {
system("cls");
cout << "ERROR: Please enter an INTEGER:";
cin.clear();
cin.ignore(123, '\n');
}
return pickNum;
}
int callIntFunc(string proc, int param)
{
char* procname = new char[proc.length() + 1];
std::strcpy(procname, proc.c_str());
PyObject* pName, * pModule, * pDict, * pFunc, * pValue = nullptr, * presult = nullptr;
// Initialize the Python Interpreter
Py_Initialize();
// Build the name object
pName = PyUnicode_FromString((char*)"PythonCode");
// Load the module object
pModule = PyImport_Import(pName);
// pDict is a borrowed reference
pDict = PyModule_GetDict(pModule);
// pFunc is also a borrowed reference
pFunc = PyDict_GetItemString(pDict, procname);
if (PyCallable_Check(pFunc))
{
pValue = Py_BuildValue("(i)", param);
PyErr_Print();
presult = PyObject_CallObject(pFunc, pValue);
PyErr_Print();
}
else
{
PyErr_Print();
}
//printf("Result is %d\n", _PyLong_AsInt(presult));
Py_DECREF(pValue);
// Clean up
Py_DECREF(pModule);
Py_DECREF(pName);
// Finish the Python Interpreter
Py_Finalize();
// clean
delete[] procname;
return _PyLong_AsInt(presult);
}
int main(){
while (CONTINUE_RUN == true) {
int userNumber = 0;
int menuValue = displayMenu();
if (menuValue == 1) {
userNumber = userData();
system("cls");
int token = callIntFunc("MultiplicationTable", userNumber);
cout << "Press any key to continue" << endl;
_getch();
}
if (menuValue == 2) {
userNumber = userData();
system("cls");
cout << callIntFunc("DoubleValue", userNumber);
cout << "Press any key to continue" << endl;
_getch();
}
}
cout << "GOODBYE" << endl;
}

OK so a big THANK YOU to #PaulMcKenzie in the comments for pointing me in the right direction...
Turns out the issue was not in my .cpp file but in fact in the .py file that it was reading.
I had used the Python syntax :
print(namedVariable + "someString" + (evaluatedCalculation))
Now while this was technically correct for some instances it was creating unpredictable results when passed from my .py file back to my .cpp file. The error was flagging in my .cpp file so the real error that was made was that. I had tunnel vision in trying to find the error solely in the .cpp file and not anywhere else. PLEASE forgive a rookie of his rookie mistake here !
To fix this, I altered the syntax in my .py file to :
print(namedVariable, "someString", (evaluatedCalculation))
The true error here was not just in the logic I applied in writing my Python code... but in the logic I applied in finding the source of my error.
I learned much more in finding the flaw in my thinking than I did in finding the flaw in this code. But hey.. live and learn right?
Anyway,
happy coding !
Love and Respect !

Related

Embedded Python in C++ cannot import pandas twice

I'm embedding Python 3.8.2 in C++ code (using Visual Studio 2019). Python has pandasn installed (through pip).
I manage to import pandas from a C++ program, however, when I try to import it a second time, it crashs.
#include <Python.h>
#include <iostream>
int main( int argc, char* argv[] )
{
{
Py_SetPythonHome( L"C:\\Python38" );
// Initialize the Python Interpreter
Py_Initialize();
std::cout << "Importing pandas..." << std::endl;
if ( PyRun_SimpleString( "import pandas" ) == 0 )
std::cout << "SUCCESS" << std::endl;
else
std::cout << "FAIL" << std::endl;
Py_Finalize();
}
{
Py_SetPythonHome( L"C:\\Python38" );
// Initialize the Python Interpreter
Py_Initialize();
std::cout << "Importing pandas..." << std::endl;
if ( PyRun_SimpleString( "import pandas" ) == 0 )
std::cout << "SUCCESS" << std::endl;
else
std::cout << "FAIL" << std::endl;
Py_Finalize();
}
return 0;
}
This crashs with an exception:
_multiarray_umath.cp38-win_amd64.pyd!00007ffbd5b8ca69() Inconnu
_multiarray_umath.cp38-win_amd64.pyd!00007ffbd5b8ffd6() Inconnu
_multiarray_umath.cp38-win_amd64.pyd!00007ffbd5b9d34d() Inconnu
python38.dll!00007ffbd22f6131() Inconnu
python38.dll!00007ffbd22f6092() Inconnu
Output is:
Importing pandas...
SUCCESS
Importing pandas...
Traceback (most recent call last):
File "<string>", line 1, in <module>
Is there any init/uninit step I missed that could make this fail while it shaould work?
Note that I cannot Debug as pandas cannot be loaded in Debug build.
Upon request from OP, I made a small demo for how we wrap user Python scripts in our application to prevent that global variables of user scripts become unintended persistent:
#include <iostream>
#include <string>
#include <Python.h>
const char *PyScript = R"(try:
print(a)
except:
print("a not (yet) defined")
a = 123
print(a)
)";
std::string wrapPyScript(const char* script)
{
std::string source = std::string("def __mainPythonFunction():\n") + script;
{ const char *const indent = "\n ";
for (size_t i = source.size(); i--;) {
size_t n = 1;
switch (source[i]) {
case '\n': if (i && source[i - 1] == '\r') n = 2, --i;
case '\r': source.replace(i, n, indent); break;
}
}
}
source += "\n"
"pass\n"
"\n"
"try:\n"
" __mainPythonFunction()\n"
"except:\n"
" rf.form.appContext.notifyAbort()\n"
" raise\n";
return source;
}
#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__
int main()
{
DEBUG(Py_Initialize());
std::cout << "\nWithout wrapper:\n\n";
DEBUG(for (int i = 0; i < 2; ++i) {
DEBUG(PyRun_SimpleString(PyScript));
});
std::cout << "\nWith wrapper:\n\n";
DEBUG(for (int i = 0; i < 2; ++i) {
DEBUG(PyRun_SimpleString(wrapPyScript(PyScript).c_str()));
});
std::cout << '\n';
DEBUG(Py_Finalize());
}
Output:
Py_Initialize();
Without wrapper:
for (int i = 0; i < 2; ++i) { DEBUG(PyRun_SimpleString(PyScript)); };
PyRun_SimpleString(PyScript);
a not (yet) defined
123
PyRun_SimpleString(PyScript);
123
123
With wrapper:
for (int i = 0; i < 2; ++i) { DEBUG(PyRun_SimpleString(wrapPyScript(PyScript).c_str())); };
PyRun_SimpleString(wrapPyScript(PyScript).c_str());
a not (yet) defined
123
PyRun_SimpleString(wrapPyScript(PyScript).c_str());
a not (yet) defined
123
Py_Finalize();
However, I'm not quite sure whether this is enough to fix OPs issue with the imported Pandas library.
In our application (where we used the above trick), we import selected libraries once after the Py_Initialize().
(I remember roughly that this was our last desperate resort to fix similar issues like OP observed.)

Embedding python in C++ and extracting c++ types

I'm trying to embed simple python instructions in my c++ program.
I'm unable to extract c++ types from the python object types...
Would appreciate any help!
Sample Program:
#include <iostream>
#include <Python.h>
using namespace std;
int main()
{
Py_Initialize();
auto pModule = PyImport_ImportModule("math");
auto pFunc = PyObject_GetAttrString(pModule, "sin");
auto pIn = Py_BuildValue("(f)", 2.);
auto pRes = PyObject_CallObject(pFunc, pIn);
auto cRes = ???;
cout << cRes << endl;
Py_Finalize();
}
The program should simply print the result for sin(2).
You'll want to know what type(s) to expect from the function call, including errors... If the function raised an exception, the PyObject_CallObject should return NULL, so check for that first:
if (!pRes) {
PyErr_Print();
// don't do anything else with pRes
}
Otherwise, you can check for and interpret each type you might expect from the Python function call:
if (pRes == Py_None) {
cout << "result is None" << endl;
} else if (PyFloat_Check(pRes)) {
auto cRes = PyFloat_AsDouble(pRes);
cout << cRes << endl;
} else if (<other checks>) {
// Handle other types
} else {
cout << "Unexpected return type" << endl;
}
In the case of your math.sin() call, you can probably safely assume either an exception or a PyFloat return.

SWIG + CMAKE: init function missing

I was provided with a CMAKE-File for a c++ Code and want to wrap its function into python. Whenever I try to import the function it's giving me an Import Error:
dynamic module does not define init function (init_main)
This is the c++ code:
#include <iostream>
#include <string>
#include <boost/bind.hpp>
#include <Memory/Interface.hpp>
#include <Memory/Subscription.hpp>
using namespace memory::interface;
using namespace memory;
MemoryPtr mMem;
Subscription *s;
std::string write_document;
void subscriber_callback(const Event &event) {
std::cout << "Received an event:" << std::endl;
switch (event.getType()) {
case Event::INSERT:
std::cout << "Insert event with document ID = " << event.getID() << std::endl;
break;
case Event::REMOVE:
std::cout << "Remove event with document ID = " << event.getID() << std::endl;
break;
case Event::QUERY:
std::cout << "Query event with document ID = " << event.getID() << std::endl;
break;
case Event::REPLACE:
std::cout << "Replace event with document ID = " << event.getID() << std::endl;
break;
case Event::ALL:
std::cout << "Generic event with document ID = " << event.getID() << std::endl;
break;
default: std::cout << "Unknown event type." << std::endl;
}
std::cout << "Contained document is: " << event.getDocument() << std::endl;
}
extern "C" int main(int argc, char *argv[]) {
// validate app arguments
if(argc < 3) {
std::cerr << "Usage : " << argv[0] << " <xcf:ShortTerm> <XPATH-trigger>" << std::endl;
return 1;
}
try {
// instantiate the memory interface
mMem = MemoryInterface::getInstance(argv[1]);
std::cout << "Memory interface initialized" << std::endl;
// create the trigger
std::string xpath(argv[2]);
// create a subscriber to a specific xpath event
s = new Subscription(
Condition(Event::INSERT, xpath),
TriggeredAction(boost::bind(&subscriber_callback, _1))
);
mMem->subscribe (*s);
std::cout << "Memory interface subscriber initialized" << std::endl;
// insert command/text to memory
write_document = "<command><stop /></command>";
mMem->insert(write_document);
std::cout << "Written to Memory interface" << std::endl;
// wait for key press
std::string end;
std::cin >> end;
}
catch (const MemoryInterfaceException& e) {
std::cerr << "MemoryInterfaceException: " << e.what() << std::endl;
return 1;
}
catch(std::exception &e) {
std::cerr << std::endl << "Could not initialize memory::interface. Reason:"
<< std::endl << e.what() << std::endl;
return 1;
}
return 0;
}
This is the CMAKE File to which I added the last SWIG part:
cmake_minimum_required(VERSION 3.0.2)
project(xcf_minimal_readwrite)
find_package(PkgConfig)
IF(PKG_CONFIG_FOUND)
message(STATUS "found pkgconfig")
SET(MODULE "Memory")
IF(Memory_FIND_REQUIRED)
SET(Memory_REQUIRED "REQUIRED")
ENDIF()
PKG_CHECK_MODULES(Memory ${Memory_REQUIRED} ${MODULE})
FIND_LIBRARY(Memory_LIBRARY
NAMES ${Memory_LIBRARIES}
HINTS ${Memory_LIBRARY_DIRS}
)
SET(Memory_LIBRARIES ${Memory_LIBRARY})
SET(MODULE "xmltio")
IF(xmltio_FIND_REQUIRED)
SET(xmltio_REQUIRED "REQUIRED")
ENDIF()
PKG_CHECK_MODULES(xmltio ${xmltio_REQUIRED} ${MODULE})
FIND_LIBRARY(xmltio_LIBRARY
NAMES ${xmltio_LIBRARIES}
HINTS ${xmltio_LIBRARY_DIRS}
)
SET(xmltio_LIBRARIES ${xmltio_LIBRARY})
ENDIF()
IF(Memory_FOUND)
message(STATUS "found Memory")
include_directories(${Memory_INCLUDE_DIRS} ${xmltio_INCLUDE_DIRS})
add_executable(${PROJECT_NAME} main.cc)
target_link_libraries(${PROJECT_NAME} ${Memory_LIBRARIES} ${xmltio_LIBRARIES})
install(TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION bin)
ENDIF()
# This is the part for Python SWIG:
FIND_PACKAGE(SWIG REQUIRED)
INCLUDE(${SWIG_USE_FILE})
FIND_PACKAGE(PythonLibs)
INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH})
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
SET(CMAKE_SWIG_FLAGS "")
SET_SOURCE_FILES_PROPERTIES(main.i PROPERTIES CPLUSPLUS ON)
SET_SOURCE_FILES_PROPERTIES(main.i PROPERTIES SWIG_FLAGS "-includeall")
SWIG_ADD_MODULE(main python main.i main.cc)
SWIG_LINK_LIBRARIES(main ${Memory_LIBRARIES} ${xmltio_LIBRARIES} ${PYTHON_LIBRARIES})
And this is how my main.i looks like:
/* File : main.i */
%module main
%{
/* Put headers and other declarations here */
extern int main(int argc, char *argv[]);
%}
extern int main(int argc, char *argv[]);
Any clue what went wrong here?
Is "main" maybe a bad name for this?
The swig invocation generates a source file that defines the init_main function. This file is either not compiled, or its object file is not linked into the shared object that constitutes your python extension.
Yes, main is a bad name, but here you are stuck at an earlier stage than where this might become a problem.

Refreshing a import in C embedded python

I have a C code which has embedded python in it using "Python.h" It works fine without any errors - But it doesn't completely do what I want it to.
What it does : After the C code starts running, it ignores all changes which I make to the python file until I restart the C code.
What I want : While the C code is running, if i make changes to the python file, it should start running the new code.
I tried using the function PyImport_ReloadModule in everytime before calling the function, but it does not work. Am I doing something wrong ?
My current code :
#include "Strategy.h"
#undef _DEBUG /* Link with python24.lib and not python24_d.lib */
#include <Python.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
PyObject *pName, *pModule, *pDict, *pFunc;
PyObject *pArgs, *pValue;
void import_py() {
pName = PyString_FromString("main");
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule == NULL) {
cout << "ERR : Unable to load main.py\n";
return;
} else {
cout << "OK : Loaded main.py\n";
}
if ( PyObject_HasAttrString(pModule, "main") ) {
cout << "OK : main.py has function main\n";
} else {
cout << "ERR : main.py has no function main\n";
return;
}
pFunc = PyObject_GetAttrString(pModule, "main");
if ( pFunc == NULL ) {
cout << "OK : main.py's function main gave NULL when trying to take it\n";
return;
}
}
void remove_py() {
Py_XDECREF(pArgs);
Py_XDECREF(pModule);
Py_XDECREF(pFunc);
Py_Finalize();
}
void Construct() {
Py_Initialize();
import_py();
}
void Destruct() {
if ( pModule || pFunc ) {
remove_py();
}
}
void Loop () {
if ( ! ( pModule && pFunc ) ) {
cout << "Looped. But python values are null\n";
return;
}
cout << "Loop : ";
pArgs = PyTuple_New(2); // Create a tuple to send to python - sends 1,2
PyTuple_SetItem(pArgs, 0, PyInt_FromLong(1));
PyTuple_SetItem(pArgs, 1, PyInt_FromLong(2));
pValue = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
double t = 0; // Get the 2 return values
t = PyFloat_AsDouble(PyTuple_GetItem(pValue, 0));
cout << t << ", ";
t = PyFloat_AsDouble(PyTuple_GetItem(pValue, 1));
cout << t;
cout << "\n";
}
void main() {
Construct();
while(1) { // Using an infinite loop for now - to test
pModule = PyImport_ReloadModule(pModule);
Loop();
}
Destruct();
}
I found the issue.
Even after getting the new module with pModule = PyImport_ReloadModule(pModule) the p
variable pFunc doesn't get automatically updated. So, the variable pFunc is still referencing the old module !
hence, every variable needs to be got again. Like so :
void main() {
Construct();
while(1) { // Using an infinite loop for now - to test
pModule = PyImport_ReloadModule(pModule);
pFunc = PyObject_GetAttrString(pModule, "main");
Loop();
}
Destruct();
}
One thing I am not sure about here is whether DECREF should be made to the pFunc which is referencing the old pModule.

C++ program crashing on Python script call

I am attempting to send a command that runs a specific python script: however, whenever the program reaches the execution line, this occurs:
Unhandled exception at 0x69bd1f16 in GameServer.exe: 0xC0000005: Access violation reading location 0x46f520ca.
The program stops resonding and crashes. Here is the method in question:
void ScriptManager::runScript(std::string scriptName, std::string args[])
{
std::string py = "python " + scriptName;
std::cout << py << std::endl;
for(int i = 0; i < args->length(); i++)
{
py += " " + args[i];
std::cout << py << std::endl;
}
std::cout << py << std::endl;
std::system(py.c_str());
}
This calls the above function:
void DBFactory::dbRegisterUser(std::string username, std::string password)
{
ScriptManager script;
std::string data[] = {username, password};
script.runScript("Python.py", data);
}
The script does not run, as far as I know. I can also post the script if it would help.
This is the problem:
for (int i = 0; i < args->length(); i++)
{
py += " " + args[i];
std::cout << py << std::endl;
}
args->length() is equivalent to args[0].length(); i.e. you're taking the length of the first string in the array and using that as an index. After two iterations pass, you're going to access past the end of the array. The best solutions are(all examples are UNTESTED):
Use an std::array(C++11 only):
void DBFactory::dbRegisterUser(std::string username, std::string password)
{
ScriptManager script;
script.runScript("Python.py", {username, password});
}
void ScriptManager::runScript(std::string scriptName, std::array<std::string, 2> args)
{
std::string py = "python " + scriptName;
std::cout << py << std::endl;
for (std::string s : args)
{
py += " " + s;
std::cout << py << std::endl;
}
std::cout << py << std::endl;
std::system(py.c_str());
}
Use an std::vector(the example uses C++03):
void DBFactory::dbRegisterUser(std::string username, std::string password)
{
ScriptManager script;
int tmp[2] = {username, password};
script.runScript("Python.py", std::vector<std::string>(&tmp[0], &tmp[0]+2));
}
void ScriptManager::runScript(std::string scriptName, std::vector<std::string> args)
{
std::string py = "python " + scriptName;
std::cout << py << std::endl;
for(std::vector<std::string>::iterator it = args.begin(); it != args.end(); it++)
{
py += " " + *it;
std::cout << py << std::endl;
}
std::cout << py << std::endl;
std::system(py.c_str());
}
Pass the array size as a parameter:
void DBFactory::dbRegisterUser(std::string username, std::string password)
{
ScriptManager script;
script.runScript("Python.py", {username, password}, 2);
}
void ScriptManager::runScript(std::string scriptName, std::string args[], int size)
{
std::string py = "python " + scriptName;
std::cout << py << std::endl;
for(int i=0; i<size; i++)
{
py += " " + args[i];
std::cout << py << std::endl;
}
std::cout << py << std::endl;
std::system(py.c_str());
}
I personally prefer example 1 and would avoid example 3 like the plague. Example 2 works well but probably isn't as fast as example 1.

Categories