public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
From: Florian Weimer <fweimer@redhat.com>
To: Martin Sebor <msebor@gmail.com>
Cc: Martin Sebor via Libc-alpha <libc-alpha@sourceware.org>,
	 Joseph Myers <joseph@codesourcery.com>
Subject: Re: [PATCH] add support for -Wmismatched-dealloc
Date: Mon, 11 Jan 2021 10:13:21 +0100	[thread overview]
Message-ID: <87czybsuoe.fsf@oldenburg2.str.redhat.com> (raw)
In-Reply-To: <ee04d104-e46e-1501-ce96-ee7f9b3fd322@gmail.com> (Martin Sebor's message of "Mon, 4 Jan 2021 16:18:07 -0700")

* Martin Sebor:

> I don't like the alias hack either.  Adding a built-in is possible
> but it's late in GCC stage 3 and I'm doubtful the change would be
> accepted before the Glibc deadline (that's this week, right?)

I think we still have some time.

One problem is that the annotations do not permit diagnosing memory
leaks: realloc is a deallocator for malloc, xfclose is one for fopen,
and so on.  But the annotations do not capture this.  So if they are
used for diagnosing leaks, false positives will be a result.  Listing
all potential deallocators in the allocator does not scale.  It also
leads to the problem shown by open_wmemstream.

I think allocators need to assign some sort of pool identifier to
allocated pointers, and deallocators should declare on which pools they
operate.  This would allow adding additional deallocators such as
xfclose.

>> Based on how this patch appears to make both __fclose and fclose
>> acceptable as a deallocator, GCC resolves redirects as part of the
>> matching check.  I wonder if this constrains the usefulness of the
>> attribute in some way.  I can imagine situations where at the source
>> level, different deallocators should be used (say to support debugging
>> builds), but release builds redirect different deallocators to the same
>> implementation.
>
> The attribute doesn't do anything special with aliases (it was
> just a way to get around the problem with functions not being
> declared in some headers).

But it has to do something with them, otherwise __fclose and fclose are
not the same deallocator and thus different functions.

> diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h
> index 5fb6e309be..21e6177fac 100644
> --- a/misc/sys/cdefs.h
> +++ b/misc/sys/cdefs.h
> @@ -569,6 +569,17 @@ _Static_assert (0, "IEEE 128-bits long double requires redirection on this platf
>  #  define __attr_access(x)
>  #endif
>  
> +#if __GNUC_PREREQ (11, 0)
> +/* Designates dealloc as a function to call to deallocate objects
> +   allocated by the declared function.  */
> +# define __attr_dealloc(dealloc, argno) \
> +    __attribute__ ((__malloc__ (dealloc, argno)))
> +# define __attr_dealloc_free __attr_dealloc (__builtin_free, 1)
> +#else
> +# define __attr_dealloc(x)
> +# define __attr_dealloc_free
> +#endif

If the GCC attribute is called “malloc”, the macro name should reflect
that.  I think it would make sense to make __attribute_malloc__
redundant, so that the headers contain only one of the two attributes
per declaration.  The new macro could expand to the argument-less
version for older GCC versions.

> diff --git a/libio/tst-freopen.c b/libio/tst-freopen.c
> index baa13166fe..c4df29d171 100644
> --- a/libio/tst-freopen.c
> +++ b/libio/tst-freopen.c
> @@ -81,6 +81,36 @@ do_test_basic (void)
>    fclose (f);
>  }
>  
> +#if defined __GNUC__ && __GNUC__ >= 11
> +#pragma GCC diagnostic push
> +#pragma GCC diagnostic error "-Wmismatched-dealloc"
> +#endif

Please add a comment referencing the fclose in the test below.

> +  /* This shouldn't trigger -Wmismatched-dealloc.  */
> +  fclose (f1);

> +#if defined __GNUC__ && __GNUC__ >= 11
> +# pragma GCC diagnostic pop
> +#endif

Likewise.

> diff --git a/libio/tst-wmemstream1.c b/libio/tst-wmemstream1.c
> index f8b308bc6c..8a0e253862 100644
> --- a/libio/tst-wmemstream1.c
> +++ b/libio/tst-wmemstream1.c
> @@ -1,5 +1,40 @@
>  #include <wchar.h>
>  
> +/* Verify that calling fclose on the result of open_wmemstream doesn't
> +   trigger GCC -Wmismatched-dealloc with fclose forward-declared and
> +   without <stdio.h> included first (it is included later, in.
> +   "tst-memstream1.c").  */
> +
> +extern int fclose (FILE*);
> +
> +#if defined __GNUC__ && __GNUC__ >= 11
> +#pragma GCC diagnostic push
> +#pragma GCC diagnostic error "-Wmismatched-dealloc"
> +#endif

Likewise.

> +#if defined __GNUC__ && __GNUC__ >= 11
> +# pragma GCC diagnostic pop
> +#endif

Likewise.

> diff --git a/libio/tst-wmemstream5.c b/libio/tst-wmemstream5.c
> new file mode 100644
> index 0000000000..64461dbe48
> --- /dev/null
> +++ b/libio/tst-wmemstream5.c
> @@ -0,0 +1,40 @@

Missing file header.

> +#include <wchar.h>
> +
> +/* Verify that calling fclose on the result of open_wmemstream doesn't
> +   trigger GCC -Wmismatched-dealloc with fclose forward-declared and
> +   without <stdio.h> included in the same translation unit.  */
> +
> +extern int fclose (FILE*);
> +
> +#if defined __GNUC__ && __GNUC__ >= 11
> +#pragma GCC diagnostic push
> +#pragma GCC diagnostic error "-Wmismatched-dealloc"
> +#endif

Likewise.

> diff --git a/stdlib/stdlib.h b/stdlib/stdlib.h
> index 3aa27a9d25..f88f8e55b3 100644
> --- a/stdlib/stdlib.h
> +++ b/stdlib/stdlib.h

>  #if defined __USE_MISC || defined __USE_XOPEN_EXTENDED
> @@ -798,7 +804,8 @@ extern char *canonicalize_file_name (const char *__name)
>     ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars,
>     returns the name in RESOLVED.  */
>  extern char *realpath (const char *__restrict __name,
> -		       char *__restrict __resolved) __THROW __wur;
> +		       char *__restrict __resolved) __THROW
> +     __attr_dealloc_free __wur;
>  #endif

