# HG changeset patch # User Chris Cannam # Date 1547482784 0 # Node ID a6718f9fe942f691ba14f5cda122120e84cfead1 # Parent c4510e5f7a17560674d66978bd09070b9b2926a3 If a module appears to redefine one of our own types, refuse to load it. Also clear out the class dict for all refused modules now, so that we don't get stale names on the next scan due to not having cleared the module on unload diff -r c4510e5f7a17 -r a6718f9fe942 PyExtensionManager.h --- a/PyExtensionManager.h Mon Jan 14 16:16:43 2019 +0000 +++ b/PyExtensionManager.h Mon Jan 14 16:19:44 2019 +0000 @@ -1,3 +1,4 @@ +/* -*- c-basic-offset: 8 indent-tabs-mode: t -*- */ /* * Vampy : This plugin is a wrapper around the Vamp plugin API. @@ -64,9 +65,9 @@ void setPlugModuleNames(vector pyPlugs); void deleteModuleName(string plugKey); + static const char* m_exposedNames[]; + private: - static const char* m_exposedNames[]; - vector m_plugModuleNames; PyObject* m_pyGlobalNamespace; PyObject* m_pyVampyNamespace; diff -r c4510e5f7a17 -r a6718f9fe942 PyPlugScanner.cpp --- a/PyPlugScanner.cpp Mon Jan 14 16:16:43 2019 +0000 +++ b/PyPlugScanner.cpp Mon Jan 14 16:19:44 2019 +0000 @@ -1,3 +1,4 @@ +/* -*- c-basic-offset: 8 indent-tabs-mode: t -*- */ /* * Vampy : This plugin is a wrapper around the Vamp plugin API. @@ -11,6 +12,8 @@ #include "PyPlugScanner.h" +#include "PyExtensionManager.h" +#include "Debug.h" #include #include //#include "vamp-hostsdk/PluginHostAdapter.h" @@ -95,13 +98,12 @@ pluginKey=joinPath(m_path[i],script)+":"+classname; pyClass = getScriptClass(m_path[i],classname); if (pyClass == NULL) - cerr << "Warning: Syntax error in VamPy plugin: " + cerr << "Warning: Syntax error or other problem in scanning VamPy plugin: " << classname << ". Avoiding plugin." << endl; else { pyPlugs.push_back(pluginKey); m_pyClasses.push_back(pyClass); - } - //pyPlugs.push_back(pluginKey); + } } } } @@ -142,7 +144,6 @@ PyObject* PyPlugScanner::getScriptClass(string path, string classname) { - //Add plugin path to active Python Path string pyCmd = "import sys\nsys.path.append('" + path + "')\n"; PyRun_SimpleString(pyCmd.c_str()); @@ -169,17 +170,91 @@ //Get the PluginClass from the module (borrowed reference) PyObject *pyClass = PyDict_GetItemString(pyDict, classname.c_str()); - //Check if class is present and a callable method is implemented - if (pyClass && PyCallable_Check(pyClass)) { - - return pyClass; - } - else { + if (pyClass == Py_None) { + DSTREAM << "Vampy: class name " << classname + << " is None in module; assuming it was scrubbed " + << "following an earlier load failure" << endl; + return NULL; + } + + // Check if class is present and a callable method is implemented + if (!pyClass || !PyCallable_Check(pyClass)) { cerr << "ERROR: callable plugin class could not be found in source: " << classname << endl << "Hint: plugin source filename and plugin class name must be the same." << endl; PyErr_Print(); return NULL; } + + bool acceptable = true; + + // Check that the module doesn't have any name collisions with + // our own symbols + + int i = 0; + while (PyExtensionManager::m_exposedNames[i]) { + + const char* name = PyExtensionManager::m_exposedNames[i]; + i++; + + PyObject *item = PyDict_GetItemString(pyDict, name); + if (!item) continue; + + if (item == Py_None) { + DSTREAM << "Vampy: name " << name << " is None " + << "in module " << classname + << "; assuming it was cleared on unload" + << endl; + continue; + } + + PyTypeObject *metatype = Py_TYPE(item); + + if (!strcmp(name, "frame2RealTime")) { + if (metatype != &PyCFunction_Type) { + cerr << "ERROR: plugin " << classname + << " redefines Vampy function name \"" + << name << "\" (metatype is \"" + << metatype->tp_name << "\")" << endl; + acceptable = false; + break; + } else { + continue; + } + } + + if (metatype != &PyType_Type) { + cerr << "ERROR: plugin " << classname + << " uses Vampy reserved type name \"" << name + << "\" for non-type (metatype is \"" + << metatype->tp_name << "\")" << endl; + acceptable = false; + break; + } + + PyTypeObject *type = (PyTypeObject *)item; + if (type->tp_name == std::string("vampy.") + name) { + DSTREAM << "Vampy: acceptable Vampy type name " + << type->tp_name << " found in module" << endl; + } else { + cerr << "ERROR: plugin " << classname + << " redefines Vampy type \"" << name << "\""; + if (strcmp(type->tp_name, name)) { + cerr << " (as \"" << type->tp_name << "\")"; + } + cerr << endl; + acceptable = false; + break; + } + } + + if (acceptable) { + return pyClass; + } else { + PyObject *key = PyString_FromString(classname.c_str()); + PyDict_SetItem(pyDict, key, Py_None); + Py_DECREF(key); + return NULL; + } }