diff --git a/CMakeLists.txt b/CMakeLists.txt index 8cbc9d3513196e99810ce6439a93cb45e518e2dd..d668d9e12e69ca2a4809b07e0e97eb0aef9daa4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,6 +53,7 @@ ADD_DEFINITIONS(-DBOOST_FILESYSTEM_VERSION=2) ADD_SUBDIRECTORY(src) ADD_SUBDIRECTORY(include) ADD_SUBDIRECTORY(doc) +ADD_SUBDIRECTORY(unitTesting) SETUP_PROJECT_FINALIZE() diff --git a/src/entity-py.cc b/src/entity-py.cc index 9e25e707a45eca3d0d366edb582ff6f70a8c176c..3901eb0a74e2d7e621a51a0e631b003ada817865 100644 --- a/src/entity-py.cc +++ b/src/entity-py.cc @@ -26,6 +26,12 @@ #include "convert-dg-to-py.hh" #include "exception.hh" +// Ignore "dereferencing type-punned pointer will break strict-aliasing rules" +// warnings on gcc caused by Py_RETURN_TRUE and Py_RETURN_FALSE. +#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)) +# pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif + using dynamicgraph::Entity; using dynamicgraph::SignalBase; using dynamicgraph::command::Command; diff --git a/src/interpreter.cc b/src/interpreter.cc index ac4fd2cd99681775c9a5594929e4b2f9de4c0a9d..ba8930ae71d553f0246f49d33cbcfdbdbf552870 100644 --- a/src/interpreter.cc +++ b/src/interpreter.cc @@ -61,6 +61,8 @@ bool HandleErr(std::string & err, PyErr_Fetch(&ptype, &pvalue, &ptraceback); if (ptraceback == NULL) { ptraceback = Py_None; + // increase the Py_None count, to avoid a crash at the tuple destruction + Py_INCREF(ptraceback); } PyObject* args = PyTuple_New(3); PyTuple_SET_ITEM(args, 0, ptype); @@ -73,12 +75,15 @@ bool HandleErr(std::string & err, for (Py_ssize_t i=0; i<size; ++i) stringRes += std::string (PyString_AsString(PyList_GET_ITEM(pyerr, i))); + Py_DecRef(pyerr); + pyerr = PyString_FromString(stringRes.c_str()); err = PyString_AsString(pyerr); dgDEBUG(15) << "err: " << err << std::endl; + Py_DecRef(pyerr); - // Here if there is a syntax error and + // Here if there is a syntax error and // and the interpreter input is set to Py_eval_input, // it is maybe a statement instead of an expression. // Therefore we indicate to re-evaluate the command. @@ -91,7 +96,9 @@ bool HandleErr(std::string & err, else lres=true; - PyErr_Clear(); + Py_CLEAR(args); + + PyErr_Clear(); } else { dgDEBUG(15) << "no object generated but no error occured." << std::endl; } @@ -106,6 +113,7 @@ bool HandleErr(std::string & err, { dgDEBUG(15) << std::endl; } else { dgDEBUG(15) << "No exception." << std::endl; } dgDEBUGOUT(15); + Py_DecRef(stdout_obj); return lres; } @@ -195,19 +203,22 @@ void Interpreter::python( const std::string& command, std::string& res, std::cout << "Output:" << out << std::endl; if (err.size()!=0) std::cout << "Error:" << err << std::endl; - result = PyObject_Repr(result); + PyObject* result2 = PyObject_Repr(result); // If python cannot build a string representation of result // then results is equal to NULL. This will trigger a SEGV - if (result!=NULL) + if (result2!=NULL) { dgDEBUG(15) << "For command :" << command << std::endl; - res = PyString_AsString(result); + res = PyString_AsString(result2); dgDEBUG(15) << "Result is: " << res <<std::endl; dgDEBUG(15) << "Out is: " << out <<std::endl; dgDEBUG(15) << "Err is :" << err << std::endl; } - else + else { dgDEBUG(15) << "Result is empty" << std::endl; } + Py_DecRef(stdout_obj); + Py_DecRef(result2); + Py_DecRef(result); return; } diff --git a/unitTesting/CMakeLists.txt b/unitTesting/CMakeLists.txt index 34c5be5c95f3f070b50c5ea08f6b9c6d34b17b67..eca30b2584efd2cc5d643ae5db42645ee0d47b44 100644 --- a/unitTesting/CMakeLists.txt +++ b/unitTesting/CMakeLists.txt @@ -2,23 +2,34 @@ # Copyright # -SET(EXECUTABLE_NAME test${PROJECT_NAME}) +INCLUDE(CTest) + +set(Python_ADDITIONAL_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0) +INCLUDE(../cmake/python.cmake) +FINDPYTHON() +INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH}) + +INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) +LINK_DIRECTORIES(${Boost_LIBRARY_DIRS} ${PYTHON_LIBRARY_DIRS}) + ADD_DEFINITIONS(-DDEBUG=2) # provide path to library libdynamic-graph.so LINK_DIRECTORIES(${DYNAMIC_GRAPH_LIBRARY_DIRS}) -ADD_EXECUTABLE(${EXECUTABLE_NAME} - main.cc - dynamic-graph-python-test.cc) - INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) - LINK_DIRECTORIES(${${PROJECT_NAME}_BINARY_DIR}/src) -TARGET_LINK_LIBRARIES(${EXECUTABLE_NAME} - dynamic-graph-python) # Add dynamic-graph compilation flags and link to library libdynamic-graph.so ADD_DEFINITIONS(${DYNAMIC_GRAPH_CFLAGS}) -TARGET_LINK_LIBRARIES(${EXECUTABLE_NAME} ${DYNAMIC_GRAPH_LIBRARIES}) + + +SET(EXECUTABLE_NAME interpreter-test) + +ADD_EXECUTABLE(${EXECUTABLE_NAME} interpreter-test.cc) +TARGET_LINK_LIBRARIES(${EXECUTABLE_NAME} dynamic-graph-python) +TARGET_LINK_LIBRARIES(${EXECUTABLE_NAME} ${DYNAMIC_GRAPH_LIBRARIES} -lpthread -ldl -lutil) + +ADD_TEST(${EXECUTABLE_NAME} ${EXECUTABLE_NAME}) + diff --git a/unitTesting/interpreter-test.cc b/unitTesting/interpreter-test.cc new file mode 100644 index 0000000000000000000000000000000000000000..268ba304eda425e32d68a94dfa3ff8216852fbb8 --- /dev/null +++ b/unitTesting/interpreter-test.cc @@ -0,0 +1,33 @@ +// The purpose of this unit test is to evaluate the memory consumption +// when call the interpreter. +#include "dynamic-graph/python/interpreter.hh" + +int main(int argc, char ** argv) +{ + int numTest = 1; + if (argc > 1) + numTest = atoi(argv[1]); + + dynamicgraph::python::Interpreter interp; + std::string command; + + for (int i=0; i<numTest; ++i) + { + //correct input + command = "print \"Hello world\""; + interp.python(command); + + //incorrect input + command = "print Hello"; + interp.python(command); + + std::string result; + std::string out; + std::string err; + //correct input + interp.python("print \"I am the interpreter\"", result, out, err); + //incorrect input + interp.python("print I am the interpreter", result, out, err); + } + return 0; +}