bind.2, mount_setattr.2, openat2.2, perf_event_open.2, pidfd_send_signal.2, recvmmsg.2, seccomp_unotify.2, select_tut.2, sendmmsg.2, set_thread_area.2, sysctl.2, bzero.3, getaddrinfo.3, getaddrinfo_a.3, getutent.3, mbrtowc.3, mbsinit.3, rtime.3, rtnetlink

Message ID 20230105193751.18846-1-alx@kernel.org
State Not applicable
Headers
Series bind.2, mount_setattr.2, openat2.2, perf_event_open.2, pidfd_send_signal.2, recvmmsg.2, seccomp_unotify.2, select_tut.2, sendmmsg.2, set_thread_area.2, sysctl.2, bzero.3, getaddrinfo.3, getaddrinfo_a.3, getutent.3, mbrtowc.3, mbsinit.3, rtime.3, rtnetlink |

Checks

Context Check Description
dj/TryBot-apply_patch fail Patch failed to apply to master at the time it was sent

Commit Message

Alejandro Colomar Jan. 5, 2023, 7:37 p.m. UTC
  bzero(3) is simpler to use, and can avoid silly mistakes that are hard
to spot.  memset(3), while it is necessary in a few very-specific cases,
should be avoided when the memory is to be zeroed.

POSIX and ISO can say otherwise, but it doesn't make any sense to
recommend using memset(3) over bzero(3).

Link: <https://stackoverflow.com/a/17097978/6872717>
Cc: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
Cc: "G. Branden Robinson" <g.branden.robinson@gmail.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
 man2/bind.2              | 2 +-
 man2/mount_setattr.2     | 4 ++--
 man2/openat2.2           | 4 ++--
 man2/perf_event_open.2   | 2 +-
 man2/pidfd_send_signal.2 | 2 +-
 man2/recvmmsg.2          | 2 +-
 man2/seccomp_unotify.2   | 2 +-
 man2/select_tut.2        | 6 +++---
 man2/sendmmsg.2          | 6 +++---
 man2/set_thread_area.2   | 2 +-
 man2/sysctl.2            | 2 +-
 man3/bzero.3             | 4 +---
 man3/getaddrinfo.3       | 4 ++--
 man3/getaddrinfo_a.3     | 2 +-
 man3/getutent.3          | 6 +++---
 man3/mbrtowc.3           | 2 +-
 man3/mbsinit.3           | 2 +-
 man3/rtime.3             | 2 +-
 man3/rtnetlink.3         | 2 +-
 man3/strptime.3          | 2 +-
 man3const/NULL.3const    | 2 +-
 man3type/size_t.3type    | 1 +
 man3type/void.3type      | 1 +
 man7/aio.7               | 2 +-
 man7/netlink.7           | 4 ++--
 man7/unix.7              | 6 +++---
 26 files changed, 38 insertions(+), 38 deletions(-)
  

Comments

Adhemerval Zanella Jan. 5, 2023, 8:48 p.m. UTC | #1
On 05/01/23 16:37, Alejandro Colomar via Libc-alpha wrote:
> bzero(3) is simpler to use, and can avoid silly mistakes that are hard
> to spot.  memset(3), while it is necessary in a few very-specific cases,
> should be avoided when the memory is to be zeroed.
> 
> POSIX and ISO can say otherwise, but it doesn't make any sense to
> recommend using memset(3) over bzero(3).

bzero is deprecated by POSIX.1-2001, removed by POSIX.1-2008, and on glibc 
implementation now calls memset (previously some architecture added ifunc 
redirection to optimized bzero to avoid the extra function call, it was
removed from all architectures). 

Also, GCC for some time also replaces bzero with memset so there is no gain
in actually call bzero (check glibc commit 9403b71ae97e3f1a91c796ddcbb4e6f044434734).
  
