misc/69448: cmsghdr macros don't work with Alpha (and other 64bit systems?)

Timo Sirainen tss at iki.fi
Thu Jul 22 14:40:24 PDT 2004


>Number:         69448
>Category:       misc
>Synopsis:       cmsghdr macros don't work with Alpha (and other 64bit systems?)
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Jul 22 21:40:23 GMT 2004
>Closed-Date:
>Last-Modified:
>Originator:     Timo Sirainen
>Release:        4.10
>Organization:
>Environment:
Alpha (not mine)
>Description:
CMSG_DATA and CMSG_LEN macros do 64bit alignment but kernel seems to want 32bit alignment. After overriding them it started working:

#define CMSG_LEN(l) (sizeof(struct cmsghdr) + (l))
#define CMSG_DATA(cmsg) ((u_char *)(cmsg) + sizeof(struct cmsghdr))

>How-To-Repeat:
This breaks:

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <sys/un.h>
#include <sys/uio.h>

ssize_t fd_send(int handle, int send_fd, const void *data, size_t size)
{
        struct msghdr msg;
        struct iovec iov;
        struct cmsghdr *cmsg;
	char buf[CMSG_SPACE(sizeof(int))];

	memset(&msg, 0, sizeof(struct msghdr));

        iov.iov_base = (void *) data;
        iov.iov_len = size;

        msg.msg_iov = &iov;
	msg.msg_iovlen = 1;

	if (send_fd != -1) {
		memset(buf, 0, sizeof(buf));
		msg.msg_control = buf;
		msg.msg_controllen = sizeof(buf);

		cmsg = CMSG_FIRSTHDR(&msg);
		cmsg->cmsg_level = SOL_SOCKET;
		cmsg->cmsg_type = SCM_RIGHTS;
		cmsg->cmsg_len = CMSG_LEN(sizeof(int));
		*((int *) CMSG_DATA(cmsg)) = send_fd;

		msg.msg_controllen = cmsg->cmsg_len;
	}

	return sendmsg(handle, &msg, 0);
}

ssize_t fd_read(int handle, void *data, size_t size, int *fd)
{
	struct msghdr msg;
	struct iovec iov;
	struct cmsghdr *cmsg;
	ssize_t ret;
	char buf[CMSG_SPACE(sizeof(int))];

	memset(&msg, 0, sizeof (struct msghdr));

	iov.iov_base = data;
	iov.iov_len = size;

	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;

	memset(buf, 0, sizeof(buf));
	msg.msg_control = buf;
	msg.msg_controllen = sizeof(buf);

	ret = recvmsg(handle, &msg, 0);
	if (ret <= 0) {
		*fd = -1;
		return ret;
	}

	cmsg = CMSG_FIRSTHDR(&msg);
	if (cmsg == NULL)
		*fd = -1;
	else
		*fd = *((int *) CMSG_DATA(cmsg));
	return ret;
}

int main(void)
{
	int fd[2], send_fd, recv_fd, status;
	struct stat st, st2;
	char data;

	send_fd = open("conftest.fdpass", O_CREAT|O_WRONLY);
	if (send_fd == -1) {
		perror("open()");
		return 2;
	}
	unlink("conftest.fdpass");
	if (fstat(send_fd, &st) < 0) {
		perror("fstat()");
		return 2;
	}
	if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) {
		perror("socketpair()");
		return 2;
	}

	switch (fork()) {
	case -1:
		perror("fork()");
		return 2;
	case 0:
		if (fd_send(fd[0], send_fd, &data, 1) != 1) {
			perror("fd_send()");
			return 2;
		}
		wait(&status);
		return status;
	default:
		if (fd_read(fd[1], &data, 1, &recv_fd) != 1) {
			perror("fd_read()");
			return 1;
		}
		if (fstat(recv_fd, &st2) < 0) {
			perror("fstat(recv_fd)");
			return 2;
		}
		return st.st_ino == st2.st_ino ? 0 : 1;
	}
}

>Fix:

>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list