Subject: Intermediate void* casts
To: None <tech-misc@NetBSD.ORG, tech-kern@NetBSD.ORG,>
From: Martin Husemann <martin@duskware.de>
List: tech-userlevel
Date: 08/10/2003 18:35:58
Hi folks,

sorry for the cross-post, please be sure to only reply to tech-misc to
avoid spreading this flame fest over various mailing lists.

Since we will switch to gcc3.3.1 soon and already had first problems
with incorrect code due to alias bugs, I think we should have a kind
of a mini audit for these. Usually gcc 3.3.1 warns about this kind
of problems, but it shuts up if an intermediate void* cast is involved.
So I tried to find dubious casts to pointer types after casts to void*.

I found quite a few of them, which was a bit of a suprise to me. I've
already dealt with some of them, and they seem to fall into three categories:

 - The (void*) cast can just be removed.
   A real world example: char *p; some_func((void**)(void*)&p);
 - The complete cast magic is better expressed by a memcpy.
   My favorite example is ./lib/libm/src/s_frexpf.c:
     *(int*)(void*)&x = hx;
 - Removing the (void*) causes gcc 3.3.1 to warn about strict alias violations
   by type-punned pointer dereferences.
   This is the thing we should care about. The warning is serious, the 
   generated code (with -O2, which includes -fstrict-alias) may not do what
   we expect it to do.

The latter point needs manual judgement from someone comfortable with that
area of the source tree. Possible solutions in that case inlcude:
 - just leave the (void*) in place if alias problems are not possible
   according to manual verification. We should not let the compiler stop
   us doing clever things, if we know what we are doing.
 - rewrite the expression completely to avoid the aliases
   I did this with svr_machdep code for sparc*, where the address of a 64bit
   value was casted to a 32bit pointer to access the two halves of the value.
   Easy to replace with shift/mask expressions. Even clearer IMHO and might
   give the compiler better optimization hints.
   This was the case for bswap64 too (which is the problem that triggered
   all this)

So, I think it would be good if everybody looks at the list below and handles
(the probably few cases) fitting into his/her favorite work area, or files a
PR if the solution is unclear (or the person looking is no developer). The
list is probably incomplete, since the grep did not handle line breaks.

Martin

The list was found by:

find . -type f | xargs egrep '\* *\) *\( *void *\* *\) *\&'