Paul Eggert Jan. 5, 2023, 8:55 p.m. UTC | #2
On 2023-01-05 12:48, Adhemerval Zanella Netto via Libc-alpha wrote:
> 
> 
> On 05/01/23 16:37, Alejandro Colomar via Libc-alpha wrote:
>> bzero(3) is simpler to use, and can avoid silly mistakes that are hard
>> to spot.  memset(3), while it is necessary in a few very-specific cases,
>> should be avoided when the memory is to be zeroed.
>>
>> POSIX and ISO can say otherwise, but it doesn't make any sense to
>> recommend using memset(3) over bzero(3).
> 
> bzero is deprecated by POSIX.1-2001, removed by POSIX.1-2008, and on glibc
> implementation now calls memset (previously some architecture added ifunc
> redirection to optimized bzero to avoid the extra function call, it was
> removed from all architectures).
> 
> Also, GCC for some time also replaces bzero with memset so there is no gain
> in actually call bzero (check glibc commit 9403b71ae97e3f1a91c796ddcbb4e6f044434734).

In addition, gcc -Wall warns if you mistakenly pass 0 as memset's 3rd 
arg, which undercuts the argument that bzero avoids silly mistakes.
  
Wilco Dijkstra Jan. 5, 2023, 9:12 p.m. UTC | #3
Hi,

>> bzero is deprecated by POSIX.1-2001, removed by POSIX.1-2008, and on glibc
>> implementation now calls memset (previously some architecture added ifunc
>> redirection to optimized bzero to avoid the extra function call, it was
>> removed from all architectures).
>> 
>> Also, GCC for some time also replaces bzero with memset so there is no gain
>> in actually call bzero (check glibc commit 9403b71ae97e3f1a91c796ddcbb4e6f044434734).

Agreed, there is no benefit from using it, and certainly no reason to try to undo
its removal. We should promote standards, not try to subvert them...
A more productive way would be to propose new functions to the C/C++
committees.

> In addition, gcc -Wall warns if you mistakenly pass 0 as memset's 3rd 
> arg, which undercuts the argument that bzero avoids silly mistakes.

Also I think GCC should give a deprecated/obsolete warning (or perhaps error?)
when using bzero, bcmp, bcopy, index, rindex etc so people can start removing
the few remaining uses from ancient code.

Cheers,
Wilco
  
Alejandro Colomar Jan. 5, 2023, 9:33 p.m. UTC | #4
Hi Wilco, Paul, and Adhemerval,

On 1/5/23 22:12, Wilco Dijkstra wrote:
> Hi,
> 
>>> bzero is deprecated by POSIX.1-2001, removed by POSIX.1-2008, and on glibc
>>> implementation now calls memset (previously some architecture added ifunc
>>> redirection to optimized bzero to avoid the extra function call, it was
>>> removed from all architectures).

Sure, POSIX prefers memset(3).  But why?  "Because it is standard" isn't a valid 
reasoning, because POSIX decides what is standard, so it would be circular 
reasoning.

Anyway, the fact that libc doesn't provide it is not a problem for callers: the 
compiler provides it.  And even if the compiler dropped support, one can write 
it with a one liner, which even POSIX once recommended[1]:

     #define bzero(b,len) (memset((b), '\0', (len)), (void) 0)


[1]:  <https://pubs.opengroup.org/onlinepubs/009695399/functions/bzero.html>

>>>
>>> Also, GCC for some time also replaces bzero with memset so there is no gain
>>> in actually call bzero (check glibc commit 9403b71ae97e3f1a91c796ddcbb4e6f044434734).

No gain in generated code; but there's a gain in source code: less cognitive 
load.  Instead of 3 arguments, the order of which is not easy to remember, the 
programmer only needs to care about 2, and they're obvious.

> 
> Agreed, there is no benefit from using it, and certainly no reason to try to undo
> its removal. We should promote standards, not try to subvert them...

I generally promote POSIX; but at the same time I'm not blindly following it, 
and when its decisions don't make sense I will deviate from it.

> A more productive way would be to propose new functions to the C/C++
> committees.

I believe in existing practice as a way of improving the standards.  IMO, it 
doesn't make sense to ask POSIX to add a function, if no-one uses it.

So I think it should be fine to recommend using a well designed API, and use 
that as a way to increase its use, hopefully resulting long-term in a 
reincorporation to POSIX.

