Merge pull request #10146 from marioalexis84/app-string_hasher_py

App: Fix crash and undefined behavior in StringHasherPy and StringIDPy
This commit is contained in:
Chris Hennes
2023-08-13 13:45:06 -07:00
committed by GitHub
6 changed files with 189 additions and 103 deletions

View File

@@ -114,6 +114,8 @@
#include "PropertyFile.h"
#include "PropertyLinks.h"
#include "PropertyPythonObject.h"
#include "StringHasherPy.h"
#include "StringIDPy.h"
#include "TextDocument.h"
#include "Transactions.h"
#include "VRMLObject.h"
@@ -311,6 +313,9 @@ void Application::setupPythonTypes()
Base::Interpreter().addType(&App::MaterialPy::Type, pAppModule, "Material");
Base::Interpreter().addType(&App::MetadataPy::Type, pAppModule, "Metadata");
Base::Interpreter().addType(&App::StringHasherPy::Type, pAppModule, "StringHasher");
Base::Interpreter().addType(&App::StringIDPy::Type, pAppModule, "StringID");
// Add document types
Base::Interpreter().addType(&App::PropertyContainerPy::Type, pAppModule, "PropertyContainer");
Base::Interpreter().addType(&App::ExtensionContainerPy::Type, pAppModule, "ExtensionContainer");
@@ -2109,6 +2114,10 @@ void Application::initTypes()
App::RangeExpression ::init();
App::PyObjectExpression ::init();
// Topological naming classes
App::StringHasher ::init();
App::StringID ::init();
// register transaction type
new App::TransactionProducer<TransactionDocumentObject>
(DocumentObject::getClassTypeId());

View File

