Re: C++ conversion status update

Pedro Alves <[email protected]>
Newsgroups gmane.comp.gdb.devel
Message-ID <[email protected]>
On 12/15/2015 08:02 PM, Simon Marchi wrote:
> On 15 December 2015 at 06:46, Jose E. Marchesi <[email protected]> wrote:
>> g++ -g -O2   -I. -I../../gdb -I../../gdb/common -I../../gdb/config -DLOCALEDIR="\"/usr/local/share/locale\"" -DHAVE_CONFIG_H -I../../gdb/../include/opcode -I../../gdb/../opcodes/.. -I../../gdb/../readline/.. -I../../gdb/../zlib -I../bfd -I../../gdb/../bfd -I../../gdb/../include -I../libdecnumber -I../../gdb/../libdecnumber  -I../../gdb/gnulib/import -Ibuild-gnulib/import   -DTUI=1  -I/usr/include/python2.6 -I/usr/include/python2.6 -Wall -Wpointer-arith -Wno-unused -Wunused-value -Wunused-function -Wno-switch -Wno-char-subscripts -Wempty-body -Wno-sign-compare -Wno-write-strings -Wno-narrowing -Wformat-nonliteral -Werror -c -o sparc64-tdep.o -MT sparc64-tdep.o -MMD -MP -MF .deps/sparc64-tdep.Tpo ../../gdb/sparc64-tdep.c
>> cc1plus: warnings being treated as errors
>> In file included from ../../gdb/target.h:74,
>>                  from ../../gdb/exec.h:23,
>>                  from ../../gdb/gdbcore.h:29,
>>                  from ../../gdb/sparc64-tdep.c:27:
>> ../../gdb/btrace.h: In function ‘size_t VEC_btrace_insn_s_embedded_size(int)’:
>> ../../gdb/btrace.h:84: error: invalid access to non-static data member ‘VEC_btrace_insn_s::vec’  of NULL object
>> ../../gdb/btrace.h:84: error: (perhaps the ‘offsetof’ macro was used incorrectly)
>> ../../gdb/btrace.h: In function ‘VEC_btrace_insn_s* VEC_btrace_insn_s_alloc(int)’:
>> ../../gdb/btrace.h:84: error: invalid access to non-static data member ‘VEC_btrace_insn_s::vec’  of NULL object
>> ../../gdb/btrace.h:84: error: (perhaps the ‘offsetof’ macro was used incorrectly)
>> ../../gdb/btrace.h: In function ‘VEC_btrace_insn_s* VEC_btrace_insn_s_copy(VEC_btrace_insn_s*)’:
>> ../../gdb/btrace.h:84: error: invalid access to non-static data member ‘VEC_btrace_insn_s::vec’  of NULL object
>> ../../gdb/btrace.h:84: error: (perhaps the ‘offsetof’ macro was used incorrectly)
>> ../../gdb/btrace.h: In function ‘VEC_btrace_insn_s* VEC_btrace_insn_s_merge(VEC_btrace_insn_s*, VEC_btrace_insn_s*)’:
>> ../../gdb/btrace.h:84: error: invalid access to non-static data member ‘VEC_btrace_insn_s::vec’  of NULL object
>> ../../gdb/btrace.h:84: error: (perhaps the ‘offsetof’ macro was used incorrectly)
>> ../../gdb/btrace.h: In function ‘int VEC_btrace_insn_s_reserve(VEC_btrace_insn_s**, int, const char*, unsigned int)’:
>> ../../gdb/btrace.h:84: error: invalid access to non-static data member ‘VEC_btrace_insn_s::vec’  of NULL object
>> ../../gdb/btrace.h:84: error: (perhaps the ‘offsetof’ macro was used incorrectly)
>> At global scope:
>> cc1plus: error: unrecognized command line option "-Wno-narrowing"
>> make[2]: *** [sparc64-tdep.o] Error 1
>> make[2]: Leaving directory `/home/jemarch/couts2/binutils-gdb/build/gdb'
>> make[1]: *** [all-gdb] Error 2
>> make[1]: Leaving directory `/home/jemarch/couts2/binutils-gdb/build'
>> make: *** [all] Error 2
> 
> This can be reproduced with g++ 4.4 on any architecture, i think.
> 
> This seems to be caused by the interaction of enum_flags and the
> vector implementation.  After preprocessing we have this:
> 
>   __builtin_offsetof (VEC_btrace_insn_s, vec)
> 
> However, VEC_btrace_insn_s is a non-POD data type, because it
> ultimately contains an enum_flags object, which is non-POD.
> 
>   VEC_btrace_insn_s
>     btrace_insn_s vec[1];
>       btrace_insn_flags flags; (enum_flags <enum btrace_insn_flag>)
> 
> From what I read, using offsetof on a non-POD structure is an
> undefined behavior, at least in C++98.  I don't know if it has changed
> in later standard versions, but later g++ do not complain.

