Skip to content

Commit 4274909

Browse files
anandoleecopybara-github
authored andcommitted
Fix python upb crashes on map/repeated reference stub destructor
The original code removes map/repeated stub from the weak map without reifying in some situations. Changed _Reify() functions to decide if need to delete from WeakMap or SetConcreteSubobj. PiperOrigin-RevId: 752524491
1 parent b07567f commit 4274909

File tree

6 files changed

+55
-32
lines changed

6 files changed

+55
-32
lines changed

python/google/protobuf/internal/message_test.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2699,6 +2699,20 @@ def testMapFindInitializationErrorsSmokeTest(self):
26992699
msg.map_string_foreign_message['foo'].c = 5
27002700
self.assertEqual(0, len(msg.FindInitializationErrors()))
27012701

2702+
def testMapStubReferenceSubMessageDestructor(self):
2703+
msg = map_unittest_pb2.TestMapSubmessage()
2704+
# A reference on map stub in sub message
2705+
map_ref = msg.test_map.map_int32_int32
2706+
# Make sure destructor after Clear the original message not crash
2707+
msg.Clear()
2708+
2709+
def testRepeatedStubReferenceSubMessageDestructor(self):
2710+
msg = unittest_pb2.NestedTestAllTypes()
2711+
# A reference on repeated stub in sub message
2712+
repeated_ref = msg.payload.repeated_int32
2713+
# Make sure destructor after Clear the original message not crash
2714+
msg.Clear()
2715+
27022716
@unittest.skipIf(sys.maxunicode == UCS2_MAXUNICODE, 'Skip for ucs2')
27032717
def testStrictUtf8Check(self):
27042718
# Test u'\ud801' is rejected at parser in both python2 and python3.

python/map.c

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ PyObject* PyUpb_MapContainer_NewStub(PyObject* parent, const upb_FieldDef* f,
9090
return &map->ob_base;
9191
}
9292