./dist/bind/lib/resolv/res_send.c:		return (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[n];
./dist/bind/lib/resolv/res_send.c:		return (struct sockaddr *)(void *)&statp->nsaddr_list[n];
./dist/file/src/apprentice.c:	uint8_t *s = (uint8_t *)(void *)&sv; 
./dist/file/src/apprentice.c:	uint8_t *d = (uint8_t *)(void *)&rv; 
./dist/file/src/apprentice.c:	uint8_t *s = (uint8_t *)(void *)&sv; 
./dist/file/src/apprentice.c:	uint8_t *d = (uint8_t *)(void *)&rv; 
./include/db.h:	((char *)(void *)&a)[0] = ((char *)(void *)&_tmp)[3];		\
./include/db.h:	((char *)(void *)&a)[1] = ((char *)(void *)&_tmp)[2];		\
./include/db.h:	((char *)(void *)&a)[2] = ((char *)(void *)&_tmp)[1];		\
./include/db.h:	((char *)(void *)&a)[3] = ((char *)(void *)&_tmp)[0];		\
./include/db.h:	((char *)(void *)&(b))[0] = ((char *)(void *)&(a))[3];		\
./include/db.h:	((char *)(void *)&(b))[1] = ((char *)(void *)&(a))[2];		\
./include/db.h:	((char *)(void *)&(b))[2] = ((char *)(void *)&(a))[1];		\
./include/db.h:	((char *)(void *)&(b))[3] = ((char *)(void *)&(a))[0];		\
./include/db.h:	((char *)(void *)&a)[0] = ((char *)(void *)&_tmp)[1];		\
./include/db.h:	((char *)(void *)&a)[1] = ((char *)(void *)&_tmp)[0];		\
./include/db.h:	((char *)(void *)&(b))[0] = ((char *)(void *)&(a))[1];		\
./include/db.h:	((char *)(void *)&(b))[1] = ((char *)(void *)&(a))[0];		\
./lib/libc/arch/alpha/gen/flt_rounds.c:	old = *(u_int64_t *)(void *)&fpcrval;
./lib/libc/arch/alpha/gen/fpgetround.c:	old = *(u_int64_t *)(void *)&fpcrval;
./lib/libc/arch/alpha/gen/fpsetround.c:	old = *(u_int64_t *)(void *)&fpcrval;
./lib/libc/arch/alpha/gen/fpsetround.c:	*(u_int64_t *)(void *)&fpcrval = new;
./lib/libc/db/btree/bt_open.c:	p = (u_char *)(void *)&x;
./lib/libc/gen/nlist_elf32.c:	ehdrp = (Elf_Ehdr *)(void *)&mappedfile[0];
./lib/libc/gen/nlist_elf32.c:	shdrp = (Elf_Shdr *)(void *)&mappedfile[shdr_off];
./lib/libc/gen/nlist_elf32.c:	symp = (Elf_Sym *)(void *)&mappedfile[symshdrp->sh_offset];
./lib/libc/gen/syslog.c:		if (connect(LogFile, (struct sockaddr *)(void *)&SyslogAddr,
./lib/libc/net/gethnamaddr.c:		*hap++ = (char *)(void *)&host_addrs[naddrs++];
./lib/libc/net/gethnamaddr.c:		*hap++ = (char *)(void *)&host6_addrs[naddrs++];
./lib/libc/net/inet_pton.c:	if (inet_pton4(cp, (u_char *)(void *)&val.s_addr, 0))
./lib/libc/net/inet_pton.c:	return inet_pton4(cp, (u_char *)(void *)&addr->s_addr, 0);
./lib/libc/net/ns_addr.c:		Field(socketname, (u_int8_t *)(void *)&addr.x_port, 2);
./lib/libc/net/rcmd.c:		s3 = accept(s2, (struct sockaddr *)(void *)&from, &len);
./lib/libc/net/rcmd.c:		switch (((struct sockaddr *)(void *)&from)->sa_family) {
./lib/libc/net/rcmd.c:			if (getnameinfo((struct sockaddr *)(void *)&from, len,
./lib/libc/net/rcmd.c:	sa = (struct sockaddr *)(void *)&ss;
./lib/libc/net/rcmd.c:	return __ivaliduser_sa(hostf, (struct sockaddr *)(void *)&ivusin,
./lib/libc/net/res_send.c:		return (struct sockaddr *)(void *)&_res_ext.nsaddr_list[n];
./lib/libc/net/res_send.c:		return (struct sockaddr *)(void *)&_res.nsaddr_list[n];
./lib/libc/net/res_send.c:			putshort((u_short)buflen, (u_char*)(void *)&len);
./lib/libc/net/res_send.c:					    (struct sockaddr *)(void *)&no_addr,
./lib/libc/net/res_send.c:			    (struct sockaddr *)(void *)&from, &fromlen);
./lib/libc/net/res_send.c:			    (struct sockaddr_in *)(void *)&from)) {
./lib/libc/rpc/bindresvport.c:		sa = (struct sockaddr *)(void *)&myaddr;
./lib/libc/rpc/bindresvport.c:		if (sa != (struct sockaddr *)(void *)&myaddr) {
./lib/libc/rpc/clnt_generic.c:		CLNT_CONTROL(clnt, CLSET_VERS, (char *)(void *)&vers_high);
./lib/libc/rpc/clnt_simple.c:				CLSET_RETRY_TIMEOUT, (char *)(void *)&timeout);
./lib/libc/rpc/clnt_simple.c:		if (CLNT_CONTROL(rcp->client, CLGET_FD, (char *)(void *)&fd))
./lib/libc/rpc/rpc_callmsg.c:	    xdr_enum(xdrs, (enum_t *)(void *)&(cmsg->rm_direction)) &&
./lib/libc/rpc/rpc_prot.c:	if (! xdr_enum(xdrs, (enum_t *)(void *)&(ar->ar_stat)))
./lib/libc/rpc/rpc_prot.c:	if (! xdr_enum(xdrs, (enum_t *)(void *)&(rr->rj_stat)))
./lib/libc/rpc/rpc_prot.c:		return (xdr_enum(xdrs, (enum_t *)(void *)&(rr->rj_why)));
./lib/libc/rpc/rpc_prot.c:	    xdr_enum(xdrs, (enum_t *)(void *)&(rmsg->rm_direction)) &&
./lib/libc/rpc/rpc_prot.c:		return (xdr_union(xdrs, (enum_t *)(void *)&(rmsg->rm_reply.rp_stat),
./lib/libc/rpc/rpc_prot.c:	    xdr_enum(xdrs, (enum_t *)(void *)&(cmsg->rm_direction)) &&
./lib/libc/rpc/svc_vc.c:	if (getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) < 0) {
./lib/libc/rpc/svc_vc.c:	if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
./lib/libc/rpc/svc_vc.c:	if (getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
./lib/libc/rpc/svc_vc.c:	if ((sock = accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr,
./lib/libc/rpc/xdr_rec.c:	rstrm->in_hdrp = (char *)(void *)&rstrm->in_header;
./lib/libc/rpc/xdr_rec.c:		if (! xdrrec_getbytes(xdrs, (char *)(void *)&mylong,
./lib/libc/rpc/xdr_rec.c:		rstrm->in_hdrp = (char *)(void *)&rstrm->in_header;
./lib/libc/rpc/xdr_rec.c:	if (! get_input_bytes(rstrm, (char *)(void *)&header, sizeof(header)))
./lib/libc/rpc/clnt_vc.c:	if (getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
./lib/libc/rpc/clnt_vc.c:		    ntohl(*(u_int32_t *)(void *)&ct->ct_u.ct_mcalli);
./lib/libc/rpc/clnt_vc.c:		*(u_int32_t *)(void *)&ct->ct_u.ct_mcalli =
./lib/libc/rpc/clnt_bcast.c:			gbsin = (struct sockaddr_in *)(void *)&bip->broadaddr;
./lib/libc/rpc/clnt_bcast.c:			sin6 = (struct sockaddr_in6 *)(void *)&bip->broadaddr;
./lib/libc/rpc/clnt_bcast.c:	    (struct rpcb_rmtcallargs *)(void *)&barg))) {
./lib/libc/rpc/clnt_bcast.c:			    0, (struct sockaddr *)(void *)&fdlist[i].raddr,
./lib/libc/rpc/clnt_dg.c:	ioctl(fd, FIONBIO, (char *)(void *)&one);
./lib/libc/rpc/clnt_dg.c:	    (struct sockaddr *)(void *)&cu->cu_raddr, (socklen_t)cu->cu_rlen)
./lib/libc/rpc/clnt_dg.c:			    cu->cu_recvsz, 0, (struct sockaddr *)(void *)&cu->cu_raddr,
./lib/libc/rpc/rpc_generic.c:	if (getsockname(fd, (struct sockaddr *)(void *)&ss, &len) < 0)
./lib/libc/rpc/rpc_generic.c:	if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0)
./lib/libc/rpc/rpc_soc.c:	(void) CLNT_CONTROL(cl, CLSET_RETRY_TIMEOUT, (char *)(void *)&wait);
./lib/libc/rpc/rpcb_clnt.c:	    (char *)(void *)&parms, (xdrproc_t) xdr_bool,
./lib/libc/rpc/rpcb_clnt.c:	    (char *)(void *)&rslt, tottimeout);
./lib/libc/rpc/rpcb_clnt.c:	    (char *)(void *)&parms, (xdrproc_t) xdr_bool,
./lib/libc/rpc/rpcb_clnt.c:	    (char *)(void *)&rslt, tottimeout);
./lib/libc/rpc/rpcb_clnt.c:		CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&pmapvers);
./lib/libc/rpc/rpcb_clnt.c:		CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)(void *)&remote);
./lib/libc/rpc/rpcb_clnt.c:				(char *)(void *)&port, sizeof (short));
./lib/libc/rpc/rpcb_clnt.c:			CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers);
./lib/libc/rpc/rpcb_clnt.c:		    (xdrproc_t) xdr_rpcb, (char *)(void *)&parms,
./lib/libc/rpc/rpcb_clnt.c:		    (char *)(void *)&relp, tottimeout);
./lib/libc/rpc/rpcb_clnt.c:				    (char *)(void *)&relp);
./lib/libc/rpc/rpcb_clnt.c:					(char *)(void *)&servaddr);
./lib/libc/rpc/rpcb_clnt.c:			    (char *)(void *)&relp);
./lib/libc/rpc/rpcb_clnt.c:		CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers);
./lib/libc/rpc/rpcb_clnt.c:		    (xdrproc_t) xdr_rpcb, (char *)(void *)&parms,
./lib/libc/rpc/rpcb_clnt.c:		    (xdrproc_t) xdr_wrapstring, (char *)(void *) &ua,
./lib/libc/rpc/rpcb_clnt.c:			    (char *)(void *)&ua);
./lib/libc/rpc/rpcb_clnt.c:			    (char *)(void *)&servaddr);
./lib/libc/rpc/rpcb_clnt.c:	    (char *)(void *)&head, tottimeout);
./lib/libc/rpc/rpcb_clnt.c:	CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers);
./lib/libc/rpc/rpcb_clnt.c:		CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers);
./lib/libc/rpc/rpcb_clnt.c:		    (char *)(void *)&head, tottimeout) == RPC_SUCCESS)
./lib/libc/rpc/rpcb_clnt.c:	CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)(void *)&rmttimeout);
./lib/libc/rpc/rpcb_clnt.c:		CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&rpcb_vers);
./lib/libc/rpc/rpcb_clnt.c:		    (xdrproc_t) xdr_rpcb_rmtcallargs, (char *)(void *)&a,
./lib/libc/rpc/rpcb_clnt.c:		    (xdrproc_t) xdr_rpcb_rmtcallres, (char *)(void *)&r, tout);
./lib/libc/rpc/rpcb_clnt.c:		xdr_free((xdrproc_t) xdr_wrapstring, (char *)(void *)&r.addr);
./lib/libc/rpc/rpcb_clnt.c:		CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers);
./lib/libc/rpc/rpcb_clnt.c:			CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers);
./lib/libc/rpc/rpcb_clnt.c:	    (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr, tottimeout);
./lib/libc/rpc/rpcb_clnt.c:	    (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr,
./lib/libc/rpc/svc_dg.c:	if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0)
./lib/libc/rpc/svc_dg.c:	    (struct sockaddr *)(void *)&ss, &alen);
./lib/libc/rpc/svc_dg.c:			    (struct sockaddr *)(void *)&ss, alen);
./lib/libc/rpc/svc_generic.c:				if (bind(fd, (struct sockaddr *)(void *)&ss,
./lib/libc/rpc/svc_generic.c:			if (getpeername(fd, (struct sockaddr *)(void *)&ss, &slen)
./lib/libc/yp/xdryp.c:	if (!xdr_ypstat(xdrs, (enum ypbind_resptype *)(void *)&objp->status))
./lib/libc/yp/xdryp.c:	if (!xdr_ypstat(xdrs, (enum ypbind_resptype *)(void *)&objp->status))
./lib/libc/yp/xdryp.c:	if (!xdr_ypstat(xdrs, (enum ypbind_resptype *)(void *)&objp->status))
./lib/libc/yp/xdryp.c:	if (!xdr_ypstat(xdrs, (enum ypbind_resptype *)(void *)&objp->status))
./lib/libc/yp/xdryp.c:	if (!xdr_ypstat(xdrs, (enum ypbind_resptype *)(void *)&objp->status))
./lib/libc/yp/yp_first.c:	xdr_free((xdrproc_t)xdr_ypresp_key_val, (char *)(void *)&yprkv);
./lib/libc/yp/yp_first.c:	xdr_free((xdrproc_t)xdr_ypresp_key_val, (char *)(void *)&yprkv);
./lib/libc/yp/yp_master.c:	xdr_free((xdrproc_t)xdr_ypresp_master, (char *)(void *)&yprm);
./lib/libc/yp/yp_match.c:	xdr_free((xdrproc_t)xdr_ypresp_val, (char *)(void *)&yprv);
./lib/libc/yp/yp_order.c:	xdr_free((xdrproc_t)xdr_ypresp_order, (char *)(void *)&ypro);
./lib/libcompat/4.3/rexec.c:	if (connect(s, (struct sockaddr *)(void *)&rsin, sizeof(rsin)) == -1) {
./lib/libcompat/4.3/rexec.c:		if (getsockname(s2, (struct sockaddr *)(void *)&sin2,
./lib/libcompat/4.3/rexec.c:		s3 = accept(s2, (struct sockaddr *)(void *)&from, &fromlen);
./lib/libcrypt/crypt.c:			if (des_cipher((char *)(void *)&keyblock,
./lib/libcrypt/crypt.c:			    (char *)(void *)&keyblock, 0L, 1))
./lib/libcrypt/crypt.c:	if (des_cipher((char *)(void *)&constdatablock,
./lib/libcrypt/crypt.c:	    (char *)(void *)&rsltblock, salt, num_iter))
./lib/libedit/el.c:	return (const LineInfo *) (void *) &el->el_line;
./lib/libm/src/s_frexpf.c:	*(int*)(void*)&x = hx;
./sbin/setkey/parse.y:			(struct sadb_ext *)(void*)&m_key, sizeof(m_key),
./sbin/setkey/parse.y:			(struct sadb_ext *)(void*)&m_key, sizeof(m_key),
./sys/arch/i386/i386/machdep.c:	if (uvm_map(kernel_map, (vaddr_t *)(void *) &buffers, round_page(size),
./sys/arch/i386/i386/svr4_machdep.c:			frame.tf_edx = ((u_int32_t *)(void *) &tm)[0];
./sys/arch/i386/i386/svr4_machdep.c:			frame.tf_eax = ((u_int32_t *)(void *) &tm)[1];
./sys/arch/i386/i386/svr4_machdep.c:			frame.tf_edx = ((u_int32_t *)(void *) &tm)[0];
./sys/arch/i386/i386/svr4_machdep.c:			frame.tf_eax = ((u_int32_t *)(void *) &tm)[1];
./sys/arch/powerpc/include/stdarg.h:#define va_arg(ap, type)	(*(type *)(void *)&(ap))
./sys/arch/sh3/sh3/sh3_machdep.c:	if (uvm_map(kernel_map, (vaddr_t *)(void *)&buffers, round_page(size),
./sys/arch/amd64/amd64/machdep.c:	if (uvm_map(kernel_map, (vaddr_t *) (void *)&buffers, round_page(size),
./sys/arch/amd64/amd64/machdep.c:			ksyms_init(*(long *)(void *)&end,
./sys/arch/amd64/amd64/machdep.c:			    ((long *)(void *)&end) + 1, esym);
./sys/arch/arm/arm/sig_machdep.c:	arm_fpe_getcontext(p, (struct fpreg *)(void *)&mcp->fpregs);
./sys/arch/arm/arm/sig_machdep.c:		arm_fpe_setcontext(p, (struct fpreg *)(void *)&mcp->__fpregs);
./sys/arch/sh5/sh5/sig_machdep.c:		process_read_fpregs(l, (struct fpreg *)(void *)&mcp->__fpregs);
./sys/arch/sh5/sh5/sig_machdep.c:		process_write_fpregs(l, (struct fpreg *)(void *)&mcp->__fpregs);
./sys/compat/irix/irix_syssgi.c:		    pht->p_vaddr, pht->p_memsz, (vaddr_t *)(void *)&uaddr,
./sys/compat/irix/irix_syssgi.c:		    IRIX_MAPELF_RELOCATE, size, (vaddr_t *)(void *)&uaddr,
./sys/compat/irix/irix_swap.c:					 (register_t *)(void *)&entries)) != 0)
./sys/compat/irix/irix_swap.c:		    (register_t *)(void *)&dontcare);
./sys/sys/wait.h:#define	_W_INT(w)	(*(int *)(void *)&(w))	/* convert union wait to int */