Yeah, C++11 relaxed the rules a lot.  enum_flags is designed to be
POD-like, though it has user-defined constructors.  It's quite safe
to memcpy it.

> 
> For g++ 4.4, it is possible to silence the warning/error with
> -Wno-invalid-offsetof, if we know that it still produces good results.
> 

Yeah, it should work.  The real fix of course would be to
reimplement vec.h using real C++ templates (until we can get rid of
C mode, that is).

An alternative is to avoid offsetof in the code itself, like in the
patch below.  It's really offsetof-but-avoid-NULL.

An advantage over disabling the warning is that it's contained in
the VEC code, which lets G++ catch issues elsewhere.  OTOH, disabling
warning is simpler.  WDYT?

From c0803a1aca62cde14c47a103aa996f1e1f4a2875 Mon Sep 17 00:00:00 2001
From: Pedro Alves <[email protected]>
Date: Tue, 15 Dec 2015 22:43:06 +0000
Subject: [PATCH] no offsetof

---
 gdb/common/vec.h | 44 ++++++++++++++++++++++++++++++++++----------
 1 file changed, 34 insertions(+), 10 deletions(-)

diff --git a/gdb/common/vec.h b/gdb/common/vec.h
index 6189283..a188b02 100644
--- a/gdb/common/vec.h
+++ b/gdb/common/vec.h
@@ -437,13 +437,23 @@ DEF_VEC_FUNC_O(T)							  \
 DEF_VEC_ALLOC_FUNC_O(T)							  \
 struct vec_swallow_trailing_semi
 
+/* Avoid offsetof (or its usual C implementation) as it triggers
+   -Winvalid-offsetof warnings with enum_flags types with G++ <= 4.4,
+   even though those types are memcpyable.  This requires allocating a
+   dummy local VEC in all routines that use this, but that has the
+   advantage that it only works if T is default constructible, which
+   is exactly a check we want, to keep C compatibility.  */
+#define vec_offset(T, VPTR) ((size_t) ((char *) &(VPTR)->vec - (char *) VPTR))
+
 #define DEF_VEC_ALLOC_FUNC_I(T)						  \
 static inline VEC(T) *VEC_OP (T,alloc)					  \
      (int alloc_)							  \
 {									  \
+  VEC(T) dummy;							  	  \
+									  \
   /* We must request exact size allocation, hence the negation.  */	  \
   return (VEC(T) *) vec_o_reserve (NULL, -alloc_,			  \
-                                   offsetof (VEC(T),vec), sizeof (T));	  \
+                                   vec_offset (T, &dummy), sizeof (T));	  \
 }									  \
 									  \
 static inline VEC(T) *VEC_OP (T,copy) (VEC(T) *vec_)			  \