I also defend mempcpy(3) over any POSIX or ISO alternatives.  It's simply 
superior to the alternatives, and POSIX should standardize it (and I'd say even 
deprecate memcpy(3), which is a misdesigned API, but I won't go that far for now).

> 
>> In addition, gcc -Wall warns if you mistakenly pass 0 as memset's 3rd
>> arg, which undercuts the argument that bzero avoids silly mistakes.
> 
> Also I think GCC should give a deprecated/obsolete warning (or perhaps error?)
> when using bzero, bcmp, bcopy, index, rindex etc so people can start removing
> the few remaining uses from ancient code.

There are many users of bzero(3) in the wild, and it is a fine API from a 
usability point of view.  Not being promoted by POSIX or ISO is not enough to 
warn about its use.  With that reasoning, we should warn about many GNU 
extensions, and some of them are really fine (so much that many ended up in POSIX).

However, it would be fine to warn about those that are error-prone:

-  bcopy(3)

And also warn about those that have a drop-in replacement in POSIX:

-  bcmp(3)
-  index(3)
-  rindex(3)

I would endorse warning about those.  BTW, I'll rewrite the bcmp(3) page to say 
it's identical to memcmp(3).

> 
> Cheers,
> Wilco

Cheers,

Alex

-- 
<http://www.alejandro-colomar.es/>
  
Alejandro Colomar Jan. 5, 2023, 9:42 p.m. UTC | #5
Hi Paul,

On 1/5/23 21:55, Paul Eggert wrote:
> On 2023-01-05 12:48, Adhemerval Zanella Netto via Libc-alpha wrote:
>>
>>
>> On 05/01/23 16:37, Alejandro Colomar via Libc-alpha wrote:
>>> bzero(3) is simpler to use, and can avoid silly mistakes that are hard
>>> to spot.  memset(3), while it is necessary in a few very-specific cases,
>>> should be avoided when the memory is to be zeroed.
>>>
>>> POSIX and ISO can say otherwise, but it doesn't make any sense to
>>> recommend using memset(3) over bzero(3).
>>
>> bzero is deprecated by POSIX.1-2001, removed by POSIX.1-2008, and on glibc
>> implementation now calls memset (previously some architecture added ifunc
>> redirection to optimized bzero to avoid the extra function call, it was
>> removed from all architectures).
>>
>> Also, GCC for some time also replaces bzero with memset so there is no gain
>> in actually call bzero (check glibc commit 
>> 9403b71ae97e3f1a91c796ddcbb4e6f044434734).
> 
> In addition, gcc -Wall warns if you mistakenly pass 0 as memset's 3rd arg, which 
> undercuts the argument that bzero avoids silly mistakes.

That's a good counterargument for the silly mistakes point.  But the cognitive 
load that programmers need to care about the extra useless argument for no good 
reason is still a problem of the memset(3) API that bszero(3) simply hasn't.

If it's about defending a minimal set of functions that serve the basic purposes 
that programmer may need, I'll prepare a counterargument:

Why does POSIX have strnlen(3)?  strnlen(s, n) is just a shorthand for memchr(s, 
'\0', n);

If the similarity wasn't obvious enough, I'll put them together:

strnlen(p, n)  ----  memchr(p, 0, n)
bzero(p, n)    ----  memset(p, 0, n)

I'd like to get a rationale for why we should promote strnlen(3) but not 
bzero(3) that doesn't reduce to "it is standard".  Why would the standard cover 
on and not the other?

Cheers,

Alex

> 

-- 
<http://www.alejandro-colomar.es/>
  
Wilco Dijkstra Jan. 5, 2023, 11:30 p.m. UTC | #6
Hi Alex,

> That's a good counterargument for the silly mistakes point.  But the cognitive 
> load that programmers need to care about the extra useless argument for no good 
> reason is still a problem of the memset(3) API that bszero(3) simply hasn't.

There is also the cognitive load of having to learn yet another interface. There is
also the overhead of libraries having to implement yet another function. Plus
compilers optimizing it. Maintaining, testing, and documenting it. And so on.

Why would anyone invest all this effort if there isn't a significant gain after all that?
So a new interface must be significantly and measurably better to be worth all this
work. More than 20 years ago people decided that it is not worth it for bzero and
various other functions given they have almost identical equivalents in the C
standard which were already supported on all targets and in most cases better
optimized. One of the most common portability issues was the lack of bcopy and
bzero which lead to hacky and buggy workarounds.

> I'd like to get a rationale for why we should promote strnlen(3) but not 
> bzero(3) that doesn't reduce to "it is standard".  Why would the standard cover 
> on and not the other?

Firstly memchr is not an equivalent of strnlen, it would be something like:

tmp = memchr (p, '\0', n);
len = (tmp == NULL) ? n : tmp - p;

Be honest, would you really prefer writing that over strnlen (p)?

And neither does memchr have the same performance. Searching for zero is typically
faster than searching for any character, so a well optimized strnlen should beat memchr.
Note that doesn't mean it is unreasonable for a generic strnlen to call memchr - one
typically starts optimizing the C standard functions, and generic string functions use
those as primitives if no optimized version is available (yet).

An optimized bzero function wouldn't be faster than memset - while you might need
a check for zero (or duplicate the input byte), that is a small overhead that is hard to
measure on modern hardware. We had a proposal for adding memzero/memclr/
memclear/memset0/memset_zero/... a while back so I measured it and concluded
there is just no benefit. A few decades ago I was programming on an 8MHz in-order
core and every single cycle&byte mattered then, but it's a very different world today!

Cheers,
Wilco
  
Christian Brauner Jan. 6, 2023, 10:55 a.m. UTC | #7
On Thu, Jan 05, 2023 at 05:48:08PM -0300, Adhemerval Zanella Netto via Libc-alpha wrote:
> 
> 
> On 05/01/23 16:37, Alejandro Colomar via Libc-alpha wrote:
> > bzero(3) is simpler to use, and can avoid silly mistakes that are hard
> > to spot.  memset(3), while it is necessary in a few very-specific cases,
> > should be avoided when the memory is to be zeroed.
> > 
> > POSIX and ISO can say otherwise, but it doesn't make any sense to
> > recommend using memset(3) over bzero(3).
> 
> bzero is deprecated by POSIX.1-2001, removed by POSIX.1-2008, and on glibc 
> implementation now calls memset (previously some architecture added ifunc 
> redirection to optimized bzero to avoid the extra function call, it was
> removed from all architectures). 
> 
> Also, GCC for some time also replaces bzero with memset so there is no gain
> in actually call bzero (check glibc commit 9403b71ae97e3f1a91c796ddcbb4e6f044434734).

This whole s/memset/bzero/g patchset seems like a lot of busywork that
doesn't seem to bring any real benefit. I would agree with the rest here
and just drop this. That's just going to add confusion to the manpages.
  

Patch

diff --git a/man2/bind.2 b/man2/bind.2
index 350a2f7e1..33d580f90 100644
--- a/man2/bind.2
+++ b/man2/bind.2
@@ -243,7 +243,7 @@  .SH EXAMPLES
     if (sfd == \-1)
         handle_error("socket");
 
-    memset(&my_addr, 0, sizeof(my_addr));
+    bzero(&my_addr, sizeof(my_addr));
     my_addr.sun_family = AF_UNIX;
     strncpy(my_addr.sun_path, MY_SOCK_PATH,
             sizeof(my_addr.sun_path) \- 1);
diff --git a/man2/mount_setattr.2 b/man2/mount_setattr.2
index cfa1a6e5a..d3c786609 100644
--- a/man2/mount_setattr.2
+++ b/man2/mount_setattr.2
@@ -878,13 +878,13 @@  .SS Extensibility
 .in
 .PP
 Alternatively, the structure can be zero-filled using
-.BR memset (3)
+.BR bzero (3)
 or similar functions:
 .PP
 .in +4n
 .EX
 struct mount_attr attr;
-memset(&attr, 0, sizeof(attr));
+bzero(&attr, sizeof(attr));
 attr.attr_set = MOUNT_ATTR_RDONLY;
 attr.attr_clr = MOUNT_ATTR_NODEV;
 .EE
diff --git a/man2/openat2.2 b/man2/openat2.2
index 19693cd8c..59d515d89 100644
--- a/man2/openat2.2
+++ b/man2/openat2.2
@@ -558,13 +558,13 @@  .SS Extensibility
 .in
 .PP
 or explicitly using
-.BR memset (3)
+.BR bzero (3)
 or similar:
 .PP
 .in +4n
 .EX
 struct open_how how;
-memset(&how, 0, sizeof(how));
+bzero(&how, sizeof(how));
 how.flags = O_RDWR;
 how.resolve = RESOLVE_IN_ROOT;
 .EE
diff --git a/man2/perf_event_open.2 b/man2/perf_event_open.2
index 8e94fb4ac..29af28bf1 100644
--- a/man2/perf_event_open.2
+++ b/man2/perf_event_open.2
@@ -3761,7 +3761,7 @@  .SH EXAMPLES
     long long               count;
     struct perf_event_attr  pe;
 
-    memset(&pe, 0, sizeof(pe));
+    bzero(&pe, sizeof(pe));
     pe.type = PERF_TYPE_HARDWARE;
     pe.size = sizeof(pe);
     pe.config = PERF_COUNT_HW_INSTRUCTIONS;
diff --git a/man2/pidfd_send_signal.2 b/man2/pidfd_send_signal.2
index 2a60ced93..76544888b 100644
--- a/man2/pidfd_send_signal.2
+++ b/man2/pidfd_send_signal.2
@@ -213,7 +213,7 @@  .SH EXAMPLES
     /* Populate a \(aqsiginfo_t\(aq structure for use with
        pidfd_send_signal(). */
 
-    memset(&info, 0, sizeof(info));
+    bzero(&info, sizeof(info));
     info.si_code = SI_QUEUE;
     info.si_signo = sig;
     info.si_errno = 0;
diff --git a/man2/recvmmsg.2 b/man2/recvmmsg.2
index 63a03bd39..d5d94dc86 100644
--- a/man2/recvmmsg.2
+++ b/man2/recvmmsg.2
@@ -244,7 +244,7 @@  .SS Program source
         exit(EXIT_FAILURE);
     }
 