realpath only returns a pointer to the heap if RESOLVED is null, so the
annotation is wrong here.

> diff --git a/wcsmbs/wchar.h b/wcsmbs/wchar.h
> index 9cf8b05a87..e31734158c 100644
> --- a/wcsmbs/wchar.h
> +++ b/wcsmbs/wchar.h
> @@ -151,7 +151,8 @@ extern size_t wcsxfrm_l (wchar_t *__s1, const wchar_t *__s2,
>  			 size_t __n, locale_t __loc) __THROW;
>  
>  /* Duplicate S, returning an identical malloc'd string.  */
> -extern wchar_t *wcsdup (const wchar_t *__s) __THROW __attribute_malloc__;
> +extern wchar_t *wcsdup (const wchar_t *__s) __THROW
> +  __attribute_malloc__ __attr_dealloc_free;
>  #endif
>  
>  /* Find the first occurrence of WC in WCS.  */
> @@ -562,9 +563,23 @@ extern wchar_t *wcpncpy (wchar_t *__restrict __dest,
>  /* Wide character I/O functions.  */
>  
>  #if defined __USE_XOPEN2K8 || __GLIBC_USE (LIB_EXT2)
> +# ifndef __attr_dealloc_fclose
> +#   if defined __has_builtin
> +#     if __has_builtin (__builtin_fclose)
> +/* If the attribute macro hasn't been defined yet (by <stdio.h>) and
> +   fclose is a built-in, use it.  */
> +#      define __attr_dealloc_fclose __attr_dealloc (__builtin_fclose, 1)
> +#     endif
> +#   endif
> +# endif
> +# ifndef __attr_dealloc_fclose
> +#  define __attr_dealloc_fclose /* empty */
> +# endif
> +
>  /* Like OPEN_MEMSTREAM, but the stream is wide oriented and produces
>     a wide character string.  */
> -extern __FILE *open_wmemstream (wchar_t **__bufloc, size_t *__sizeloc) __THROW;
> +extern __FILE *open_wmemstream (wchar_t **__bufloc, size_t *__sizeloc) __THROW
> +  __attribute_malloc__ __attr_dealloc_fclose;
>  #endif
>  
>  #if defined __USE_ISOC95 || defined __USE_UNIX98

Does this mean that if one includes <wchar.h> first and then <stdio.h>
to get the declaration of fclose, fclose is not registered as a
deallocator for open_wmemstream?

Maybe it is possible to redeclare open_wmemstream in <stdio.h> if
<wchar.h> has already been included?

Thanks,
Florian
-- 
Red Hat GmbH, https://de.redhat.com/ , Registered seat: Grasbrunn,
Commercial register: Amtsgericht Muenchen, HRB 153243,
Managing Directors: Charles Cachera, Brian Klemm, Laurie Krebs, Michael O'Neill


  parent reply	other threads:[~2021-01-11  9:13 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-08 22:52 Martin Sebor
2020-12-09  0:07 ` Joseph Myers
2020-12-12  2:25   ` Martin Sebor
2020-12-14 21:39     ` Martin Sebor
2020-12-14 22:16       ` Florian Weimer
2020-12-15  1:01       ` Joseph Myers
2020-12-15 16:52         ` Martin Sebor
2020-12-27 23:13           ` Martin Sebor
2021-01-04 15:56             ` Ping: " Martin Sebor
2021-01-04 16:07             ` Florian Weimer
2021-01-04 16:18               ` Martin Sebor
2021-01-04 16:57                 ` Florian Weimer
2021-01-04 23:18                   ` Martin Sebor
2021-01-10 20:42                     ` Ping: " Martin Sebor
2021-01-11  9:13                     ` Florian Weimer [this message]
2021-01-12  0:00                       ` Martin Sebor
2021-01-12  0:01                       ` Martin Sebor
2021-01-12  8:59                         ` Florian Weimer
2021-01-19  1:08                           ` Martin Sebor
2021-01-19 16:54                           ` David Malcolm
2021-01-22 21:26                         ` DJ Delorie
2021-01-25 10:56                         ` Florian Weimer
2021-01-25 11:31                         ` Florian Weimer
2021-04-23  0:00                         ` Martin Sebor
2021-05-06 23:54                           ` Martin Sebor
2021-05-13 21:49                             ` Martin Sebor
2021-05-16 21:25                               ` Martin Sebor

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87czybsuoe.fsf@oldenburg2.str.redhat.com \
    --to=fweimer@redhat.com \
    --cc=joseph@codesourcery.com \
    --cc=libc-alpha@sourceware.org \
    --cc=msebor@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).