Bug 105460

Summary: consider using _Must_inspect_result_ or _Check_result_ MSVC annotations
Product: dbus Reporter: Ralf Habacker <ralf.habacker>
Component: coreAssignee: D-Bus Maintainers <dbus>
Status: RESOLVED FIXED QA Contact: D-Bus Maintainers <dbus>
Severity: enhancement    
Priority: low Keywords: patch
Version: git master   
Hardware: Other   
OS: Windows (All)   
Whiteboard: review+, rebase needs testing
i915 platform: i915 features:
Attachments: patch proposal (requires msvc >= 2012)
enable msvc warning
Enable "unused result" warning for MSVC Compiler
Enable "unused result" warning for MSVC Compiler
Enable "unused result" warning for Visual Studio >= 2012 (MSVC 11.0)

Description Ralf Habacker 2018-03-12 15:31:57 UTC
With patch https://bugs.freedesktop.org/attachment.cgi?id=138019 applied the mentioned warnings are not displayed with cmake on Windows probably because cmake does not use the required compile warning flags.
Comment 1 Simon McVittie 2018-03-12 17:18:02 UTC
Are you using gcc or clang or the MSVC C compiler?

I think gcc will warn about ignoring the result of functions decorated with _DBUS_GNUC_WARN_UNUSED_RESULT without needing extra compiler flags. See dbus/dbus-macros.h: the definition of the macro is guarded by a __GNUC__ check. That's why it has GNUC in the name.

clang probably will too, because I think clang pretends to be gcc (it defines __GNUC__).

Other compilers, including MSVC, won't. If you know how to make MSVC warn about an unused result, please say (and also tell the GLib developers, because G_GNUC_WARN_UNUSED_RESULT is basically the same macro).

If there's no way to do this portably, it seems better to have only gcc warn about something than to have no compilers at all warn about it (and we get gcc warnings on Travis-CI, even if you're building with MSVC yourself).

