Selaa lähdekoodia

Fix for race in lazy initialization of handlers.

This fixes https://github.com/protocolbuffers/protobuf/issues/6532.
Joshua Haberman 6 vuotta sitten
vanhempi
commit
b245551a61
1 muutettua tiedostoa jossa 21 lisäystä ja 0 poistoa
  1. 21 0
      ruby/ext/google/protobuf_c/defs.c

+ 21 - 0
ruby/ext/google/protobuf_c/defs.c

@@ -2228,6 +2228,27 @@ static VALUE get_def_obj(VALUE _descriptor_pool, const void* ptr, VALUE klass) {
     VALUE args[3] = { c_only_cookie, _descriptor_pool, key };
     VALUE args[3] = { c_only_cookie, _descriptor_pool, key };
     def = rb_class_new_instance(3, args, klass);
     def = rb_class_new_instance(3, args, klass);
     rb_hash_aset(descriptor_pool->def_to_descriptor, key, def);
     rb_hash_aset(descriptor_pool->def_to_descriptor, key, def);
+
+    // For message defs, we now eagerly get/create descriptors for all
+    // submessages.  We will need these anyway to parse or serialize this
+    // message type.  But more importantly, we must do this now so that
+    // add_handlers_for_message() (which calls get_msgdef_obj()) does *not*
+    // need to create a Ruby object or insert into a Ruby Hash.  We need to
+    // avoid triggering GC, which can switch Ruby threads and re-enter our
+    // C extension from a different thread.  This wreaks havoc on our state
+    // if we were in the middle of building handlers.
+    if (klass == cDescriptor) {
+      const upb_msgdef *m = ptr;
+      upb_msg_field_iter it;
+      for (upb_msg_field_begin(&it, m);
+           !upb_msg_field_done(&it);
+           upb_msg_field_next(&it)) {
+        const upb_fielddef* f = upb_msg_iter_field(&it);
+        if (upb_fielddef_issubmsg(f)) {
+          get_msgdef_obj(_descriptor_pool, upb_fielddef_msgsubdef(f));
+        }
+      }
+    }
   }
   }
 
 
   return def;
   return def;