Bug 30077 - Duplicate definition of typedef struct debuginfod_client in libdwfl
Summary: Duplicate definition of typedef struct debuginfod_client in libdwfl
Status: RESOLVED FIXED
Alias: None
Product: elfutils
Classification: Unclassified
Component: libdw (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2023-02-03 20:12 UTC by David Edelsohn
Modified: 2023-02-06 09:47 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description David Edelsohn 2023-02-03 20:12:28 UTC
typedef struct debuginfod_client is defined in both libdwfl/libdwfl.h and in debuginfod.h included by libdwfl/libdwflP.h.  Although innocuous, this is invalid C and causes compilation failures with strict compliance.

One possible set of patches is:

--- libdwfl.h.orig	2023-02-03 15:03:57.669810336 -0500
+++ libdwfl.h	2023-02-03 15:00:53.959921348 -0500
@@ -49,8 +49,10 @@
    PC location described by an FDE belonging to Dwfl_Thread.  */
 typedef struct Dwfl_Frame Dwfl_Frame;
 
+#ifndef ENABLE_LIBDEBUGINFOD
 /* Handle for debuginfod-client connection.  */
 typedef struct debuginfod_client debuginfod_client;
+#endif
 
 /* Callbacks.  */
 typedef struct

--- libdwflP.h.orig	2023-02-03 15:04:29.749793736 -0500
+++ libdwflP.h	2023-02-03 14:53:56.320181520 -0500
@@ -29,6 +29,10 @@
 #ifndef _LIBDWFLP_H
 #define _LIBDWFLP_H	1
 
+#ifdef ENABLE_LIBDEBUGINFOD
+#include "../debuginfod/debuginfod.h"
+#endif
+
 #include <libdwfl.h>
 #include <libebl.h>
 #include <assert.h>
@@ -41,10 +45,6 @@
 #include "../libdw/libdwP.h"	/* We need its INTDECLs.  */
 #include "../libdwelf/libdwelfP.h"
 
-#ifdef ENABLE_LIBDEBUGINFOD
-#include "../debuginfod/debuginfod.h"
-#endif
-
 typedef struct Dwfl_Process Dwfl_Process;
 
 #define DWFL_ERRORS							      \
Comment 1 Mark Wielaard 2023-02-04 17:32:14 UTC
(In reply to David Edelsohn from comment #0)
> typedef struct debuginfod_client is defined in both libdwfl/libdwfl.h and in
> debuginfod.h included by libdwfl/libdwflP.h.  Although innocuous, this is
> invalid C and causes compilation failures with strict compliance.

Is there a gcc flag that can help us detect this issue?

If the problem is that there cannot be two equal typedefs then we have to solve this not just in the implementation code but also in the public headers.

If if understand the issue correctly then a program that includes both the public debuginfod.h and dwfl.h headers (in any order or indirectly) has the same problem?

Would the following fix it?

diff --git a/debuginfod/debuginfod.h.in b/debuginfod/debuginfod.h.in
index 69c9efd2..4a256ba9 100644
--- a/debuginfod/debuginfod.h.in
+++ b/debuginfod/debuginfod.h.in
@@ -44,7 +44,10 @@
 #define DEBUGINFOD_SONAME "@LIBDEBUGINFOD_SONAME@"
 
 /* Handle for debuginfod-client connection.  */
+#ifndef _ELFUTILS_DEBUGINFOD_CLIENT_TYPEDEF
 typedef struct debuginfod_client debuginfod_client;
+#define _ELFUTILS_DEBUGINFOD_CLIENT_TYPEDEF 1
+#endif
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h
index 9114f7f0..49ad6664 100644
--- a/libdwfl/libdwfl.h
+++ b/libdwfl/libdwfl.h
@@ -50,7 +50,10 @@ typedef struct Dwfl_Thread Dwfl_Thread;
 typedef struct Dwfl_Frame Dwfl_Frame;
 
 /* Handle for debuginfod-client connection.  */
+#ifndef _ELFUTILS_DEBUGINFOD_CLIENT_TYPEDEF
 typedef struct debuginfod_client debuginfod_client;
+#define _ELFUTILS_DEBUGINFOD_CLIENT_TYPEDEF 1
+#endif
 
 /* Callbacks.  */
 typedef struct
Comment 2 Sam James 2023-02-04 18:25:28 UTC
These issues sometimes appear with -flto -Wlto-type-mismatch but not clear that's the case here.
Comment 3 David Edelsohn 2023-02-04 22:04:07 UTC
The proposed patch in Comment #1 will work. It seems unfortunate for libdwfl.h to define a struct that is part of debuginfod instead of using the debuginfod header.

The struct is needed by libdwfl.h to prototype

extern debuginfod_client *dwfl_get_debuginfod_client (Dwfl *dwfl);

but that function is defined in debuginfod-client.c protected by

#ifdef ENABLE_LIBDEBUGINFOD

It already is protected where it is referenced by an existing macro.  The problem is the header logic doesn't match the logic in the file that uses that prototype.

So, again, it would seem better to include the struct from debuginfod-client.h directly instead of adding more macros to protect the headers and types that already are protected.  Something like:

--- libdwfl.h.orig	2023-02-03 15:03:57.669810336 -0500
+++ libdwfl.h	2023-02-04 16:57:05.734206129 -0500
@@ -49,9 +49,6 @@
    PC location described by an FDE belonging to Dwfl_Thread.  */
 typedef struct Dwfl_Frame Dwfl_Frame;
 
-/* Handle for debuginfod-client connection.  */
-typedef struct debuginfod_client debuginfod_client;
-
 /* Callbacks.  */
 typedef struct
 {
@@ -808,12 +805,16 @@
 int dwfl_frame_reg (Dwfl_Frame *state, unsigned regno, Dwarf_Word *val)
   __nonnull_attribute__ (1);
 
+#ifdef ENABLE_LIBDEBUGINFOD
+#include "../debuginfod/debuginfod.h"
+
 /* Return the internal debuginfod-client connection handle for the DWFL session.
    When the client connection has not yet been initialized, it will be done on the
    first call to this function. If elfutils is compiled without support for debuginfod,
    NULL will be returned.
  */
 extern debuginfod_client *dwfl_get_debuginfod_client (Dwfl *dwfl);
+#endif
 
 #ifdef __cplusplus
 }

That defines the struct in only one place (debuginfod.h) and includes the header and prototype with the same macro protecting its use in debuginfod-client.c.
Comment 4 Mark Wielaard 2023-02-05 10:35:23 UTC
(In reply to Sam James from comment #2)
> These issues sometimes appear with -flto -Wlto-type-mismatch but not clear
> that's the case here.

Yes, but typedefs don't define new types, just alias types.
Also it looks like this is actually allowed (at least in C11, maybe some compilers didn't accept it before?):

- a typedef name may be redefined to denote the same type as it currently does,
provided that type is not a variably modified type
Comment 5 Mark Wielaard 2023-02-05 10:46:21 UTC
(In reply to David Edelsohn from comment #3)
> The struct is needed by libdwfl.h to prototype
> 
> extern debuginfod_client *dwfl_get_debuginfod_client (Dwfl *dwfl);
> 
> but that function is defined in debuginfod-client.c protected by
> 
> #ifdef ENABLE_LIBDEBUGINFOD
> 
> It already is protected where it is referenced by an existing macro.  The
> problem is the header logic doesn't match the logic in the file that uses
> that prototype.
> 
> So, again, it would seem better to include the struct from
> debuginfod-client.h directly instead of adding more macros to protect the
> headers and types that already are protected.  Something like:

The public headers are independent and can be used with or without the other being available. And the function must be defined with or without libdebuginfod support available or installed.

You cannot use the same guards in the public headers and the implementation sources because they are independent.

It might be helpful to know in which configuration you are having this issue.
Comment 6 David Edelsohn 2023-02-05 21:41:01 UTC
The error is reported if one configures and builds with Clang.

Also, yes, this is a C11 feature, but libdwfl/Makefile.in explicitly invokes the compiler with -std=gnu99 (AM_CFLAGS).
Comment 7 Mark Wielaard 2023-02-06 09:47:06 UTC
(In reply to David Edelsohn from comment #6)
> The error is reported if one configures and builds with Clang.

Aha. I am not sure things will build with clang. It seems to have a couple more quirks like not supporting some uses of flexible arrays.

Note that this really is a pendantic warning and shouldn't be enabled by default imho. You can simply silence it with -Wno-typedef-redefinition

> Also, yes, this is a C11 feature, but libdwfl/Makefile.in explicitly invokes
> the compiler with -std=gnu99 (AM_CFLAGS).

Maybe it is time to switch to gnu11 these days. But since this is in public headers and we don't control the compiler/standard users use lets simply make sure there is only one typedef:

commit 45576ab5f24cd39669a418fa8e005b4d04f8e9ca (HEAD -> master)
Author: Mark Wielaard <mark@klomp.org>
Date:   Mon Feb 6 10:21:58 2023 +0100

    debuginfod: Make sure there is only one typedef for debuginfod_client
    
    Both debuginfod.h and libdwfl.h have a simple typedef for struct
    debuginfod_client. Some compilers pedantically warn when including
    both headers that such typedefs are only officially supported in
    C11. So guard them with _ELFUTILS_DEBUGINFOD_CLIENT_TYPEDEF to
    make them happy.
    
    https://sourceware.org/bugzilla/show_bug.cgi?id=30077
    
    Signed-off-by: Mark Wielaard <mark@klomp.org>