-    memset(msgs, 0, sizeof(msgs));
+    bzero(msgs, sizeof(msgs));
     for (size_t i = 0; i < VLEN; i++) {
         iovecs[i].iov_base         = bufs[i];
         iovecs[i].iov_len          = BUFSIZE;
diff --git a/man2/seccomp_unotify.2 b/man2/seccomp_unotify.2
index 157fbb94a..9e0d83d4a 100644
--- a/man2/seccomp_unotify.2
+++ b/man2/seccomp_unotify.2
@@ -1838,7 +1838,7 @@  .SS Program source
 
         /* Wait for next notification, returning info in \(aq*req\(aq */
 
-        memset(req, 0, sizes.seccomp_notif);
+        bzero(req, sizes.seccomp_notif);
         if (ioctl(notifyFd, SECCOMP_IOCTL_NOTIF_RECV, req) == \-1) {
             if (errno == EINTR)
                 continue;
diff --git a/man2/select_tut.2 b/man2/select_tut.2
index 9d62db023..75480368c 100644
--- a/man2/select_tut.2
+++ b/man2/select_tut.2
@@ -373,7 +373,7 @@  .SH EXAMPLES
         return \-1;
     }
 
-    memset(&addr, 0, sizeof(addr));
+    bzero(&addr, sizeof(addr));
     addr.sin_port = htons(listen_port);
     addr.sin_family = AF_INET;
     if (bind(lfd, (struct sockaddr *) &addr, sizeof(addr)) == \-1) {
@@ -399,7 +399,7 @@  .SH EXAMPLES
         return \-1;
     }
 
-    memset(&addr, 0, sizeof(addr));
+    bzero(&addr, sizeof(addr));
     addr.sin_port = htons(connect_port);
     addr.sin_family = AF_INET;
 
@@ -508,7 +508,7 @@  .SH EXAMPLES
             int fd;
 
             addrlen = sizeof(client_addr);
-            memset(&client_addr, 0, addrlen);
+            bzero(&client_addr, addrlen);
             fd = accept(h, (struct sockaddr *) &client_addr, &addrlen);
             if (fd == \-1) {
                 perror("accept()");
diff --git a/man2/sendmmsg.2 b/man2/sendmmsg.2
index 4e5475c45..4b284ab34 100644
--- a/man2/sendmmsg.2
+++ b/man2/sendmmsg.2
@@ -201,17 +201,17 @@  .SH EXAMPLES
         exit(EXIT_FAILURE);
     }
 
-    memset(msg1, 0, sizeof(msg1));
+    bzero(msg1, sizeof(msg1));
     msg1[0].iov_base = "one";
     msg1[0].iov_len = 3;
     msg1[1].iov_base = "two";
     msg1[1].iov_len = 3;
 
-    memset(&msg2, 0, sizeof(msg2));
+    bzero(&msg2, sizeof(msg2));
     msg2.iov_base = "three";
     msg2.iov_len = 5;
 
-    memset(msg, 0, sizeof(msg));
+    bzero(msg, sizeof(msg));
     msg[0].msg_hdr.msg_iov = msg1;
     msg[0].msg_hdr.msg_iovlen = 2;
 
diff --git a/man2/set_thread_area.2 b/man2/set_thread_area.2
index ccfacc70d..263bda38c 100644
--- a/man2/set_thread_area.2
+++ b/man2/set_thread_area.2
@@ -207,7 +207,7 @@  .SH BUGS
 if set, would prevent the descriptor from being considered empty (see
 .BR modify_ldt (2)).
 As a result, the only reliable way to clear a TLS entry is to use
-.BR memset (3)
+.BR bzero (3)
 to zero the entire
 .I user_desc
 structure, including padding bits, and then to set the
diff --git a/man2/sysctl.2 b/man2/sysctl.2
index 679b20a74..8f15fea03 100644
--- a/man2/sysctl.2
+++ b/man2/sysctl.2
@@ -137,7 +137,7 @@  .SH EXAMPLES
     size_t                osnamelth;
     struct __sysctl_args  args;
 
-    memset(&args, 0, sizeof(args));
+    bzero(&args, sizeof(args));
     args.name = name;
     args.nlen = ARRAY_SIZE(name);
     args.oldval = osname;
diff --git a/man3/bzero.3 b/man3/bzero.3
index 1cd2fa664..503ad6c98 100644
--- a/man3/bzero.3
+++ b/man3/bzero.3
@@ -62,9 +62,7 @@  .SH ATTRIBUTES
 .SH STANDARDS
 The
 .BR bzero ()
-function is deprecated (marked as LEGACY in POSIX.1-2001); use
-.BR memset (3)
-in new programs.
+function is marked as LEGACY in POSIX.1-2001;
 POSIX.1-2008 removes the specification of
 .BR bzero ().
 The
diff --git a/man3/getaddrinfo.3 b/man3/getaddrinfo.3
index 1248ae34d..67b049fe2 100644
--- a/man3/getaddrinfo.3
+++ b/man3/getaddrinfo.3
@@ -671,7 +671,7 @@  .SS Server program
         exit(EXIT_FAILURE);
     }
 