@@ -453,9 +463,11 @@ static inline VEC(T) *VEC_OP (T,copy) (VEC(T) *vec_)			  \
 									  \
   if (len_)								  \
     {									  \
+      VEC(T) dummy;							  \
+									  \
       /* We must request exact size allocation, hence the negation.  */	  \
       new_vec_ = (VEC (T) *)						  \
-	vec_o_reserve (NULL, -len_, offsetof (VEC(T),vec), sizeof (T));	  \
+	vec_o_reserve (NULL, -len_, vec_offset (T, &dummy), sizeof (T));	\
 									  \
       new_vec_->num = len_;						  \
       memcpy (new_vec_->vec, vec_->vec, sizeof (T) * len_);		  \
@@ -467,12 +479,13 @@ static inline VEC(T) *VEC_OP (T,merge) (VEC(T) *vec1_, VEC(T) *vec2_)	  \
 {									  \
   if (vec1_ && vec2_)							  \
     {									  \
+      VEC(T) dummy;							  \
       size_t len_ = vec1_->num + vec2_->num;				  \
       VEC (T) *new_vec_ = NULL;						  \
 									  \
       /* We must request exact size allocation, hence the negation.  */	  \
       new_vec_ = (VEC (T) *)						  \
-	vec_o_reserve (NULL, -len_, offsetof (VEC(T),vec), sizeof (T));	  \
+	vec_o_reserve (NULL, -len_, vec_offset (T, &dummy), sizeof (T));	  \
 									  \
       new_vec_->num = len_;						  \
       memcpy (new_vec_->vec, vec1_->vec, sizeof (T) * vec1_->num);	  \
@@ -505,12 +518,13 @@ static inline void VEC_OP (T,cleanup)					  \
 static inline int VEC_OP (T,reserve)					  \
      (VEC(T) **vec_, int alloc_ VEC_ASSERT_DECL)			  \
 {									  \
+  VEC(T) dummy;								  \
   int extend = !VEC_OP (T,space)					  \
 	(*vec_, alloc_ < 0 ? -alloc_ : alloc_ VEC_ASSERT_PASS);		  \
 									  \
   if (extend)								  \
     *vec_ = (VEC(T) *) vec_o_reserve (*vec_, alloc_,			  \
-				      offsetof (VEC(T),vec), sizeof (T)); \
+				      vec_offset (T, &dummy), sizeof (T)); \
 									  \
   return extend;							  \
 }									  \
@@ -581,7 +595,9 @@ static inline int VEC_OP (T,iterate)					  \
 static inline size_t VEC_OP (T,embedded_size)				  \
      (int alloc_)							  \
 {									  \
-  return offsetof (VEC(T),vec) + alloc_ * sizeof(T);			  \
+  VEC(T) dummy;								  \
+									  \
+  return vec_offset (T, &dummy) + alloc_ * sizeof(T);			  \
 }									  \
 									  \
 static inline void VEC_OP (T,embedded_init)				  \
@@ -863,7 +879,9 @@ static inline int VEC_OP (T,iterate)					  \
 static inline size_t VEC_OP (T,embedded_size)				  \
      (int alloc_)							  \
 {									  \
-  return offsetof (VEC(T),vec) + alloc_ * sizeof(T);			  \
+  VEC(T) dummy;								  \
+									  \
+  return vec_offset (T, &dummy) + alloc_ * sizeof(T);			  \
 }									  \
 									  \
 static inline void VEC_OP (T,embedded_init)				  \
@@ -998,9 +1016,11 @@ static inline unsigned VEC_OP (T,lower_bound)				  \
 static inline VEC(T) *VEC_OP (T,alloc)					  \
      (int alloc_)							  \
 {									  \
+  VEC(T) dummy;								  \
+									  \
   /* We must request exact size allocation, hence the negation.  */	  \
   return (VEC(T) *) vec_o_reserve (NULL, -alloc_,			  \
-                                   offsetof (VEC(T),vec), sizeof (T));	  \
+                                   vec_offset (T, &dummy), sizeof (T));	  \
 }									  \
 									  \
 static inline VEC(T) *VEC_OP (T,copy) (VEC(T) *vec_)			  \
@@ -1010,9 +1030,11 @@ static inline VEC(T) *VEC_OP (T,copy) (VEC(T) *vec_)			  \
 									  \
   if (len_)								  \
     {									  \
+      VEC(T) dummy;							  \
+									  \
       /* We must request exact size allocation, hence the negation.  */	  \
       new_vec_ = (VEC (T) *)						  \
-	vec_o_reserve  (NULL, -len_, offsetof (VEC(T),vec), sizeof (T));  \
+	vec_o_reserve  (NULL, -len_, vec_offset (T, &dummy), sizeof (T)); \
 									  \
       new_vec_->num = len_;						  \
       memcpy (new_vec_->vec, vec_->vec, sizeof (T) * len_);		  \
@@ -1024,12 +1046,13 @@ static inline VEC(T) *VEC_OP (T,merge) (VEC(T) *vec1_, VEC(T) *vec2_)	  \
 {									  \
   if (vec1_ && vec2_)							  \
     {									  \
+      VEC(T) dummy;							  \
       size_t len_ = vec1_->num + vec2_->num;				  \
       VEC (T) *new_vec_ = NULL;						  \
 									  \
       /* We must request exact size allocation, hence the negation.  */	  \
       new_vec_ = (VEC (T) *)						  \
-	vec_o_reserve (NULL, -len_, offsetof (VEC(T),vec), sizeof (T));	  \
+	vec_o_reserve (NULL, -len_, vec_offset (T, &dummy), sizeof (T));  \
 									  \
       new_vec_->num = len_;						  \
       memcpy (new_vec_->vec, vec1_->vec, sizeof (T) * vec1_->num);	  \
@@ -1062,12 +1085,13 @@ static inline void VEC_OP (T,cleanup)					  \
 static inline int VEC_OP (T,reserve)					  \
      (VEC(T) **vec_, int alloc_ VEC_ASSERT_DECL)			  \
 {									  \
+  VEC(T) dummy;								  \
   int extend = !VEC_OP (T,space) (*vec_, alloc_ < 0 ? -alloc_ : alloc_	  \
 				  VEC_ASSERT_PASS);			  \
 									  \
   if (extend)								  \
     *vec_ = (VEC(T) *)							  \
-	vec_o_reserve (*vec_, alloc_, offsetof (VEC(T),vec), sizeof (T)); \
+      vec_o_reserve (*vec_, alloc_, vec_offset (T, &dummy), sizeof (T));  \
 									  \
   return extend;							  \
 }									  \
-- 
1.9.3
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.