验证 Boost.Python shim 惰性边界

This commit is contained in:
cnc
2026-06-06 05:20:23 +08:00
parent 5bc568eaa9
commit 66ea34a76d

View File

@@ -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;
}