Thank you in advance for your comprehensive example, I understood it now. I 
just haven't considered that the macros need to ensure var-changing 
instructions may only be ran once. :)

Regards,
Marvin.

> -----Original Message-----
> From: Laszlo Ersek [mailto:[email protected]]
> Sent: Monday, May 30, 2016 8:54 PM
> To: Marvin Häuser <[email protected]>
> Cc: [email protected] <[email protected]>
> Subject: Re: [edk2] [PATCH v1 1/1] MdePkg/DebugLib: Ignore DEBUG
> variables in RELEASE builds.
> 
> On 05/30/16 20:13, Marvin Häuser wrote:
> > Hey Laszlo,
> >
> > Thanks for your comment. To be honest, I was not aware of any side
> > effects when casting to VOID - that's what I have been used to in the
> > past and also saw it in several sources, including Microsoft (yes, not
> > a good example for good src :) ).
> 
> No, that's not what I meant. It is fine to cast an expression that you already
> have in place to VOID. For example, if you have the (statement-)expression
> 
>   fprintf(stdout, "hello world\n");
> 
> and you expressly don't care about the return value (an "int", for printf()),
> you can write
> 
>   (void)fprintf(stdout, "hello world\n");
> 
> But that's not *all* your patch does. Instead, your patch adds brand new
> instances (evaluations) of the debug expression that have been there
> before.
> 
> For example:
> 
> >>> @@ -288,6 +288,8 @@ DebugPrintLevelEnabled (  #if
> >>> !defined(MDEPKG_NDEBUG)
> >>>    #define ASSERT(Expression)        \
> >>>      do {                            \
> >>> +      (VOID)(Expression);           \
> >>> +                                    \
> >>>        if (DebugAssertEnabled ()) {  \
> >>>          if (!(Expression)) {        \
> >>>            _ASSERT (Expression);     \
> >>> @@ -295,7 +297,7 @@ DebugPrintLevelEnabled (
> >>>        }                             \
> >>>      } while (FALSE)
> >>>  #else
> >>> -  #define ASSERT(Expression)
> >>> +  #define ASSERT(Expression) (VOID)(Expression)
> >>>  #endif
> 
> First, some background:
> 
> * On a toolchain that supports link time optimization (here: elimination of
> dead code at linking), the MDEPKG_NDEBUG macro is not supposed to be
> defined. Instead, the DebugAssertEnabled() function is called. That function
> is usually based on PcdDebugPropertyMask. If the latter PCD is a fixed PCD,
> then the condition can be evaluated at build time, and if it is false, then an
> LTO-capable toolchain can remove the entire code block dependent on the
> condition. This is what the first branch of the outermost #if is for.
> 
> * The second branch is for toolchains that don't support LTO. For them, the
> only way to remove code that is dead, due to building for RELEASE (as
> opposed to DEBUG), is to #define MDEPKG_NDEBUG in the RELEASE build
> flags. In this case, the compiler doesn't even see the code (it doesn't 
> survive
> into linking) because the preprocessor removes it.
> 
> But, *either way*, the end result is, if you build for RELEASE, the Expression
> passed to ASSERT() is not evaluated. It doesn't matter if it's the
> DebugAssertEnabled() function call or the MDEPKG_NDEBUG macro that
> prevents the evaluation, the point is, the evaluation doesn't occur.
> 
> And that's what your patch breaks. Consider the following example:
> 
>   STATIC UINT32 CheckCounter;
> 
>   BOOLEAN
>   CheckIfStuffIsOkay (
>     VOID
>     )
>   {
>     BOOLEAN Okay;
> 
>     Print (L"Checking (%u)...\n", CheckCounter++);
>     //
>     // Okay = ...
>     //
>     return Okay;
>   }
> ...
> 
>   TYPE
>   SomeOtherFunction (
>     ...
>     )
>   {
>     ...
>     ASSERT (CheckIfStuffIsOkay ());
>     ...
>   }
> 
> Without your patch:
> - in a RELEASE build, the CheckCounter variable will not be incremented, and
> the string will not appear on the console
> - in a DEBUG build, the CheckCounter variable will be incremented once, and
> the string will appear once, on the console.
> 
> With your patch:
> - In a RELEASE build with a toolchain that supports LTO (i.e., one that 
> doesn't
> define MDEPKG_NDEBUG), the variable will be incremented, and the
> message will be printed.
> - In a DEBUG build with the same toolchain, the increment and the
> corresponding Print() will be executed twice.
> 
> In short, your patch changes behavior for when Expression, passed to
> ASSERT(), has side effects, and the toolchain supports LTO (i.e.,
> MDEPKG_NDEBUG is never defined).
> 
> It's a separate question whether it makes sense for any programmer to pass
> any such expression (i.e., one with side effects) to ASSERT(), but that's for
> the caller to decide, not the callee. As far as I can see, the ASSERT()
> specification in "MdePkg/Include/Library/DebugLib.h" does not require
> Expression to be free of side effects.
> 
> > But as the issue is obviously
> > known already, which I didn't know either, I will just wait it out.
> > Though, if only DEBUG builds are checked for unused variables, might
> > be an issue for those who only build RELEASE.
> 
> The idea is, people who build only RELEASE are likely end-users (or, perhaps
> more precisely, not edk2 developers). It is not helpful to annoy them with
> such warnings. However, edk2 developers are definitely expected to build
> DEBUG as well, which is how they can root out issues such as set-but-unused
> variables, and fix them.
> 
> Thanks,
> Laszlo
> 
> 
> >> -----Original Message-----
> >> From: Laszlo Ersek [mailto:[email protected]]
> >> Sent: Monday, May 30, 2016 6:03 PM
> >> To: Marvin Häuser <[email protected]>; edk2-
> >> [email protected] <[email protected]>
> >> Cc: [email protected]; [email protected]; Ard Biesheuvel
> >> <[email protected]>
> >> Subject: Re: [edk2] [PATCH v1 1/1] MdePkg/DebugLib: Ignore DEBUG
> >> variables in RELEASE builds.
> >>
> >> On 05/30/16 15:22, Marvin Häuser wrote:
> >>> When the only point of use of a variable is a DEBUG() or ASSERT()
> >>> expression, most compilers will issue a warning when targeting
> >>> RELEASE. Cast the parameters to VOID to silence these warnings.
> >>>
> >>> Contributed-under: TianoCore Contribution Agreement 1.0
> >>> Signed-off-by: Marvin Haeuser <[email protected]>
> >>> ---
> >>>  MdePkg/Include/Library/DebugLib.h | 19 ++++++++++++++-----
> >>>  1 file changed, 14 insertions(+), 5 deletions(-)
> >>
> >> This seems incorrect to me. The patch doesn't only cast existing
> >> expressions to VOID, it evaluates expressions for one more time. If
> >> the expressions have side effects (which may or may not be a smart
> >> thing, but it depends on the caller of DEBUG()), this patch will cause
> problems.
> >>
> >> Instead, the compiler flags should be changed for RELEASE builds not
> >> to warn about such variables. Please see the following messages:
> >>
> >> http://thread.gmane.org/gmane.comp.bios.edk2.devel/9184/focus=9454
> >> http://thread.gmane.org/gmane.comp.bios.edk2.devel/9702/focus=9735
> >>
> >> In brief, we converted the tree to be "clean" with regard to gcc's
> >> "-Wunused- but-set-variable", but only for DEBUG builds.
> >>
> >> Thanks
> >> Laszlo
> >>
> >>> diff --git a/MdePkg/Include/Library/DebugLib.h
> >>> b/MdePkg/Include/Library/DebugLib.h
> >>> index 93b6f8df34ae..25c8ebb95740 100644
> >>> --- a/MdePkg/Include/Library/DebugLib.h
> >>> +++ b/MdePkg/Include/Library/DebugLib.h
> >>> @@ -270,7 +270,7 @@ DebugPrintLevelEnabled (
> >>>      } while (FALSE)
> >>>    #define _DEBUG(Expression)   _DEBUG_PRINT Expression
> >>>  #else
> >>> -#define _DEBUG(Expression)   DebugPrint Expression
> >>> +  #define _DEBUG(Expression)   DebugPrint Expression
> >>>  #endif
> >>>
> >>>  /**
> >>> @@ -288,6 +288,8 @@ DebugPrintLevelEnabled (  #if
> >>> !defined(MDEPKG_NDEBUG)
> >>>    #define ASSERT(Expression)        \
> >>>      do {                            \
> >>> +      (VOID)(Expression);           \
> >>> +                                    \
> >>>        if (DebugAssertEnabled ()) {  \
> >>>          if (!(Expression)) {        \
> >>>            _ASSERT (Expression);     \
> >>> @@ -295,7 +297,7 @@ DebugPrintLevelEnabled (
> >>>        }                             \
> >>>      } while (FALSE)
> >>>  #else
> >>> -  #define ASSERT(Expression)
> >>> +  #define ASSERT(Expression) (VOID)(Expression)
> >>>  #endif
> >>>
> >>>  /**
> >>> @@ -312,13 +314,15 @@ DebugPrintLevelEnabled (  **/  #if
> >>> !defined(MDEPKG_NDEBUG)
> >>>    #define DEBUG(Expression)        \
> >>> +    (VOID)(Expression);            \
> >>> +                                   \
> >>>      do {                           \
> >>>        if (DebugPrintEnabled ()) {  \
> >>>          _DEBUG (Expression);       \
> >>>        }                            \
> >>>      } while (FALSE)
> >>>  #else
> >>> -  #define DEBUG(Expression)
> >>> +  #define DEBUG(Expression) (VOID)(Expression)
> >>>  #endif
> >>>
> >>>  /**
> >>> @@ -336,6 +340,8 @@ DebugPrintLevelEnabled (  #if
> >>> !defined(MDEPKG_NDEBUG)
> >>>    #define ASSERT_EFI_ERROR(StatusParameter)                              
> >>>                 \
> >>>      do {                                                                 
> >>>                 \
> >>> +      (VOID)(StatusParameter);                                           
> >>>                 \
> >>> +
> >>> + \
> >>>        if (DebugAssertEnabled ()) {                                       
> >>>                 \
> >>>          if (EFI_ERROR (StatusParameter)) {                               
> >>>                 \
> >>>            DEBUG ((EFI_D_ERROR, "\nASSERT_EFI_ERROR (Status =
> >>> %r)\n", StatusParameter));  \ @@ -344,7 +350,7 @@
> DebugPrintLevelEnabled (
> >>>        }                                                                  
> >>>                 \
> >>>      } while (FALSE)
> >>>  #else
> >>> -  #define ASSERT_EFI_ERROR(StatusParameter)
> >>> +  #define ASSERT_EFI_ERROR(StatusParameter)
> (VOID)(StatusParameter)
> >>>  #endif
> >>>
> >>>  /**
> >>> @@ -372,6 +378,9 @@ DebugPrintLevelEnabled (  #if
> >>> !defined(MDEPKG_NDEBUG)
> >>>    #define ASSERT_PROTOCOL_ALREADY_INSTALLED(Handle, Guid)
> >> \
> >>>      do {                                                                 
> >>>                \
> >>> +      (VOID)(Handle);                                                    
> >>>                \
> >>> +      (VOID)(Guid);                                                      
> >>>                \
> >>> +
> >>> + \
> >>>        if (DebugAssertEnabled ()) {                                       
> >>>                \
> >>>          VOID  *Instance;                                                 
> >>>                \
> >>>          ASSERT (Guid != NULL);                                           
> >>>                \
> >>> @@ -387,7 +396,7 @@ DebugPrintLevelEnabled (
> >>>        }                                                                  
> >>>                \
> >>>      } while (FALSE)
> >>>  #else
> >>> -  #define ASSERT_PROTOCOL_ALREADY_INSTALLED(Handle, Guid)
> >>> +  #define ASSERT_PROTOCOL_ALREADY_INSTALLED(Handle, Guid)
> >>> + (VOID)(Handle)
> >>>  #endif
> >>>
> >>>  /**
> >>>
> >

_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to