@@ -32,117 +32,135 @@ using namespace App;
// returns a string which represent the object e.g. when printed in python
std::string StringHasherPy::representation() const
{
std::ostringstream str;
str << "<StringHasher at " << getStringHasherPtr() << ">";
return str.str();
std::ostringstream str;
str << "<StringHasher at " << getStringHasherPtr() << ">";
return str.str();
}
PyObject *StringHasherPy::PyMake(struct _typeobject *, PyObject *, PyObject *) // Python wrapper
{
return new StringHasherPy(new StringHasher);
return new StringHasherPy(new StringHasher);
}
// constructor method
int StringHasherPy::PyInit(PyObject* , PyObject* )
int StringHasherPy::PyInit(PyObject* args, PyObject* kwds)
{
return 0;
char* kw[] = {nullptr};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "", kw)) {
return -1;
}
return 0;
}
PyObject* StringHasherPy::isSame(PyObject *args)
{
PyObject *other;
if (!PyArg_ParseTuple(args, "O!", &StringHasherPy::Type, &other)){ // convert args: Python->C
return Py::new_reference_to(Py::False());
}
auto otherHasher = static_cast<StringHasherPy*>(other)->getStringHasherPtr();
return Py::new_reference_to(Py::Boolean(getStringHasherPtr() == otherHasher));
PyObject *other;
if (!PyArg_ParseTuple(args, "O!", &StringHasherPy::Type, &other)) {
return nullptr;
}
auto otherHasher = static_cast<StringHasherPy*>(other)->getStringHasherPtr();
bool same = getStringHasherPtr() == otherHasher;
return PyBool_FromLong(same ? 1 : 0);
}
PyObject* StringHasherPy::getID(PyObject *args)
{
long id = -1;
int index = 0;
PyObject *value = nullptr;
PyObject *base64 = Py_False;
if (!PyArg_ParseTuple(args, "l|i",&id,&index)) {
PyErr_Clear();
if (!PyArg_ParseTuple(args, "O|O",&value,&base64))
return nullptr;
}
if(id>0) {
PY_TRY {
auto sid = getStringHasherPtr()->getID(id, index);
if(!sid) Py_Return;
return sid.getPyObject();
}PY_CATCH;
}
std::string txt;
#if PY_MAJOR_VERSION >= 3
if (PyUnicode_Check(value)) {
txt = PyUnicode_AsUTF8(value);
}
#else
if (PyUnicode_Check(value)) {
PyObject* unicode = PyUnicode_AsLatin1String(value);
txt = PyString_AsString(unicode);
Py_DECREF(unicode);
}
else if (PyString_Check(value)) {
txt = PyString_AsString(value);
}
#endif
else
throw Py::TypeError("expect argument of type string");
PY_TRY {
QByteArray data;
StringIDRef sid;
if(PyObject_IsTrue(base64)) {
data = QByteArray::fromBase64(QByteArray::fromRawData(txt.c_str(),txt.size()));
sid = getStringHasherPtr()->getID(data,true);
}else
sid = getStringHasherPtr()->getID(txt.c_str(),txt.size());
return sid.getPyObject();
}PY_CATCH;
long id;
int index = 0;
if (PyArg_ParseTuple(args, "l|i", &id, &index)) {
if (id > 0) {
PY_TRY {
auto sid = getStringHasherPtr()->getID(id, index);
if (!sid) {
Py_Return;
}
return sid.getPyObject();
}
PY_CATCH;
}
else {
PyErr_SetString(PyExc_ValueError, "Id must be positive integer");
return nullptr;
}
}
PyErr_Clear();
PyObject *value = nullptr;
PyObject *base64 = Py_False;
if (PyArg_ParseTuple(args, "O!|O!", &PyUnicode_Type, &value, &PyBool_Type, &base64)) {
PY_TRY {
std::string txt = PyUnicode_AsUTF8(value);
QByteArray data;
StringIDRef sid;
if (PyObject_IsTrue(base64)) {
data = QByteArray::fromBase64(QByteArray::fromRawData(txt.c_str(),txt.size()));
sid = getStringHasherPtr()->getID(data,true);
}
else {
sid = getStringHasherPtr()->getID(txt.c_str(),txt.size());
}
return sid.getPyObject();
}
PY_CATCH;
}
PyErr_SetString(PyExc_TypeError, "Positive integer and optional integer or "
"string and optional boolean is required");
return nullptr;
}
Py::Int StringHasherPy::getCount() const {
return Py::Int((long)getStringHasherPtr()->count());
Py::Long StringHasherPy::getCount() const
{
return Py::Long(PyLong_FromSize_t(getStringHasherPtr()->count()), true);
}
Py::Int StringHasherPy::getSize() const {
return Py::Int((long)getStringHasherPtr()->size());
Py::Long StringHasherPy::getSize() const
{
return Py::Long(PyLong_FromSize_t(getStringHasherPtr()->size()), true);
}
Py::Boolean StringHasherPy::getSaveAll() const {
return Py::Boolean(getStringHasherPtr()->getSaveAll());
Py::Boolean StringHasherPy::getSaveAll() const
{
return Py::Boolean(getStringHasherPtr()->getSaveAll());
}
void StringHasherPy::setSaveAll(Py::Boolean value) {
getStringHasherPtr()->setSaveAll(value);
void StringHasherPy::setSaveAll(Py::Boolean value)
{
getStringHasherPtr()->setSaveAll(value);
}
Py::Int StringHasherPy::getThreshold() const {
return Py::Int((long)getStringHasherPtr()->getThreshold());
Py::Long StringHasherPy::getThreshold() const
{
return Py::Long(getStringHasherPtr()->getThreshold());
}
void StringHasherPy::setThreshold(Py::Int value) {
getStringHasherPtr()->setThreshold(value);
void StringHasherPy::setThreshold(Py::Long value)
{
getStringHasherPtr()->setThreshold(value);
}
Py::Dict StringHasherPy::getTable() const {
Py::Dict dict;
for(auto &v : getStringHasherPtr()->getIDMap())
dict.setItem(Py::Int(v.first),Py::String(v.second.dataToText()));
return dict;
Py::Dict StringHasherPy::getTable() const
{
Py::Dict dict;
for (const auto &v : getStringHasherPtr()->getIDMap()) {
dict.setItem(Py::Long(v.first), Py::String(v.second.dataToText()));
}
return dict;
}
PyObject *StringHasherPy::getCustomAttributes(const char* /*attr*/) const
{
return nullptr;
return nullptr;
}
int StringHasherPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
return 0;
return 0;
}

View File

@@ -32,59 +32,69 @@ using namespace App;
// returns a string which represent the object e.g. when printed in python
std::string StringIDPy::representation() const
{
return getStringIDPtr()->toString(_index);
return getStringIDPtr()->toString(this->_index);
}
PyObject* StringIDPy::isSame(PyObject *args)
{
PyObject *other = nullptr;
if (PyArg_ParseTuple(args, "O!", &StringIDPy::Type, &other) == 0) { // convert args: Python->C
return Py::new_reference_to(Py::False());
}
auto *otherPy = static_cast<StringIDPy*>(other);
return Py::new_reference_to(Py::Boolean(
otherPy->getStringIDPtr() == this->getStringIDPtr()
&& otherPy->_index == this->_index));
PyObject *other = nullptr;
if (!PyArg_ParseTuple(args, "O!", &StringIDPy::Type, &other)) {
return nullptr;
}
auto *otherPy = static_cast<StringIDPy*>(other);
bool same = (otherPy->getStringIDPtr() == this->getStringIDPtr())
&& (otherPy->_index == this->_index);
return PyBool_FromLong(same ? 1 : 0);
}
Py::Int StringIDPy::getValue() const {
return Py::Int(getStringIDPtr()->value());
Py::Long StringIDPy::getValue() const
{
return Py::Long(getStringIDPtr()->value());
}
Py::List StringIDPy::getRelated() const {
Py::List list;
for (const auto &id : getStringIDPtr()->relatedIDs()) {
list.append(Py::Long(id.value()));
}
return list;
Py::List StringIDPy::getRelated() const
{
Py::List list;
for (const auto &id : getStringIDPtr()->relatedIDs()) {
list.append(Py::Long(id.value()));
}
return list;
}
Py::String StringIDPy::getData() const {
return {Py::String(getStringIDPtr()->dataToText(this->_index))};
Py::String StringIDPy::getData() const
{
return Py::String(getStringIDPtr()->dataToText(this->_index));
}
Py::Boolean StringIDPy::getIsBinary() const {
return {getStringIDPtr()->isBinary()};
Py::Boolean StringIDPy::getIsBinary() const
{
return Py::Boolean(getStringIDPtr()->isBinary());
}
Py::Boolean StringIDPy::getIsHashed() const {
return {getStringIDPtr()->isHashed()};
Py::Boolean StringIDPy::getIsHashed() const
{
return Py::Boolean(getStringIDPtr()->isHashed());
}
Py::Int StringIDPy::getIndex() const {
return Py::Int(this->_index);
Py::Long StringIDPy::getIndex() const
{
return Py::Long(this->_index);
}
void StringIDPy::setIndex(Py::Int index) {
this->_index = index;
void StringIDPy::setIndex(Py::Long index)
{
this->_index = index;
}
PyObject *StringIDPy::getCustomAttributes(const char* /*attr*/) const
{
return nullptr;
return nullptr;
}
int StringIDPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
{
return 0;
return 0;
}