From af23ec69a8531bf1927607176ab755a7baba1be7 Mon Sep 17 00:00:00 2001 From: Jorge Gorbe Moya Date: Fri, 19 May 2023 16:31:41 -0700 Subject: [PATCH] Move definitions for empty private constructors out of line. When building in debug mode, clang uses constructor type homing as an optimization for debug info size. This means the debug info for types is emitted at the same time as the constructor definition. Some `*Descriptor` types in this file only have an inline constructor which is never called (by design). Instead of properly constructing these objects, it looks like memory is allocated elsewhere and then cast to the needed type. This causes the compiler to never emit neither the inline constructor definition nor the debug info for these types, which harms the debugger experience (it is also technically undefined behavior). This change moves their definitions out of line to the .cc file. This doesn't solve the UB but it makes the compiler emit the definitions for the constructors somewhere, and thus the debug info too. PiperOrigin-RevId: 533579527 --- src/google/protobuf/descriptor.cc | 15 +++++++++++++++ src/google/protobuf/descriptor.h | 16 ++++++++-------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index ad3b52ba20..7f55985aa0 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc @@ -2579,6 +2579,21 @@ std::string FieldDescriptor::DefaultValueAsString( return ""; } +// Out-of-line constructor definitions ============================== +// When using constructor type homing in Clang, debug info for a type +// is only emitted when a constructor definition is emitted, as an +// optimization. These constructors are never called, so we define them +// out of line to make sure the debug info is emitted somewhere. + +Descriptor::Descriptor() {} +FieldDescriptor::FieldDescriptor() {} +OneofDescriptor::OneofDescriptor() {} +EnumDescriptor::EnumDescriptor() {} +EnumValueDescriptor::EnumValueDescriptor() {} +ServiceDescriptor::ServiceDescriptor() {} +MethodDescriptor::MethodDescriptor() {} +FileDescriptor::FileDescriptor() {} + // CopyTo methods ==================================================== void FileDescriptor::CopyTo(FileDescriptorProto* proto) const { diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h index 3ae042f482..47c05f4f04 100644 --- a/src/google/protobuf/descriptor.h +++ b/src/google/protobuf/descriptor.h @@ -660,7 +660,7 @@ class PROTOBUF_EXPORT Descriptor : private internal::SymbolBase { // and update them to initialize the field. // Must be constructed using DescriptorPool. - Descriptor() {} + Descriptor(); friend class DescriptorBuilder; friend class DescriptorPool; friend class EnumDescriptor; @@ -1077,7 +1077,7 @@ class PROTOBUF_EXPORT FieldDescriptor : private internal::SymbolBase { static const char* const kLabelToName[MAX_LABEL + 1]; // Must be constructed using DescriptorPool. - FieldDescriptor() {} + FieldDescriptor(); friend class DescriptorBuilder; friend class FileDescriptor; friend class Descriptor; @@ -1173,7 +1173,7 @@ class PROTOBUF_EXPORT OneofDescriptor : private internal::SymbolBase { // in descriptor.cc and update them to initialize the field. // Must be constructed using DescriptorPool. - OneofDescriptor() {} + OneofDescriptor(); friend class DescriptorBuilder; friend class Descriptor; friend class FieldDescriptor; @@ -1363,7 +1363,7 @@ class PROTOBUF_EXPORT EnumDescriptor : private internal::SymbolBase { // descriptor.cc and update them to initialize the field. // Must be constructed using DescriptorPool. - EnumDescriptor() {} + EnumDescriptor(); friend class DescriptorBuilder; friend class Descriptor; friend class FieldDescriptor; @@ -1456,7 +1456,7 @@ class PROTOBUF_EXPORT EnumValueDescriptor : private internal::SymbolBaseN<0>, // in descriptor.cc and update them to initialize the field. // Must be constructed using DescriptorPool. - EnumValueDescriptor() {} + EnumValueDescriptor(); friend class DescriptorBuilder; friend class EnumDescriptor; friend class DescriptorPool; @@ -1546,7 +1546,7 @@ class PROTOBUF_EXPORT ServiceDescriptor : private internal::SymbolBase { // descriptor.cc and update them to initialize the field. // Must be constructed using DescriptorPool. - ServiceDescriptor() {} + ServiceDescriptor(); friend class DescriptorBuilder; friend class FileDescriptor; friend class MethodDescriptor; @@ -1641,7 +1641,7 @@ class PROTOBUF_EXPORT MethodDescriptor : private internal::SymbolBase { // descriptor.cc and update them to initialize the field. // Must be constructed using DescriptorPool. - MethodDescriptor() {} + MethodDescriptor(); friend class DescriptorBuilder; friend class ServiceDescriptor; }; @@ -1875,7 +1875,7 @@ class PROTOBUF_EXPORT FileDescriptor : private internal::SymbolBase { // of Allocate() and AllocateArray() in // descriptor.cc and update them to initialize the field. - FileDescriptor() {} + FileDescriptor(); friend class DescriptorBuilder; friend class DescriptorPool; friend class Descriptor;