@@ -1424,17 +1424,34 @@ int write_dict(PyObject* self, buffer_t buffer,
14241424 }
14251425
14261426 /* Write _id first if this is a top level doc. */
1427- if (top_level && PyMapping_HasKeyString (dict , "_id" )) {
1428- PyObject * _id = PyMapping_GetItemString (dict , "_id" );
1429- if (!_id ) {
1430- return 0 ;
1431- }
1432- if (!write_pair (self , buffer , "_id" , 3 ,
1433- _id , check_keys , options , 1 )) {
1427+ if (top_level ) {
1428+ /*
1429+ * If "dict" is a defaultdict we don't want to call
1430+ * PyMapping_GetItemString on it. That would **create**
1431+ * an _id where one didn't previously exist (PYTHON-871).
1432+ */
1433+ if (PyDict_Check (dict )) {
1434+ /* PyDict_GetItemString returns a borrowed reference. */
1435+ PyObject * _id = PyDict_GetItemString (dict , "_id" );
1436+ if (_id ) {
1437+ if (!write_pair (self , buffer , "_id" , 3 ,
1438+ _id , check_keys , options , 1 )) {
1439+ return 0 ;
1440+ }
1441+ }
1442+ } else if (PyMapping_HasKeyString (dict , "_id" )) {
1443+ PyObject * _id = PyMapping_GetItemString (dict , "_id" );
1444+ if (!_id ) {
1445+ return 0 ;
1446+ }
1447+ if (!write_pair (self , buffer , "_id" , 3 ,
1448+ _id , check_keys , options , 1 )) {
1449+ Py_DECREF (_id );
1450+ return 0 ;
1451+ }
1452+ /* PyMapping_GetItemString returns a new reference. */
14341453 Py_DECREF (_id );
1435- return 0 ;
14361454 }
1437- Py_DECREF (_id );
14381455 }
14391456
14401457 iter = PyObject_GetIter (dict );
0 commit comments