验证 Boost.Python shim 惰性边界
This commit is contained in:
@@ -1,12 +1,31 @@
|
||||
#include "boost/python/class.hpp"
|
||||
#include "boost/python/converter/registry.hpp"
|
||||
#include "boost/python/def.hpp"
|
||||
#include "boost/python/dict.hpp"
|
||||
#include "boost/python/enum.hpp"
|
||||
#include "boost/python/exception_translator.hpp"
|
||||
#include "boost/python/extract.hpp"
|
||||
#include "boost/python/import.hpp"
|
||||
#include "boost/python/list.hpp"
|
||||
#include "boost/python/module.hpp"
|
||||
#include "boost/python/object.hpp"
|
||||
#include "boost/python/object/class_detail.hpp"
|
||||
#include "boost/python/return_internal_reference.hpp"
|
||||
#include "boost/python/scope.hpp"
|
||||
#include "boost/python/str.hpp"
|
||||
#include "boost/python/suite/indexing/map_indexing_suite.hpp"
|
||||
#include "boost/python/tuple.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
// LinuxCNC source basis: src/emc/rs274ngc/gcodemodule.cc,
|
||||
// interpmodule.cc, and py*.cc use these Python C API entry points while
|
||||
// defining RS274 Python binding objects. The WASM shim keeps the API inert
|
||||
// and link-safe while browser Python execution remains disabled.
|
||||
// interpmodule.cc, py*.cc, interp_python.cc, interp_namedparams.cc, and
|
||||
// src/emc/pythonplugin/python_plugin.cc use these Python C API and
|
||||
// Boost.Python entry points. The WASM shim keeps the API inert and link-safe
|
||||
// while browser Python execution remains disabled.
|
||||
namespace {
|
||||
|
||||
struct ProbeObject {
|
||||
@@ -14,8 +33,111 @@ struct ProbeObject {
|
||||
int value;
|
||||
};
|
||||
|
||||
struct ProbeCppObject {
|
||||
int value = 0;
|
||||
};
|
||||
|
||||
PyObject *probe_getter(PyObject *, void *) {
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
int probe_setter(PyObject *, PyObject *, void *) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject *probe_method(PyObject *, PyObject *) {
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
void translate_probe_exception(const std::runtime_error &) {
|
||||
}
|
||||
|
||||
bool boost_python_shims_are_inert() {
|
||||
namespace bp = boost::python;
|
||||
|
||||
bp::object object;
|
||||
if (object.ptr() != nullptr || object.attr("missing").operator bp::object().ptr() != nullptr ||
|
||||
object["missing"].ptr() != nullptr || object[0].ptr() != nullptr ||
|
||||
object().ptr() != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bp::list list;
|
||||
list.append(object);
|
||||
list.extend(list);
|
||||
bp::tuple tuple(list);
|
||||
bp::dict dict;
|
||||
if (bp::tuple().ptr() != nullptr || tuple.ptr() != nullptr ||
|
||||
bp::make_tuple(1, 2.0, "three").ptr() != nullptr ||
|
||||
dict.keys().ptr() != nullptr || bp::len(list) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((object % tuple).ptr() != nullptr || ("linuxcnc" % tuple).ptr() != nullptr ||
|
||||
(object + object).ptr() != nullptr || (object + "suffix").ptr() != nullptr ||
|
||||
("prefix" + object).ptr() != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bp::scope scope(object);
|
||||
scope.attr("this") = object;
|
||||
if (scope.attr("this").operator bp::object().ptr() != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bp::getattr(object, "__next__").ptr() != nullptr ||
|
||||
bp::make_function(probe_method).ptr() != nullptr ||
|
||||
bp::make_getter(probe_getter).ptr() != nullptr ||
|
||||
bp::make_setter(probe_setter).ptr() != nullptr ||
|
||||
bp::import("traceback").ptr() != nullptr ||
|
||||
bp::str("\n").join(object).ptr() != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (static_cast<int>(bp::extract<int>(object)) != 0 ||
|
||||
static_cast<double>(bp::extract<double>(object)) != 0.0 ||
|
||||
static_cast<std::string>(bp::extract<std::string>(object)) != std::string() ||
|
||||
static_cast<char *>(bp::extract<char *>(object)) != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bp::handle<> default_handle;
|
||||
bp::handle<> null_handle(bp::allow_null(static_cast<PyObject *>(nullptr)));
|
||||
bp::handle<> borrowed_handle(bp::borrowed(Py_None));
|
||||
if (default_handle || default_handle.get() != nullptr ||
|
||||
null_handle || null_handle.get() != nullptr ||
|
||||
borrowed_handle || borrowed_handle.get() != nullptr) {
|
||||
return false;
|
||||
}
|
||||
bp::handle_exception();
|
||||
|
||||
bp::class_<ProbeCppObject>("ProbeCppObject")
|
||||
.def("method", probe_method)
|
||||
.def_readwrite("value", &ProbeCppObject::value)
|
||||
.add_property("property", bp::make_getter(probe_getter), bp::make_setter(probe_setter));
|
||||
bp::class_<ProbeCppObject>("ProbeCppObjectNoInit", bp::no_init);
|
||||
bp::class_<ProbeCppObject>("ProbeCppObjectDoc", "doc");
|
||||
bp::class_<ProbeCppObject>("ProbeCppObjectDocNoInit", "doc", bp::no_init);
|
||||
|
||||
bp::enum_<int>("ProbeEnum").value("one", 1).export_values();
|
||||
bp::def("probe", probe_method);
|
||||
bp::register_exception_translator<std::runtime_error>(translate_probe_exception);
|
||||
bp::return_internal_reference<1, bp::default_call_policies> reference_policy;
|
||||
(void)reference_policy;
|
||||
bp::map_indexing_suite<std::map<int, int>> map_suite;
|
||||
(void)map_suite;
|
||||
if (bp::objects::registered_class_object(bp::type_id<ProbeCppObject>()) != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
BOOST_PYTHON_MODULE(cnc_sim_python_c_api_probe_module) {
|
||||
}
|
||||
|
||||
int main() {
|
||||
if (Py_IsInitialized() != 1) {
|
||||
return 1;
|
||||
@@ -123,5 +245,8 @@ int main() {
|
||||
if (PyErr_Format(PyExc_TypeError, "linuxcnc") != nullptr) {
|
||||
return 15;
|
||||
}
|
||||
if (!boost_python_shims_are_inert()) {
|
||||
return 28;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user