Re: incorrect use of 'pure' attribute
Bruno Haible via Gnulib discussion list <[email protected]>
| Newsgroups | gmane.comp.lib.gnulib.bugs |
|---|---|
| Message-ID | <3146070.o7ts2hSHzF@cagnes> |
Hi Arsen,
In <https://lists.gnu.org/archive/html/bug-gettext/2026-08/msg00000.html> you
write:
> Pure functions cannot have any observable effects other than their
> return value. Thus, it is not valid for a pure function to have an
> out-parameter.
> ...
> Please, when you get the chance, audit the usages of _GL_ATTRIBUTE_PURE
> to check whether marked-pure functions have out-params.
Thank you for the suggestion. Just did an audit of Gnulib:
- There are indeed 6 functions marked 'pure' but which have out parameters.
They need to be marked 'reproducible', not 'pure'.
- There are also a couple of functions marked 'pure' where it is not
immediately clear from the prototype whether these have out parameters.
Fixed through these two patches:
2026-08-07 Bruno Haible <[email protected]>
Fix incorrect use of _GL_ATTRIBUTE_PURE.
Reported by Arsen Arsenović <[email protected]> in
<https://lists.gnu.org/archive/html/bug-gettext/2026-08/msg00000.html>.
* lib/gl_array_omap.c (gl_array_search, gl_array_search_atleast): Use
attribute _GL_ATTRIBUTE_REPRODUCIBLE instead of attribute
_GL_ATTRIBUTE_PURE.
* lib/gl_array_oset.c (gl_array_search_atleast): Likewise.
* lib/gl_hash_map.c (gl_hash_search): Likewise.
* lib/gl_linkedhash_map.c (gl_linkedhash_search): Likewise.
* lib/modechange.h (mode_adjust): Likewise.
2026-08-07 Bruno Haible <[email protected]>
Clarify that "pure" functions don't have out parameters.
* lib/acl-internal.h (acl_nontrivial, acl_ace_nontrivial,
aclv_nontrivial): Make the 'entries' parameter a const pointer.
* lib/acl-internal.c (acl_nontrivial, acl_ace_nontrivial,
aclv_nontrivial): Likewise.
* lib/dfa.c (state_separate_contexts): Make the 'd' parameter a const
pointer.
* lib/dirent.in.h (alphasort): Clarify prototype.
* lib/fpending.h (__fpending): Likewise.
* lib/freadable.h (freadable): Likewise.
* lib/freadahead.h (freadahead): Likewise.
* lib/freading.h (freading): Likewise.
* lib/fwritable.h (fwritable): Likewise.
* lib/fwriting.h (fwriting): Likewise.
0001-Clarify-that-pure-functions-don-t-have-out-parameter.patch
(text/x-patch, 10.4 KB)
From 2d7434acbbb79519c266b778aba858f22e09697d Mon Sep 17 00:00:00 2001 From: Bruno Haible <[email protected]> Date: Sat, 8 Aug 2026 00:04:54 +0200 Subject: [PATCH 1/2] Clarify that "pure" functions don't have out parameters. * lib/acl-internal.h (acl_nontrivial, acl_ace_nontrivial, aclv_nontrivial): Make the 'entries' parameter a const pointer. * lib/acl-internal.c (acl_nontrivial, acl_ace_nontrivial, aclv_nontrivial): Likewise. * lib/dfa.c (state_separate_contexts): Make the 'd' parameter a const pointer. * lib/dirent.in.h (alphasort): Clarify prototype. * lib/fpending.h (__fpending): Likewise. * lib/freadable.h (freadable): Likewise. * lib/freadahead.h (freadahead): Likewise. * lib/freading.h (freading): Likewise. * lib/fwritable.h (fwritable): Likewise. * lib/fwriting.h (fwriting): Likewise. --- ChangeLog | 17 +++++++++++++++++ lib/acl-internal.c | 22 +++++++++++----------- lib/acl-internal.h | 10 +++++----- lib/dfa.c | 2 +- lib/dirent.in.h | 2 +- lib/fpending.h | 2 +- lib/freadable.h | 2 +- lib/freadahead.h | 2 +- lib/freading.h | 2 +- lib/fwritable.h | 2 +- lib/fwriting.h | 2 +- 11 files changed, 41 insertions(+), 24 deletions(-) diff --git a/ChangeLog b/ChangeLog index 521e657631..ec566864ff 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2026-08-07 Bruno Haible <[email protected]> + + Clarify that "pure" functions don't have out parameters. + * lib/acl-internal.h (acl_nontrivial, acl_ace_nontrivial, + aclv_nontrivial): Make the 'entries' parameter a const pointer. + * lib/acl-internal.c (acl_nontrivial, acl_ace_nontrivial, + aclv_nontrivial): Likewise. + * lib/dfa.c (state_separate_contexts): Make the 'd' parameter a const + pointer. + * lib/dirent.in.h (alphasort): Clarify prototype. + * lib/fpending.h (__fpending): Likewise. + * lib/freadable.h (freadable): Likewise. + * lib/freadahead.h (freadahead): Likewise. + * lib/freading.h (freading): Likewise. + * lib/fwritable.h (fwritable): Likewise. + * lib/fwriting.h (fwriting): Likewise. + 2026-08-04 Bruno Haible <[email protected]> readutmp: Add option to make use of wtmpdb. diff --git a/lib/acl-internal.c b/lib/acl-internal.c index 7603abed68..e012cc64bb 100644 --- a/lib/acl-internal.c +++ b/lib/acl-internal.c @@ -159,11 +159,11 @@ acl_default_nontrivial (acl_t acl) Return 1 if the given ACL, consisting of COUNT entries, is non-trivial. Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ int -acl_nontrivial (int count, aclent_t *entries) +acl_nontrivial (int count, aclent_t const *entries) { for (int i = 0; i < count; i++) { - aclent_t *ace = &entries[i]; + aclent_t const *ace = &entries[i]; /* Note: If ace->a_type = USER_OBJ, ace->a_id is the st_uid from stat(). If ace->a_type = GROUP_OBJ, ace->a_id is the st_gid from stat(). @@ -188,7 +188,7 @@ acl_nontrivial (int count, aclent_t *entries) Return 1 if the given ACL, consisting of COUNT entries, is non-trivial. Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ int -acl_ace_nontrivial (int count, ace_t *entries) +acl_ace_nontrivial (int count, ace_t const *entries) { /* The flags in the ace_t structure changed in a binary incompatible way when ACL_NO_TRIVIAL etc. were introduced in <sys/acl.h> version 1.15. @@ -209,7 +209,7 @@ acl_ace_nontrivial (int count, ace_t *entries) /* Running on Solaris 10. */ for (int i = 0; i < count; i++) { - ace_t *ace = &entries[i]; + ace_t const *ace = &entries[i]; /* Note: If ace->a_flags = ACE_OWNER, ace->a_who is the st_uid from stat(). @@ -236,7 +236,7 @@ acl_ace_nontrivial (int count, ace_t *entries) for (int i = 0; i < count; i++) { - ace_t *ace = &entries[i]; + ace_t const *ace = &entries[i]; unsigned int index1; if (ace->a_type == NEW_ACE_ACCESS_ALLOWED_ACE_TYPE) @@ -368,14 +368,14 @@ acl_ace_nontrivial (int count, ace_t *entries) /* Return 1 if the given ACL is non-trivial. Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ int -acl_nontrivial (int count, struct acl_entry *entries) +acl_nontrivial (int count, struct acl_entry const *entries) { if (count > 3) return 1; for (int i = 0; i < count; i++) { - struct acl_entry *ace = &entries[i]; + struct acl_entry const *ace = &entries[i]; if (ace->uid != ACL_NSUSER && ace->gid != ACL_NSGROUP) return 1; @@ -388,11 +388,11 @@ acl_nontrivial (int count, struct acl_entry *entries) /* Return 1 if the given ACL is non-trivial. Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ int -aclv_nontrivial (int count, struct acl *entries) +aclv_nontrivial (int count, struct acl const *entries) { for (int i = 0; i < count; i++) { - struct acl *ace = &entries[i]; + struct acl const *ace = &entries[i]; /* Note: If ace->a_type = USER_OBJ, ace->a_id is the st_uid from stat(). If ace->a_type = GROUP_OBJ, ace->a_id is the st_gid from stat(). @@ -471,11 +471,11 @@ acl_nfs4_nontrivial (nfs4_acl_int_t *a) Return 1 if the given ACL, consisting of COUNT entries, is non-trivial. Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ int -acl_nontrivial (int count, struct acl *entries) +acl_nontrivial (int count, struct acl const *entries) { for (int i = 0; i < count; i++) { - struct acl *ace = &entries[i]; + struct acl const *ace = &entries[i]; /* Note: If ace->a_type = USER_OBJ, ace->a_id is the st_uid from stat(). If ace->a_type = GROUP_OBJ, ace->a_id is the st_gid from stat(). diff --git a/lib/acl-internal.h b/lib/acl-internal.h index eafb4d027f..36be1f657d 100644 --- a/lib/acl-internal.h +++ b/lib/acl-internal.h @@ -156,14 +156,14 @@ extern int acl_default_nontrivial (acl_t); /* Return 1 if the given ACL is non-trivial. Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ -extern int acl_nontrivial (int count, aclent_t *entries) _GL_ATTRIBUTE_PURE; +extern int acl_nontrivial (int count, aclent_t const *entries) _GL_ATTRIBUTE_PURE; # ifdef ACE_GETACL /* Solaris 10 */ /* Test an ACL retrieved with ACE_GETACL. Return 1 if the given ACL, consisting of COUNT entries, is non-trivial. Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ -extern int acl_ace_nontrivial (int count, ace_t *entries) _GL_ATTRIBUTE_PURE; +extern int acl_ace_nontrivial (int count, ace_t const *entries) _GL_ATTRIBUTE_PURE; /* Definitions for when the built executable is executed on Solaris 10 (newer version) or Solaris 11. */ @@ -202,13 +202,13 @@ extern int acl_ace_nontrivial (int count, ace_t *entries) _GL_ATTRIBUTE_PURE; /* Return 1 if the given ACL is non-trivial. Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ -extern int acl_nontrivial (int count, struct acl_entry *entries); +extern int acl_nontrivial (int count, struct acl_entry const *entries); # if HAVE_ACLV_H /* HP-UX >= 11.11 */ /* Return 1 if the given ACL is non-trivial. Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ -extern int aclv_nontrivial (int count, struct acl *entries); +extern int aclv_nontrivial (int count, struct acl const *entries); # endif @@ -226,7 +226,7 @@ extern int acl_nontrivial (struct acl *a); /* Return 1 if the given ACL is non-trivial. Return 0 if it is trivial, i.e. equivalent to a simple stat() mode. */ -extern int acl_nontrivial (int count, struct acl *entries); +extern int acl_nontrivial (int count, struct acl const *entries); # endif diff --git a/lib/dfa.c b/lib/dfa.c index 13dae682ed..b84d86feef 100644 --- a/lib/dfa.c +++ b/lib/dfa.c @@ -2402,7 +2402,7 @@ charclass_context (struct dfa const *dfa, charclass const *c) in the complement set will have the same follow set. */ static int _GL_ATTRIBUTE_PURE -state_separate_contexts (struct dfa *d, position_set const *s) +state_separate_contexts (struct dfa const *d, position_set const *s) { int separate_contexts = 0; diff --git a/lib/dirent.in.h b/lib/dirent.in.h index 9198c1d308..0a32637b8a 100644 --- a/lib/dirent.in.h +++ b/lib/dirent.in.h @@ -367,7 +367,7 @@ _GL_WARN_ON_USE (scandir, "scandir is unportable - " /* Compare two 'struct dirent' entries alphabetically. */ # if !@HAVE_ALPHASORT@ _GL_FUNCDECL_SYS (alphasort, int, - (const struct dirent **, const struct dirent **), + (const struct dirent * /*const*/ *, const struct dirent * /*const*/ *), _GL_ATTRIBUTE_PURE _GL_ARG_NONNULL ((1, 2))); # endif diff --git a/lib/fpending.h b/lib/fpending.h index aeb1d9310d..dd4e74b750 100644 --- a/lib/fpending.h +++ b/lib/fpending.h @@ -36,7 +36,7 @@ extern "C" { #if !HAVE_DECL___FPENDING -size_t __fpending (FILE *) _GL_ATTRIBUTE_PURE; +size_t __fpending (FILE /*const*/ *) _GL_ATTRIBUTE_PURE; #endif diff --git a/lib/freadable.h b/lib/freadable.h index ceaa7ef34f..d0c1faf593 100644 --- a/lib/freadable.h +++ b/lib/freadable.h @@ -40,7 +40,7 @@ extern "C" { # endif -extern bool freadable (FILE *stream) _GL_ATTRIBUTE_PURE; +extern bool freadable (FILE /*const*/ *stream) _GL_ATTRIBUTE_PURE; # ifdef __cplusplus } diff --git a/lib/freadahead.h b/lib/freadahead.h index 4f441ae454..ad5c476dbe 100644 --- a/lib/freadahead.h +++ b/lib/freadahead.h @@ -43,7 +43,7 @@ extern "C" { # endif -extern size_t freadahead (FILE *stream) _GL_ATTRIBUTE_PURE; +extern size_t freadahead (FILE /*const*/ *stream) _GL_ATTRIBUTE_PURE; # ifdef __cplusplus } diff --git a/lib/freading.h b/lib/freading.h index 3d75d75e3a..62e6cbda1b 100644 --- a/lib/freading.h +++ b/lib/freading.h @@ -50,7 +50,7 @@ extern "C" { # endif -extern bool freading (FILE *stream) _GL_ATTRIBUTE_PURE; +extern bool freading (FILE /*const*/ *stream) _GL_ATTRIBUTE_PURE; # ifdef __cplusplus } diff --git a/lib/fwritable.h b/lib/fwritable.h index 23888e50fb..ba9b4cd9ee 100644 --- a/lib/fwritable.h +++ b/lib/fwritable.h @@ -40,7 +40,7 @@ extern "C" { # endif -extern bool fwritable (FILE *stream) _GL_ATTRIBUTE_PURE; +extern bool fwritable (FILE /*const*/ *stream) _GL_ATTRIBUTE_PURE; # ifdef __cplusplus } diff --git a/lib/fwriting.h b/lib/fwriting.h index b42d999df8..a88e50a73b 100644 --- a/lib/fwriting.h +++ b/lib/fwriting.h @@ -51,7 +51,7 @@ extern "C" { # endif -extern bool fwriting (FILE *stream) _GL_ATTRIBUTE_PURE; +extern bool fwriting (FILE /*const*/ *stream) _GL_ATTRIBUTE_PURE; # ifdef __cplusplus } -- 2.53.0
0002-Fix-incorrect-use-of-_GL_ATTRIBUTE_PURE.patch
(text/x-patch, 4.2 KB)
From f9b4c8013b1880e7b3953f3ba6f233ba5b0cd8c5 Mon Sep 17 00:00:00 2001 From: Bruno Haible <[email protected]> Date: Sat, 8 Aug 2026 00:09:48 +0200 Subject: [PATCH 2/2] Fix incorrect use of _GL_ATTRIBUTE_PURE. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported by Arsen Arsenović <[email protected]> in <https://lists.gnu.org/archive/html/bug-gettext/2026-08/msg00000.html>. * lib/gl_array_omap.c (gl_array_search, gl_array_search_atleast): Use attribute _GL_ATTRIBUTE_REPRODUCIBLE instead of attribute _GL_ATTRIBUTE_PURE. * lib/gl_array_oset.c (gl_array_search_atleast): Likewise. * lib/gl_hash_map.c (gl_hash_search): Likewise. * lib/gl_linkedhash_map.c (gl_linkedhash_search): Likewise. * lib/modechange.h (mode_adjust): Likewise. --- ChangeLog | 13 +++++++++++++ lib/gl_array_omap.c | 4 ++-- lib/gl_array_oset.c | 2 +- lib/gl_hash_map.c | 2 +- lib/gl_linkedhash_map.c | 2 +- lib/modechange.h | 2 +- 6 files changed, 19 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index ec566864ff..1e26e6875e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2026-08-07 Bruno Haible <[email protected]> + + Fix incorrect use of _GL_ATTRIBUTE_PURE. + Reported by Arsen Arsenović <[email protected]> in + <https://lists.gnu.org/archive/html/bug-gettext/2026-08/msg00000.html>. + * lib/gl_array_omap.c (gl_array_search, gl_array_search_atleast): Use + attribute _GL_ATTRIBUTE_REPRODUCIBLE instead of attribute + _GL_ATTRIBUTE_PURE. + * lib/gl_array_oset.c (gl_array_search_atleast): Likewise. + * lib/gl_hash_map.c (gl_hash_search): Likewise. + * lib/gl_linkedhash_map.c (gl_linkedhash_search): Likewise. + * lib/modechange.h (mode_adjust): Likewise. + 2026-08-07 Bruno Haible <[email protected]> Clarify that "pure" functions don't have out parameters. diff --git a/lib/gl_array_omap.c b/lib/gl_array_omap.c index be1b9151ad..0fda12ce7a 100644 --- a/lib/gl_array_omap.c +++ b/lib/gl_array_omap.c @@ -110,7 +110,7 @@ gl_array_indexof (gl_omap_t map, const void *key) return (size_t)(-1); } -static bool _GL_ATTRIBUTE_PURE +static bool _GL_ATTRIBUTE_REPRODUCIBLE gl_array_search (gl_omap_t map, const void *key, const void **valuep) { size_t index = gl_array_indexof (map, key); @@ -123,7 +123,7 @@ gl_array_search (gl_omap_t map, const void *key, const void **valuep) return false; } -static bool _GL_ATTRIBUTE_PURE +static bool _GL_ATTRIBUTE_REPRODUCIBLE gl_array_search_atleast (gl_omap_t map, gl_mapkey_threshold_fn threshold_fn, const void *threshold, diff --git a/lib/gl_array_oset.c b/lib/gl_array_oset.c index 5672e1e4c0..03afec519e 100644 --- a/lib/gl_array_oset.c +++ b/lib/gl_array_oset.c @@ -161,7 +161,7 @@ gl_array_indexof_atleast (gl_oset_t set, return count; } -static bool _GL_ATTRIBUTE_PURE +static bool _GL_ATTRIBUTE_REPRODUCIBLE gl_array_search_atleast (gl_oset_t set, gl_setelement_threshold_fn threshold_fn, const void *threshold, diff --git a/lib/gl_hash_map.c b/lib/gl_hash_map.c index 1598515641..3767b17cae 100644 --- a/lib/gl_hash_map.c +++ b/lib/gl_hash_map.c @@ -95,7 +95,7 @@ gl_hash_size (gl_map_t map) return map->count; } -static bool _GL_ATTRIBUTE_PURE +static bool _GL_ATTRIBUTE_REPRODUCIBLE gl_hash_search (gl_map_t map, const void *key, const void **valuep) { size_t hashcode = diff --git a/lib/gl_linkedhash_map.c b/lib/gl_linkedhash_map.c index fd9e786128..3b85099a60 100644 --- a/lib/gl_linkedhash_map.c +++ b/lib/gl_linkedhash_map.c @@ -120,7 +120,7 @@ gl_linkedhash_size (gl_map_t map) return map->count; } -static bool _GL_ATTRIBUTE_PURE +static bool _GL_ATTRIBUTE_REPRODUCIBLE gl_linkedhash_search (gl_map_t map, const void *key, const void **valuep) { size_t hashcode = diff --git a/lib/modechange.h b/lib/modechange.h index eed2ffb18f..2b5a2c29a1 100644 --- a/lib/modechange.h +++ b/lib/modechange.h @@ -38,7 +38,7 @@ struct mode_change *mode_create_from_ref (const char *) _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE; mode_t mode_adjust (mode_t, bool, mode_t, struct mode_change const *, mode_t *) - _GL_ATTRIBUTE_PURE; + _GL_ATTRIBUTE_REPRODUCIBLE; #ifdef __cplusplus -- 2.53.0