-    memset(&hints, 0, sizeof(hints));
+    bzero(&hints, sizeof(hints));
     hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
     hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
     hints.ai_flags = AI_PASSIVE;    /* For wildcard IP address */
@@ -770,7 +770,7 @@  .SS Client program
 
     /* Obtain address(es) matching host/port. */
 
-    memset(&hints, 0, sizeof(hints));
+    bzero(&hints, sizeof(hints));
     hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
     hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
     hints.ai_flags = 0;
diff --git a/man3/getaddrinfo_a.3 b/man3/getaddrinfo_a.3
index 3ca5d9858..98617ee82 100644
--- a/man3/getaddrinfo_a.3
+++ b/man3/getaddrinfo_a.3
@@ -360,7 +360,7 @@  .SS Synchronous example
             perror("malloc");
             exit(EXIT_FAILURE);
         }
-        memset(reqs[i], 0, sizeof(*reqs[0]));
+        bzero(reqs[i], sizeof(*reqs[0]));
         reqs[i]\->ar_name = argv[i + 1];
     }
 
diff --git a/man3/getutent.3 b/man3/getutent.3
index 32a87b4a9..55961b460 100644
--- a/man3/getutent.3
+++ b/man3/getutent.3
@@ -317,7 +317,7 @@  .SH EXAMPLES
     strcpy(entry.ut_id, ttyname(STDIN_FILENO) + strlen("/dev/tty"));
     time(&entry.ut_time);
     strcpy(entry.ut_user, getpwuid(getuid())\->pw_name);
