|
@@ -349,8 +349,6 @@ static void *oneofsubmsg_handler(void *closure,
|
|
|
MessageHeader* msg = closure;
|
|
|
const oneof_handlerdata_t *oneofdata = hd;
|
|
|
uint32_t oldcase = DEREF(msg, oneofdata->case_ofs, uint32_t);
|
|
|
- DEREF(msg, oneofdata->case_ofs, uint32_t) =
|
|
|
- oneofdata->oneof_case_num;
|
|
|
|
|
|
VALUE subdesc =
|
|
|
get_def_obj((void*)oneofdata->md);
|
|
@@ -361,6 +359,11 @@ static void *oneofsubmsg_handler(void *closure,
|
|
|
DEREF(msg, oneofdata->ofs, VALUE) =
|
|
|
rb_class_new_instance(0, NULL, subklass);
|
|
|
}
|
|
|
+ // Set the oneof case *after* allocating the new class instance -- see comment
|
|
|
+ // in layout_set() as to why. There are subtle interactions with possible GC
|
|
|
+ // points and oneof field type transitions.
|
|
|
+ DEREF(msg, oneofdata->case_ofs, uint32_t) =
|
|
|
+ oneofdata->oneof_case_num;
|
|
|
|
|
|
VALUE submsg_rb = DEREF(msg, oneofdata->ofs, VALUE);
|
|
|
MessageHeader* submsg;
|
|
@@ -965,11 +968,11 @@ static void putmsg(VALUE msg_rb, const Descriptor* desc,
|
|
|
uint32_t offset =
|
|
|
desc->layout->fields[upb_fielddef_index(f)].offset +
|
|
|
sizeof(MessageHeader);
|
|
|
- uint32_t oneof_case_offset =
|
|
|
- desc->layout->fields[upb_fielddef_index(f)].case_offset +
|
|
|
- sizeof(MessageHeader);
|
|
|
|
|
|
if (upb_fielddef_containingoneof(f)) {
|
|
|
+ uint32_t oneof_case_offset =
|
|
|
+ desc->layout->fields[upb_fielddef_index(f)].case_offset +
|
|
|
+ sizeof(MessageHeader);
|
|
|
// For a oneof, check that this field is actually present -- skip all the
|
|
|
// below if not.
|
|
|
if (DEREF(msg, oneof_case_offset, uint32_t) !=
|