Skip to content

Commit 54944c0

Browse files
committed
PYTHON-2680 Add buggy BSON DBRef refactor
1 parent 7a67270 commit 54944c0

File tree

1 file changed

+70
-50
lines changed

1 file changed

+70
-50
lines changed

bson/_cbsonmodule.c

Lines changed: 70 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,6 +1506,72 @@ static PyObject* _cbson_dict_to_bson(PyObject* self, PyObject* args) {
15061506
return result;
15071507
}
15081508

1509+
/*
1510+
* Hook for optional decoding BSON documents to DBRef.
1511+
*/
1512+
static PyObject *_decode_as_dbref(PyObject* self, PyObject* value) {
1513+
struct module_state *state = GETSTATE(self);
1514+
PyObject* dbref = NULL;
1515+
PyObject* dbref_type = NULL;
1516+
PyObject* ref = NULL;
1517+
PyObject* id = NULL;
1518+
PyObject* database = NULL;
1519+
PyObject* ret = NULL;
1520+
int db_present = 0;
1521+
1522+
/* Decoding for DBRefs */
1523+
if (PyMapping_HasKeyString(value, "$ref") && PyMapping_HasKeyString(value, "$id")) { /* DBRef */
1524+
ref = PyMapping_GetItemString(value, "$ref");
1525+
/* PyMapping_GetItemString returns NULL to indicate error. */
1526+
if (!ref) {
1527+
goto invalid;
1528+
}
1529+
id = PyMapping_GetItemString(value, "$id");
1530+
/* PyMapping_GetItemString returns NULL to indicate error. */
1531+
if (!id) {
1532+
goto invalid;
1533+
}
1534+
1535+
if (PyMapping_HasKeyString(value, "$db")) {
1536+
database = PyMapping_GetItemString(value, "$db");
1537+
if (!database) {
1538+
goto invalid;
1539+
}
1540+
db_present = 1;
1541+
} else {
1542+
database = Py_None;
1543+
Py_INCREF(database);
1544+
}
1545+
1546+
// check types
1547+
if (!(PyUnicode_Check(ref) && (database == Py_None || PyUnicode_Check(database)))) {
1548+
ret = value;
1549+
goto invalid;
1550+
}
1551+
1552+
PyMapping_DelItemString(value, "$ref");
1553+
PyMapping_DelItemString(value, "$id");
1554+
if (db_present) {
1555+
PyMapping_DelItemString(value, "$db");
1556+
}
1557+
1558+
if ((dbref_type = _get_object(state->DBRef, "bson.dbref", "DBRef"))) {
1559+
dbref = PyObject_CallFunctionObjArgs(dbref_type, ref, id, database, value, NULL);
1560+
Py_DECREF(value);
1561+
value = dbref;
1562+
}
1563+
} else {
1564+
ret = value;
1565+
}
1566+
invalid:
1567+
Py_XDECREF(dbref);
1568+
Py_XDECREF(dbref_type);
1569+
Py_XDECREF(ref);
1570+
Py_XDECREF(id);
1571+
Py_XDECREF(database);
1572+
return ret;
1573+
}
1574+
15091575
static PyObject* get_value(PyObject* self, PyObject* name, const char* buffer,
15101576
unsigned* position, unsigned char type,
15111577
unsigned max, const codec_options_t* options) {
@@ -1552,7 +1618,6 @@ static PyObject* get_value(PyObject* self, PyObject* name, const char* buffer,
15521618
}
15531619
case 3:
15541620
{
1555-
PyObject* collection;
15561621
uint32_t size;
15571622

15581623
if (max < 4) {
@@ -1585,55 +1650,10 @@ static PyObject* get_value(PyObject* self, PyObject* name, const char* buffer,
15851650
goto invalid;
15861651
}
15871652

1588-
/* Decoding for DBRefs */
1589-
if (PyMapping_HasKeyString(value, "$ref")) { /* DBRef */
1590-
PyObject* dbref = NULL;
1591-
PyObject* dbref_type;
1592-
PyObject* id;
1593-
PyObject* database;
1594-
1595-
collection = PyMapping_GetItemString(value, "$ref");
1596-
/* PyMapping_GetItemString returns NULL to indicate error. */
1597-
if (!collection) {
1598-
goto invalid;
1599-
}
1600-
PyMapping_DelItemString(value, "$ref");
1601-
1602-
if (PyMapping_HasKeyString(value, "$id")) {
1603-
id = PyMapping_GetItemString(value, "$id");
1604-
if (!id) {
1605-
Py_DECREF(collection);
1606-
goto invalid;
1607-
}
1608-
PyMapping_DelItemString(value, "$id");
1609-
} else {
1610-
id = Py_None;
1611-
Py_INCREF(id);
1612-
}
1613-
1614-
if (PyMapping_HasKeyString(value, "$db")) {
1615-
database = PyMapping_GetItemString(value, "$db");
1616-
if (!database) {
1617-
Py_DECREF(collection);
1618-
Py_DECREF(id);
1619-
goto invalid;
1620-
}
1621-
PyMapping_DelItemString(value, "$db");
1622-
} else {
1623-
database = Py_None;
1624-
Py_INCREF(database);
1625-
}
1626-
1627-
if ((dbref_type = _get_object(state->DBRef, "bson.dbref", "DBRef"))) {
1628-
dbref = PyObject_CallFunctionObjArgs(dbref_type, collection, id, database, value, NULL);
1629-
Py_DECREF(dbref_type);
1630-
}
1631-
Py_DECREF(value);
1632-
value = dbref;
1633-
1634-
Py_DECREF(id);
1635-
Py_DECREF(collection);
1636-
Py_DECREF(database);
1653+
/* Hook for DBRefs */
1654+
value = _decode_as_dbref(self, value);
1655+
if (!value) {
1656+
goto invalid;
16371657
}
16381658

16391659
*position += size;

0 commit comments

Comments
 (0)