93-
void PyUpb_MapContainer_Reify(PyObject* _self, upb_Map* map) {
93+
upb_Map* PyUpb_MapContainer_Reify(PyObject* _self, upb_Map* map,
94+
PyUpb_WeakMap* subobj_map, intptr_t iter) {
9495
PyUpb_MapContainer* self = (PyUpb_MapContainer*)_self;
9596
if (!map) {
9697
const upb_FieldDef* f = PyUpb_MapContainer_GetField(self);
@@ -101,11 +102,19 @@ void PyUpb_MapContainer_Reify(PyObject* _self, upb_Map* map) {
101102
map = upb_Map_New(arena, upb_FieldDef_CType(key_f),
102103
upb_FieldDef_CType(val_f));
103104
}
105+
if (subobj_map) {
106+
PyUpb_WeakMap_DeleteIter(subobj_map, &iter);
107+
} else {
108+
const upb_FieldDef* f = PyUpb_MapContainer_GetField(self);
109+
upb_MessageValue msgval = {.map_val = map};
110+
PyUpb_Message_SetConcreteSubobj(self->ptr.parent, f, msgval);
111+
}
104112
PyUpb_ObjCache_Add(map, &self->ob_base);
105113
Py_DECREF(self->ptr.parent);
106114
self->ptr.map = map; // Overwrites self->ptr.parent.
107115
self->field &= ~(uintptr_t)1;
108116
assert(!PyUpb_MapContainer_IsStub(self));
117+
return map;
109118
}
110119

111120
void PyUpb_MapContainer_Invalidate(PyObject* obj) {
@@ -119,17 +128,7 @@ upb_Map* PyUpb_MapContainer_EnsureReified(PyObject* _self) {
119128
upb_Map* map = PyUpb_MapContainer_GetIfReified(self);
120129
if (map) return map; // Already writable.
121130

122-
const upb_FieldDef* f = PyUpb_MapContainer_GetField(self);
123-
upb_Arena* arena = PyUpb_Arena_Get(self->arena);
124-
const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(f);
125-
const upb_FieldDef* key_f = upb_MessageDef_Field(entry_m, 0);
126-
const upb_FieldDef* val_f = upb_MessageDef_Field(entry_m, 1);
127-
map =
128-
upb_Map_New(arena, upb_FieldDef_CType(key_f), upb_FieldDef_CType(val_f));
129-
upb_MessageValue msgval = {.map_val = map};
130-
PyUpb_Message_SetConcreteSubobj(self->ptr.parent, f, msgval);
131-
PyUpb_MapContainer_Reify((PyObject*)self, map);
132-
return map;
131+
return PyUpb_MapContainer_Reify((PyObject*)self, NULL, NULL, 0);
133132
}
134133

135134
static bool PyUpb_MapContainer_Set(PyUpb_MapContainer* self, upb_Map* map,

python/map.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include <stdbool.h>
1212

13+
#include "python/protobuf.h"
1314
#include "python/python_api.h"
1415
#include "upb/reflection/def.h"
1516

@@ -28,7 +29,8 @@ PyObject* PyUpb_MapContainer_GetOrCreateWrapper(upb_Map* map,
2829

2930
// Reifies a map stub to point to the concrete data in `map`.
3031
// If `map` is NULL, an appropriate empty map will be constructed.
31-
void PyUpb_MapContainer_Reify(PyObject* self, upb_Map* map);
32+
upb_Map* PyUpb_MapContainer_Reify(PyObject* self, upb_Map* map,
33+
PyUpb_WeakMap* subobj_map, intptr_t iter);
3234

3335
// Reifies this map object if it is not already reified.
3436
upb_Map* PyUpb_MapContainer_EnsureReified(PyObject* self);

python/message.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -685,8 +685,10 @@ static void PyUpb_Message_SyncSubobjs(PyUpb_Message* self);
685685
* the set state (having a non-owning pointer to self->ptr.msg).
686686
*/
687687
static void PyUpb_Message_Reify(PyUpb_Message* self, const upb_FieldDef* f,
688-
upb_Message* msg) {
688+
upb_Message* msg, PyUpb_WeakMap* subobj_map,
689+
intptr_t iter) {
689690
assert(f == PyUpb_Message_GetFieldDef(self));
691+
PyUpb_WeakMap_DeleteIter(subobj_map, &iter);
690692
if (!msg) {
691693
const upb_MessageDef* msgdef = PyUpb_Message_GetMsgdef((PyObject*)self);
692694
const upb_MiniTable* layout = upb_MessageDef_MiniTable(msgdef);
@@ -738,17 +740,18 @@ static void PyUpb_Message_SyncSubobjs(PyUpb_Message* self) {
738740
if (upb_FieldDef_HasPresence(f) && !upb_Message_HasFieldByDef(msg, f))
739741
continue;
740742
upb_MessageValue msgval = upb_Message_GetFieldByDef(msg, f);
741-
PyUpb_WeakMap_DeleteIter(subobj_map, &iter);
742743
if (upb_FieldDef_IsMap(f)) {
743744
if (!msgval.map_val) continue;
744-
PyUpb_MapContainer_Reify(obj, (upb_Map*)msgval.map_val);
745+
PyUpb_MapContainer_Reify(obj, (upb_Map*)msgval.map_val, subobj_map, iter);
745746
} else if (upb_FieldDef_IsRepeated(f)) {
746747
if (!msgval.array_val) continue;
747-
PyUpb_RepeatedContainer_Reify(obj, (upb_Array*)msgval.array_val);
748+
PyUpb_RepeatedContainer_Reify(obj, (upb_Array*)msgval.array_val,
749+
subobj_map, iter);
748750
} else {
749751
PyUpb_Message* sub = (void*)obj;
750752
assert(self == sub->ptr.parent);
751-
PyUpb_Message_Reify(sub, f, (upb_Message*)msgval.msg_val);
753+
PyUpb_Message_Reify(sub, f, (upb_Message*)msgval.msg_val, subobj_map,
754+
iter);
752755
}
753756
}
754757

@@ -1404,18 +1407,17 @@ static PyObject* PyUpb_Message_Clear(PyUpb_Message* self) {
14041407

14051408
while (PyUpb_WeakMap_Next(subobj_map, &key, &obj, &iter)) {
14061409
const upb_FieldDef* f = key;
1407-
PyUpb_WeakMap_DeleteIter(subobj_map, &iter);
14081410
if (upb_FieldDef_IsMap(f)) {
14091411
assert(upb_Message_GetFieldByDef(msg, f).map_val == NULL);
1410-
PyUpb_MapContainer_Reify(obj, NULL);
1412+
PyUpb_MapContainer_Reify(obj, NULL, subobj_map, iter);
14111413
} else if (upb_FieldDef_IsRepeated(f)) {
14121414
assert(upb_Message_GetFieldByDef(msg, f).array_val == NULL);
1413-
PyUpb_RepeatedContainer_Reify(obj, NULL);
1415+
PyUpb_RepeatedContainer_Reify(obj, NULL, subobj_map, iter);
14141416
} else {
14151417
assert(!upb_Message_HasFieldByDef(msg, f));
14161418
PyUpb_Message* sub = (void*)obj;
14171419
assert(self == sub->ptr.parent);
1418-
PyUpb_Message_Reify(sub, f, NULL);
1420+
PyUpb_Message_Reify(sub, f, NULL, subobj_map, iter);
14191421
}
14201422
}
14211423
}

python/repeated.c

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,33 +55,36 @@ static upb_Array* PyUpb_RepeatedContainer_GetIfReified(
5555
return PyUpb_RepeatedContainer_IsStub(self) ? NULL : self->ptr.arr;
5656
}
5757

58-
void PyUpb_RepeatedContainer_Reify(PyObject* _self, upb_Array* arr) {
58+
upb_Array* PyUpb_RepeatedContainer_Reify(PyObject* _self, upb_Array* arr,
59+
PyUpb_WeakMap* subobj_map,
60+
intptr_t iter) {
5961
PyUpb_RepeatedContainer* self = (PyUpb_RepeatedContainer*)_self;
6062
assert(PyUpb_RepeatedContainer_IsStub(self));
63+
const upb_FieldDef* f = PyUpb_RepeatedContainer_GetField(self);
6164
if (!arr) {
62-
const upb_FieldDef* f = PyUpb_RepeatedContainer_GetField(self);
6365
upb_Arena* arena = PyUpb_Arena_Get(self->arena);
6466
arr = upb_Array_New(arena, upb_FieldDef_CType(f));
6567
}
68+
if (subobj_map) {
69+
PyUpb_WeakMap_DeleteIter(subobj_map, &iter);
70+
} else {
71+
PyUpb_Message_SetConcreteSubobj(self->ptr.parent, f,
72+
(upb_MessageValue){.array_val = arr});
73+
}
6674
PyUpb_ObjCache_Add(arr, &self->ob_base);
6775
Py_DECREF(self->ptr.parent);
6876
self->ptr.arr = arr; // Overwrites self->ptr.parent.
6977
self->field &= ~(uintptr_t)1;
7078
assert(!PyUpb_RepeatedContainer_IsStub(self));
79+
return arr;
7180
}
7281

7382
upb_Array* PyUpb_RepeatedContainer_EnsureReified(PyObject* _self) {
7483
PyUpb_RepeatedContainer* self = (PyUpb_RepeatedContainer*)_self;
7584
upb_Array* arr = PyUpb_RepeatedContainer_GetIfReified(self);
7685
if (arr) return arr; // Already writable.
7786

78-
const upb_FieldDef* f = PyUpb_RepeatedContainer_GetField(self);
79-
upb_Arena* arena = PyUpb_Arena_Get(self->arena);
80-
arr = upb_Array_New(arena, upb_FieldDef_CType(f));
81-
PyUpb_Message_SetConcreteSubobj(self->ptr.parent, f,
82-
(upb_MessageValue){.array_val = arr});
83-
PyUpb_RepeatedContainer_Reify((PyObject*)self, arr);
84-
return arr;
87+
return PyUpb_RepeatedContainer_Reify((PyObject*)self, NULL, NULL, 0);
8588
}
8689

8790
static void PyUpb_RepeatedContainer_Dealloc(PyObject* _self) {

python/repeated.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include <stdbool.h>
1212

13+
#include "python/protobuf.h"
1314
#include "python/python_api.h"
1415
#include "upb/reflection/def.h"
1516

@@ -29,7 +30,9 @@ PyObject* PyUpb_RepeatedContainer_GetOrCreateWrapper(upb_Array* arr,
2930

3031
// Reifies a repeated field stub to point to the concrete data in `arr`.
3132
// If `arr` is NULL, an appropriate empty array will be constructed.
32-
void PyUpb_RepeatedContainer_Reify(PyObject* self, upb_Array* arr);
33+
upb_Array* PyUpb_RepeatedContainer_Reify(PyObject* self, upb_Array* arr,
34+
PyUpb_WeakMap* subobj_map,
35+
intptr_t iter);
3336

3437
// Reifies this repeated object if it is not already reified.
3538
upb_Array* PyUpb_RepeatedContainer_EnsureReified(PyObject* self);

0 commit comments

Comments
 (0)