-    memset(entry.ut_host, 0, UT_HOSTSIZE);
+    bzero(entry.ut_host, UT_HOSTSIZE);
     entry.ut_addr = 0;
     setutent();
     pututline(&entry);
@@ -325,9 +325,9 @@  .SH EXAMPLES
     system("echo after adding entry:;who");
 
     entry.ut_type = DEAD_PROCESS;
-    memset(entry.ut_line, 0, UT_LINESIZE);
+    bzero(entry.ut_line, UT_LINESIZE);
     entry.ut_time = 0;
-    memset(entry.ut_user, 0, UT_NAMESIZE);
+    bzero(entry.ut_user, UT_NAMESIZE);
     setutent();
     pututline(&entry);
 
diff --git a/man3/mbrtowc.3 b/man3/mbrtowc.3
index cf401c9fa..a62e06885 100644
--- a/man3/mbrtowc.3
+++ b/man3/mbrtowc.3
@@ -145,7 +145,7 @@  .SH DESCRIPTION
 .PP
 .in +4n
 .EX
-memset(&a, 0, sizeof(a));
+bzero(&a, sizeof(a));
 .EE
 .in
 .SH RETURN VALUE
diff --git a/man3/mbsinit.3 b/man3/mbsinit.3
index f93d48132..9d6182cab 100644
--- a/man3/mbsinit.3
+++ b/man3/mbsinit.3
@@ -58,7 +58,7 @@  .SH DESCRIPTION
 .in +4n
 .EX
 mbstate_t state;
