Mercurial > hg > vampy
comparison PyPlugScanner.cpp @ 92:a6718f9fe942
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
author | Chris Cannam |
---|---|
date | Mon, 14 Jan 2019 16:19:44 +0000 |
parents | 0120dac53a69 |
children | 2f2292b029a4 |
comparison
equal
deleted
inserted
replaced
91:c4510e5f7a17 | 92:a6718f9fe942 |
---|---|
1 /* -*- c-basic-offset: 8 indent-tabs-mode: t -*- */ | |
1 /* | 2 /* |
2 | 3 |
3 * Vampy : This plugin is a wrapper around the Vamp plugin API. | 4 * Vampy : This plugin is a wrapper around the Vamp plugin API. |
4 * It allows for writing Vamp plugins in Python. | 5 * It allows for writing Vamp plugins in Python. |
5 | 6 |
9 | 10 |
10 */ | 11 */ |
11 | 12 |
12 | 13 |
13 #include "PyPlugScanner.h" | 14 #include "PyPlugScanner.h" |
15 #include "PyExtensionManager.h" | |
16 #include "Debug.h" | |
14 #include <algorithm> | 17 #include <algorithm> |
15 #include <cstdlib> | 18 #include <cstdlib> |
16 //#include "vamp-hostsdk/PluginHostAdapter.h" | 19 //#include "vamp-hostsdk/PluginHostAdapter.h" |
17 | 20 |
18 #ifdef _WIN32 | 21 #ifdef _WIN32 |
93 if (!script.empty()) { | 96 if (!script.empty()) { |
94 string classname=script.substr(0,script.rfind('.')); | 97 string classname=script.substr(0,script.rfind('.')); |
95 pluginKey=joinPath(m_path[i],script)+":"+classname; | 98 pluginKey=joinPath(m_path[i],script)+":"+classname; |
96 pyClass = getScriptClass(m_path[i],classname); | 99 pyClass = getScriptClass(m_path[i],classname); |
97 if (pyClass == NULL) | 100 if (pyClass == NULL) |
98 cerr << "Warning: Syntax error in VamPy plugin: " | 101 cerr << "Warning: Syntax error or other problem in scanning VamPy plugin: " |
99 << classname << ". Avoiding plugin." << endl; | 102 << classname << ". Avoiding plugin." << endl; |
100 else { | 103 else { |
101 pyPlugs.push_back(pluginKey); | 104 pyPlugs.push_back(pluginKey); |
102 m_pyClasses.push_back(pyClass); | 105 m_pyClasses.push_back(pyClass); |
103 } | 106 } |
104 //pyPlugs.push_back(pluginKey); | |
105 } | 107 } |
106 } | 108 } |
107 } | 109 } |
108 | 110 |
109 return pyPlugs; | 111 return pyPlugs; |
140 //Validate | 142 //Validate |
141 //This should not be called more than once! | 143 //This should not be called more than once! |
142 PyObject* | 144 PyObject* |
143 PyPlugScanner::getScriptClass(string path, string classname) | 145 PyPlugScanner::getScriptClass(string path, string classname) |
144 { | 146 { |
145 | |
146 //Add plugin path to active Python Path | 147 //Add plugin path to active Python Path |
147 string pyCmd = "import sys\nsys.path.append('" + path + "')\n"; | 148 string pyCmd = "import sys\nsys.path.append('" + path + "')\n"; |
148 PyRun_SimpleString(pyCmd.c_str()); | 149 PyRun_SimpleString(pyCmd.c_str()); |
149 | 150 |
150 //Assign an object to the source code | 151 //Assign an object to the source code |
167 Py_DECREF(pyModule); | 168 Py_DECREF(pyModule); |
168 | 169 |
169 //Get the PluginClass from the module (borrowed reference) | 170 //Get the PluginClass from the module (borrowed reference) |
170 PyObject *pyClass = PyDict_GetItemString(pyDict, classname.c_str()); | 171 PyObject *pyClass = PyDict_GetItemString(pyDict, classname.c_str()); |
171 | 172 |
172 //Check if class is present and a callable method is implemented | 173 if (pyClass == Py_None) { |
173 if (pyClass && PyCallable_Check(pyClass)) { | 174 DSTREAM << "Vampy: class name " << classname |
174 | 175 << " is None in module; assuming it was scrubbed " |
175 return pyClass; | 176 << "following an earlier load failure" << endl; |
176 } | 177 return NULL; |
177 else { | 178 } |
179 | |
180 // Check if class is present and a callable method is implemented | |
181 if (!pyClass || !PyCallable_Check(pyClass)) { | |
178 cerr << "ERROR: callable plugin class could not be found in source: " << classname << endl | 182 cerr << "ERROR: callable plugin class could not be found in source: " << classname << endl |
179 << "Hint: plugin source filename and plugin class name must be the same." << endl; | 183 << "Hint: plugin source filename and plugin class name must be the same." << endl; |
180 PyErr_Print(); | 184 PyErr_Print(); |
185 return NULL; | |
186 } | |
187 | |
188 bool acceptable = true; | |
189 | |
190 // Check that the module doesn't have any name collisions with | |
191 // our own symbols | |
192 | |
193 int i = 0; | |
194 while (PyExtensionManager::m_exposedNames[i]) { | |
195 | |
196 const char* name = PyExtensionManager::m_exposedNames[i]; | |
197 i++; | |
198 | |
199 PyObject *item = PyDict_GetItemString(pyDict, name); | |
200 if (!item) continue; | |
201 | |
202 if (item == Py_None) { | |
203 DSTREAM << "Vampy: name " << name << " is None " | |
204 << "in module " << classname | |
205 << "; assuming it was cleared on unload" | |
206 << endl; | |
207 continue; | |
208 } | |
209 | |
210 PyTypeObject *metatype = Py_TYPE(item); | |
211 | |
212 if (!strcmp(name, "frame2RealTime")) { | |
213 if (metatype != &PyCFunction_Type) { | |
214 cerr << "ERROR: plugin " << classname | |
215 << " redefines Vampy function name \"" | |
216 << name << "\" (metatype is \"" | |
217 << metatype->tp_name << "\")" << endl; | |
218 acceptable = false; | |
219 break; | |
220 } else { | |
221 continue; | |
222 } | |
223 } | |
224 | |
225 if (metatype != &PyType_Type) { | |
226 cerr << "ERROR: plugin " << classname | |
227 << " uses Vampy reserved type name \"" << name | |
228 << "\" for non-type (metatype is \"" | |
229 << metatype->tp_name << "\")" << endl; | |
230 acceptable = false; | |
231 break; | |
232 } | |
233 | |
234 PyTypeObject *type = (PyTypeObject *)item; | |
235 if (type->tp_name == std::string("vampy.") + name) { | |
236 DSTREAM << "Vampy: acceptable Vampy type name " | |
237 << type->tp_name << " found in module" << endl; | |
238 } else { | |
239 cerr << "ERROR: plugin " << classname | |
240 << " redefines Vampy type \"" << name << "\""; | |
241 if (strcmp(type->tp_name, name)) { | |
242 cerr << " (as \"" << type->tp_name << "\")"; | |
243 } | |
244 cerr << endl; | |
245 acceptable = false; | |
246 break; | |
247 } | |
248 } | |
249 | |
250 if (acceptable) { | |
251 return pyClass; | |
252 } else { | |
253 PyObject *key = PyString_FromString(classname.c_str()); | |
254 PyDict_SetItem(pyDict, key, Py_None); | |
255 Py_DECREF(key); | |
181 return NULL; | 256 return NULL; |
182 } | 257 } |
183 } | 258 } |
184 | 259 |
185 | 260 |