One day I'd like to have a CI build of dbus for Windows done with MSVC on Appveyor, similar to the way Travis-CI tests cross-compiling from Linux for Windows with gcc, but I haven't had time for a while to learn how to do that.
Comment 2 Ralf Habacker 2018-03-12 19:32:10 UTC
Sorry, I forget to mention the compiler - it is i686-w64-mingw32 version 7.2  (In reply to Simon McVittie from comment #1)
> Are you using gcc or clang or the MSVC C compiler?
gcc i686-mingw32 version 7.2. 
 
> I think gcc will warn about ignoring the result of functions decorated with
> _DBUS_GNUC_WARN_UNUSED_RESULT without needing extra compiler flags. See
> dbus/dbus-macros.h: the definition of the macro is guarded by a __GNUC__
> check. That's why it has GNUC in the name.
rechecked on a different host and now got the warning - seemed to be a build system not recompiling the patched file

> clang probably will too, because I think clang pretends to be gcc (it
> defines __GNUC__).
yes, checked - /home/xxx/src/dbus-1/dbus/dbus-sysdeps-unix.c:1392:7: warning: ignoring return value of function declared with warn_unused_result attribute [-Wunused-result]
      _dbus_socket_get_invalid ();
      ^~~~~~~~~~~~~~~~~~~~~~~~

> Other compilers, including MSVC, won't. If you know how to make MSVC warn
> about an unused result, please say (and also tell the GLib developers,
> because G_GNUC_WARN_UNUSED_RESULT is basically the same macro).

https://stackoverflow.com/questions/4226308/msvc-equivalent-of-attribute-warn-unused-result
mentions _check_return_, which requires to set compile switch /analyze.

refers to https://msdn.microsoft.com/en-us/library/jj159529(v=vs.110).aspx mentions to use '_Must_inspect_result_' 
 
> If there's no way to do this portably, it seems better to have only gcc warn
> about something than to have no compilers at all warn about it (and we get
> gcc warnings on Travis-CI, even if you're building with MSVC yourself).
yes, I also do development with cross compiled gcc
Comment 3 Simon McVittie 2018-03-12 20:04:40 UTC
I think there are two ways this bug could go.

If you mostly develop with gcc anyway, we could rely on gcc for all our -Wunused-result needs, ignore MSVC, and close this as NOTABUG.

Or, we could use the MSVC annotations:

(In reply to Ralf Habacker from comment #2)
> https://stackoverflow.com/questions/4226308/msvc-equivalent-of-attribute-
> warn-unused-result
> mentions _check_return_, which requires to set compile switch /analyze.
> 
> refers to https://msdn.microsoft.com/en-us/library/jj159529(v=vs.110).aspx
> mentions to use '_Must_inspect_result_' 

I don't think we can *require* MSVC users to use /analyze, but if these attributes are accepted and ignored by the non-analyzing MSVC compiler, then using them would be fine.

If you want to make use of that annotation, because its positioning seems to be more strict than gcc attributes, I think the way to do it would be:

* add a new _DBUS_WARN_UNUSED_RESULT which expands to
  _Must_inspect_result_ on (recent) MSVC, __attribute__((warn_unused_result))
  on gcc and compatible compilers, and nothing on other compilers

* give that macro a doc-comment that indicates how to use it correctly,
  in terms that a non-MSVC-user like me will understand
  (if I'm reading the docs correctly, it needs to go on both declaration
  and definition, before the static storage class if the function is static,
  and before the return type if not static; if there is a required order
  for whether __declspec-based macros appear before or after these
  annotations then you'll also need to document that)

* change all uses of _DBUS_GNUC_WARN_UNUSED_RESULT to
  _DBUS_WARN_UNUSED_RESULT, and when each one is changed, move the
  annotation to the right place(s) where MSVC will accept it

* remove _DBUS_GNUC_WARN_UNUSED_RESULT when it has no more users
Comment 4 Ralf Habacker 2018-03-13 08:01:52 UTC
Created attachment 138067 [details] [review]
patch proposal (requires msvc >= 2012)
Comment 5 Ralf Habacker 2018-03-13 10:48:50 UTC
(In reply to Ralf Habacker from comment #4)
> Created attachment 138067 [details] [review] [review]
> patch proposal (requires msvc >= 2012)

A colleague is currently testing this patch on a machine with msvc 2012 and will provide a working patch.
Comment 6 Daniel Wendt 2018-03-13 12:12:51 UTC
Created attachment 138071 [details] [review]
enable msvc warning

After researching the Internet, the annotation should be used in
declaration and implementation. After own tests with the MSVC 2012
compiler it is sufficient to use the annotation only in the
declaration to get a compiler warning, as with the GCC compiler.
So the annotation is not necessary in the C implementation.
Comment 7 Simon McVittie 2018-03-13 13:11:31 UTC
Comment on attachment 138071 [details] [review]
enable msvc warning

Review of attachment 138071 [details] [review]:
-----------------------------------------------------------------

This looks very promising. Would it be possible to contribute a similar macro to GLib, while you're looking at this? In the GLib case, G_GNUC_WARN_UNUSED_RESULT would have to stay as-is for backwards compat (since it's public API, unlike _DBUS_WARN_UNUSED_RESULT), but setting up for better warnings on all compilers seems like a very good thing.

Are there really no other uses of _DBUS_GNUC_WARN_UNUSED_RESULT? I'm surprised there aren't more...

We should definitely add it in more places (like all the _dbus_string_foo() functions that return FALSE on out-of-memory) but I'll delay doing that until this commit is ready, to avoid adding a lot of _DBUS_GNUC_WARN_UNUSED_RESULT and then immediately having to turn it into _DBUS_WARN_UNUSED_RESULT.

::: cmake/CMakeLists.txt
@@ +218,5 @@
>      # 4114 same type qualifier used more than once
>      # 4133 'type' : incompatible types - from 'type1' to 'type2'
>      set(WARNINGS_ERRORS "4002 4003 4013 4028 4031 4047 4114 4133")
> +    if(MSVC_VERSION GREATER 1600 AND ${CMAKE_BUILD_TYPE} STREQUAL "Debug")
> +        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /analyze")

How "expensive" is /analyze?

If it's something that makes sense to use all the time for your debug builds (like gcc -Og -g) then you might as well go ahead with this. If it's really slow, then we'd probably be better off leaving out this change, and developers who really want static analysis can opt-in to it by setting whatever is CMake's equivalent of CFLAGS.

::: dbus/dbus-macros.h
@@ +92,4 @@
>  #define DBUS_ALLOC_SIZE2(x,y)
>  #endif
>  
> +/* MSVC requires to specify this warning in the declaration */

Please expand this comment to tell me *where* in the declaration (bear in mind that Linux developers like me have to be able to get this right in future code contributions, without ever actually using MSVC themselves). gcc attributes can be used like

__attribute__((foo)) static void foo (bar);
static void foo (bar) __attribute__((foo));

or even (I think)

static void __attribute__((foo)) foo (bar);
static __attribute__((foo)) void foo (bar);

but from what I've seen in documentation, MSVC attributes like _Must_inspect_result_ must come before the return type?

Is there any requirement about putting _DBUS_WARN_UNUSED_RESULT before or after the "static" of a static declaration?

Is there any requirement about putting _DBUS_WARN_UNUSED_RESULT before or after a macro that expands to __declspec(something), such as like DBUS_PRIVATE_EXPORT?
Comment 8 Simon McVittie 2018-03-13 13:16:21 UTC
(In reply to Ralf Habacker from comment #4)
> patch proposal (requires msvc >= 2012)

If it would make your life easier to put a Visual Studio requirement in NEWS, perhaps something like

* Visual Studio >= 20xx is required when compiling with CMake and MSVC

then I'd have no problem with that. (It would be best if at least one of the free Community Editions is supported, of course.)
Comment 9 Daniel Wendt 2018-03-14 12:38:01 UTC
(In reply to Simon McVittie from comment #7)
> Comment on attachment 138071 [details] [review] [review]
> enable msvc warning
> 
> Review of attachment 138071 [details] [review] [review]:
> -----------------------------------------------------------------
> 
> Are there really no other uses of _DBUS_GNUC_WARN_UNUSED_RESULT? I'm
> surprised there aren't more...

The macro is still used in the test program test/test-utils.h. I correct this in the following patch.


> ::: cmake/CMakeLists.txt
> @@ +218,5 @@
> >      # 4114 same type qualifier used more than once
> >      # 4133 'type' : incompatible types - from 'type1' to 'type2'
> >      set(WARNINGS_ERRORS "4002 4003 4013 4028 4031 4047 4114 4133")
> > +    if(MSVC_VERSION GREATER 1600 AND ${CMAKE_BUILD_TYPE} STREQUAL "Debug")
> > +        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /analyze")
> 
> How "expensive" is /analyze?
> 
> If it's something that makes sense to use all the time for your debug builds
> (like gcc -Og -g) then you might as well go ahead with this. If it's really
> slow, then we'd probably be better off leaving out this change, and
> developers who really want static analysis can opt-in to it by setting
> whatever is CMake's equivalent of CFLAGS.

With an Intel Core i7-2640M, the following times are required for compilation:

With /analyze 0:03:22.945000
Without /analyze 0:01:43.620000

Without the option /analyze, it is about 50 percent faster. So, it's really expensive, I guess. In the next patch is a CMake option that disables this by default.

> 
> ::: dbus/dbus-macros.h
> @@ +92,4 @@
> >  #define DBUS_ALLOC_SIZE2(x,y)
> >  #endif
> >  
> > +/* MSVC requires to specify this warning in the declaration */
> 
> Please expand this comment to tell me *where* in the declaration (bear in
> mind that Linux developers like me have to be able to get this right in
> future code contributions, without ever actually using MSVC themselves). gcc
> attributes can be used like
> 
> __attribute__((foo)) static void foo (bar);
> static void foo (bar) __attribute__((foo));
> 
> or even (I think)
> 
> static void __attribute__((foo)) foo (bar);
> static __attribute__((foo)) void foo (bar);
> 
> but from what I've seen in documentation, MSVC attributes like
> _Must_inspect_result_ must come before the return type?
> 
> Is there any requirement about putting _DBUS_WARN_UNUSED_RESULT before or
> after the "static" of a static declaration?
> 
> Is there any requirement about putting _DBUS_WARN_UNUSED_RESULT before or
> after a macro that expands to __declspec(something), such as like
> DBUS_PRIVATE_EXPORT?

I did some tests and expanded the comment. In this context I found the usage of this macro in dbus-userdb.h, where the macro is misplaced for the msvc compiler. But this has no effect because the file is only used under Linux. That is why we could leave it at that in this case.
Comment 10 Daniel Wendt 2018-03-14 12:39:36 UTC
Created attachment 138099 [details] [review]
Enable "unused result" warning for MSVC Compiler

Enable "unused result" warning for MSVC Compiler (Visual Studio >= 2012, MSVC 11.0)
Comment 11 Simon McVittie 2018-03-14 12:42:56 UTC
(In reply to Daniel Wendt from comment #9)
> In this context I found the usage
> of this macro in dbus-userdb.h, where the macro is misplaced for the msvc
> compiler. But this has no effect because the file is only used under Linux.
> That is why we could leave it at that in this case.

If this macro is going to have a MSVC implementation, then I think I'd prefer to adopt "put this macro where MSVC needs it to be" as part of our coding style, to make the rule to follow simpler for reviewers.
Comment 12 Simon McVittie 2018-03-14 12:59:00 UTC
Comment on attachment 138099 [details] [review]
Enable "unused result" warning for MSVC Compiler

Review of attachment 138099 [details] [review]:
-----------------------------------------------------------------

::: cmake/CMakeLists.txt
@@ +176,4 @@
>      ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE)
>      SET(CMAKE_C_FLAGS_DEBUG   "${CMAKE_C_FLAGS_DEBUG}   /FIconfig.h")
>      SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /FIconfig.h")
> +    option (DBUS_MSVC_CODEANALYZE "Enable code analyzing for MSVC compiler: /analyze" OFF)

Maybe DBUS_MSVC_ANALYZE? Then we don't have to argue about whether CODEANALYZE is one word or two :-)

@@ +219,4 @@
>      # 4114 same type qualifier used more than once
>      # 4133 'type' : incompatible types - from 'type1' to 'type2'
>      set(WARNINGS_ERRORS "4002 4003 4013 4028 4031 4047 4114 4133")
> +    if(DBUS_MSVC_CODEANALYZE AND MSVC_VERSION GREATER 1600 AND ${CMAKE_BUILD_TYPE} STREQUAL "Debug")

I don't see much point in conditioning this on CMAKE_BUILD_TYPE==Debug any more, if it's off by default anyway.

::: dbus/dbus-macros.h
@@ +105,5 @@
> + * static inline returnvalue _DBUS_WARN_UNUSED_RESULT functionName();
> + *
> + * does not work with MSVC, produces compiling errors:
> + * DBUS_PRIVATE_EXPORT returnvalue functionName _DBUS_WARN_UNUSED_RESULT ();
> + * DBUS_PRIVATE_EXPORT returnvalue functionName() _DBUS_WARN_UNUSED_RESULT;

Thanks for testing all these. I think this could be summarized as something like:

"""
This macro is used in function declarations. Unlike gcc-specific attributes, to avoid compilation failure with MSVC it must appear somewhere before the function name in the declaration. Our preferred coding style is to place it before the return type, for example

DBUS_PRIVATE_EXPORT _DBUS_WARN_UNUSED_RESULT
dbus_bool_t _dbus_user_database_lock_system (void);
"""

That way, we are documenting both the requirement (must be somewhere before the function name) and the coding-style recommendation (should be before the return type).

@@ +123,5 @@
>  /** @def _DBUS_GNUC_NORETURN
>   * used to tell gcc about functions that never return, such as _dbus_abort()
>   */
> +/** @def _DBUS_WARN_UNUSED_RESULT
> + * used to tell gcc and msvc about functions whose result must be used

Please combine this doc-comment with the comment above, something like this:

/** @def _DBUS_WARN_UNUSED_RESULT
 *
 * An attribute for functions whose result must be checked by the caller.
 *
 * This macro is used in function declarations. [etc.]
 */
#if defined(_MSC_VER) && ...
#define ...
#elif ... [etc.]

::: dbus/dbus-userdb.h
@@ +94,4 @@
>  DBUS_PRIVATE_EXPORT
>  DBusUserDatabase* _dbus_user_database_get_system    (void);
>  DBUS_PRIVATE_EXPORT
> +dbus_bool_t       _dbus_user_database_lock_system   (void) _DBUS_WARN_UNUSED_RESULT;

To be consistent with portable and Windows-specific code, and to avoid reviewers having to think about whether they are looking at portable, Windows-specific or Unix-specific code as much as possible, please move _DBUS_WARN_UNUSED_RESULT onto the line with DBUS_PRIVATE_EXPORT.
Comment 13 Daniel Wendt 2018-03-15 09:54:53 UTC
Created attachment 138126 [details] [review]
Enable "unused result" warning for MSVC Compiler

patch update

I also updated the Readme.cmake
Comment 14 Simon McVittie 2018-03-15 12:22:34 UTC
Comment on attachment 138126 [details] [review]
Enable "unused result" warning for MSVC Compiler

Review of attachment 138126 [details] [review]:
-----------------------------------------------------------------

Looks good to me!

::: README.cmake
@@ +166,5 @@
>  DBUS_BUILD_X11:BOOL=ON
>  
> +MSVC only (Visual Studio >= 2012):
> +// Enable code analyzing for MSVC compiler: /analyze
> +DBUS_MSVC_ANALYZE:BOOL=OFF

Thanks, I always forget to update this file :-)
Comment 15 Simon McVittie 2018-03-15 12:29:28 UTC
Comment on attachment 138126 [details] [review]
Enable "unused result" warning for MSVC Compiler

Review of attachment 138126 [details] [review]:
-----------------------------------------------------------------

What version of dbus did you base this patch on? It doesn't seem to apply cleanly to git master with `git am`.

New feature changes should be done on the master branch. Older branches like dbus-1.12 and dbus-1.10 are bugfix-only.

I'll attach a version that's been rebased on master for someone who has MSVC to test.
Comment 16 Simon McVittie 2018-03-15 12:38:29 UTC
Created attachment 138129 [details] [review]
Enable "unused result" warning for Visual Studio >= 2012 (MSVC 11.0)

From: Daniel Wendt

The _Must_inspect_result_ annotation is documented to be used in both
the declaration and implementation, but in testing with the MSVC 2012
compiler it appears to be sufficient to use the annotation only in the
declaration to get a compiler warning, as with the GCC compiler.
So the annotation is not necessary in the C implementation.
                                                                         
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=105460
[smcv: Rebase dbus-sysdeps.h changes on master]
[smcv: Clarify commit message]
Reviewed-by: Simon McVittie <smcv@collabora.com>

---

Someone with MSVC should test this. Also available on my Github repository: https://github.com/smcv/dbus/commits/must-inspect-result-105460

CI in progress with various gcc-based configurations: https://travis-ci.org/smcv/dbus/builds/353801680

One day I'd like to have similar CI for CMake+MSVC+Windows in AppVeyor or similar, but I never finished working out how to get suitable versions of libexpat and GLib installed on an AppVeyor CI worker, so we don't have that. appveyor.yml contributions welcome!
Comment 17 Daniel Wendt 2018-03-15 13:16:16 UTC
(In reply to Simon McVittie from comment #15)
> Comment on attachment 138126 [details] [review] [review]
> Enable "unused result" warning for MSVC Compiler
> 
> Review of attachment 138126 [details] [review] [review]:
> -----------------------------------------------------------------
> 
> What version of dbus did you base this patch on? It doesn't seem to apply
> cleanly to git master with `git am`.
> 
> New feature changes should be done on the master branch. Older branches like
> dbus-1.12 and dbus-1.10 are bugfix-only.
> 
> I'll attach a version that's been rebased on master for someone who has MSVC
> to test.

Sorry, that was my fault.

I just tested the rebased patch. It works with and without the /analyze option :-)
Comment 18 Simon McVittie 2018-03-15 19:54:04 UTC
(In reply to Simon McVittie from comment #16)
> One day I'd like to have similar CI for CMake+MSVC+Windows in AppVeyor or
> similar

Bug #105521
Comment 19 Simon McVittie 2018-03-15 19:58:44 UTC
Fixed in git for 1.13.4

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.