-memset(&state, 0, sizeof(state));
+bzero(&state, sizeof(state));
 .EE
 .in
 .PP
diff --git a/man3/rtime.3 b/man3/rtime.3
index 0abcf6fce..1cba00162 100644
--- a/man3/rtime.3
+++ b/man3/rtime.3
@@ -131,7 +131,7 @@  .SH EXAMPLES
     struct rpc_timeval  timeout = {1, 0};
     struct sockaddr_in  name;
 
-    memset(&name, 0, sizeof(name));
+    bzero(&name, sizeof(name));
     sethostent(1);
     hent = gethostbyname(servername);
     memcpy(&name.sin_addr, hent\->h_addr, hent\->h_length);
diff --git a/man3/rtnetlink.3 b/man3/rtnetlink.3
index 460b2b5a5..f045facf5 100644
--- a/man3/rtnetlink.3
+++ b/man3/rtnetlink.3
@@ -104,7 +104,7 @@  .SH EXAMPLES
 
 int rtnetlink_sk = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
 
-memset(&req, 0, sizeof(req));
+bzero(&req, sizeof(req));
 req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.if));
 req.nh.nlmsg_flags = NLM_F_REQUEST;
 req.nh.nlmsg_type = RTM_NEWLINK;
diff --git a/man3/strptime.3 b/man3/strptime.3
index 8c3a569c0..6d451c5c8 100644
--- a/man3/strptime.3
+++ b/man3/strptime.3
@@ -398,7 +398,7 @@  .SH EXAMPLES
     struct tm tm;
     char buf[255];
 
-    memset(&tm, 0, sizeof(tm));
+    bzero(&tm, sizeof(tm));
     strptime("2001\-11\-12 18:31:01", "%Y\-%m\-%d %H:%M:%S", &tm);
     strftime(buf, sizeof(buf), "%d %b %Y %H:%M", &tm);
     puts(buf);
diff --git a/man3const/NULL.3const b/man3const/NULL.3const
index 1b60b2b4c..d30b053a6 100644
--- a/man3const/NULL.3const
+++ b/man3const/NULL.3const
@@ -62,7 +62,7 @@  .SH CAVEATS
 .SH BUGS
 When it is necessary to set a pointer variable to a null pointer,
 it is not enough to use
-.BR memset (3)
+.BR bzero (3)
 to zero the pointer
 (this is usually done when zeroing a struct that contains pointers),
 since ISO C and POSIX don't guarantee that a bit pattern of all 0s
diff --git a/man3type/size_t.3type b/man3type/size_t.3type
index ba02993a2..8a10a6634 100644
--- a/man3type/size_t.3type
+++ b/man3type/size_t.3type
@@ -173,6 +173,7 @@  .SH SEE ALSO
 .BR fwrite (3),
 .BR memcmp (3),
 .BR memcpy (3),
+.BR bzero (3),
 .BR memset (3),
 .BR offsetof (3),
 .BR ptrdiff_t (3type)
diff --git a/man3type/void.3type b/man3type/void.3type
index ddcbf482f..df7339377 100644
--- a/man3type/void.3type
+++ b/man3type/void.3type
@@ -71,5 +71,6 @@  .SH SEE ALSO
 .BR malloc (3),
 .BR memcmp (3),
 .BR memcpy (3),
+.BR bzero (3),
 .BR memset (3),
 .BR intptr_t (3type)
diff --git a/man7/aio.7 b/man7/aio.7
index d0d814cb2..c539f3a43 100644
--- a/man7/aio.7
+++ b/man7/aio.7
@@ -145,7 +145,7 @@  .SH STANDARDS
 POSIX.1-2001, POSIX.1-2008.
 .SH NOTES
 It is a good idea to zero out the control block buffer before use (see
-.BR memset (3)).
+.BR bzero (3)).
 The control block buffer and the buffer pointed to by
 .I aio_buf
 must not be changed while the I/O operation is in progress.
diff --git a/man7/netlink.7 b/man7/netlink.7
index 83f7bee13..6e04d9fc5 100644
--- a/man7/netlink.7
+++ b/man7/netlink.7
@@ -539,7 +539,7 @@  .SH EXAMPLES
 .EX
 struct sockaddr_nl sa;
 
-memset(&sa, 0, sizeof(sa));
+bzero(&sa, sizeof(sa));
 sa.nl_family = AF_NETLINK;
 sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;
 
@@ -561,7 +561,7 @@  .SH EXAMPLES
 struct msghdr msg;
 
 msg = { &sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
-memset(&sa, 0, sizeof(sa));
+bzero(&sa, sizeof(sa));
 sa.nl_family = AF_NETLINK;
 nh\->nlmsg_pid = 0;
 nh\->nlmsg_seq = ++sequence_number;
diff --git a/man7/unix.7 b/man7/unix.7
index b290117fc..03f5cad5c 100644
--- a/man7/unix.7
+++ b/man7/unix.7
@@ -912,7 +912,7 @@  .SH BUGS
 addrp = malloc(addrlen + 1);
 if (addrp == NULL)
     /* Handle error */ ;
-memset(addrp, 0, addrlen + 1);
+bzero(addrp, addrlen + 1);
 
 if (getsockname(sfd, (struct sockaddr *) addrp, &addrlen)) == \-1)
     /* handle error */ ;
@@ -1004,7 +1004,7 @@  .SS Program source
      * the structure.
      */
 
-    memset(&name, 0, sizeof(name));
+    bzero(&name, sizeof(name));
 
     /* Bind socket to socket name. */
 
@@ -1137,7 +1137,7 @@  .SS Program source
      * the structure.
      */
 
-    memset(&addr, 0, sizeof(addr));
+    bzero(&addr, sizeof(addr));
 
     /* Connect socket to socket address. */