您尚未登录。

#1 2020-05-27 22:29:16

nsfoxer
会员
注册时间: 2020-04-17
帖子: 20

linux的msgsnd()函数在使用ipcrm后调用失败

今天学习msgsnd()函数后发现,在调用ipcrm -q [id]后,再次调用后会出现msgsnd error: Invalid argument错误。具体过程如下:

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/msg.h>

typedef struct {
	long type;
	char mtext[512];
} MSG;

int main(int argc, char *argv[])
{
	if (argc < 2) {
		fprintf(stderr, "usage:%s key\n", argv[0]);
		exit(1);
	}
        // 指定参数1为消息队列的key
	key_t key = atoi(argv[1]);
	printf("key: %d\n", key);

	int msq_id;
	if ((msq_id = msgget(key, IPC_CREAT | IPC_EXCL | 0666) < 0)) {
		perror("msgget error");
	}
	printf("msq id: %d\n", msq_id);

	MSG m1 = {4, "1" };
	MSG m2 = {1, "2" };
	MSG m3 = {2, "3"};
	MSG m4 = {6, "4" };
	MSG m5 = {6, "5"};

	if (msgsnd(msq_id, (void*)&m1, sizeof(MSG)-sizeof(long), IPC_NOWAIT) < 0) {
		perror("msgsnd error");
	}
	if (msgsnd(msq_id, &m2, sizeof(MSG)-sizeof(m2.type), IPC_NOWAIT) < 0) {
		perror("msgsnd error");
	}
	if (msgsnd(msq_id, &m3, sizeof(MSG)-sizeof(m2.type), IPC_NOWAIT) < 0) {
		perror("msgsnd error");
	}
	if (msgsnd(msq_id, &m4, sizeof(MSG)-sizeof(m2.type), IPC_NOWAIT) < 0) {
		perror("msgsnd error");
	}
	if (msgsnd(msq_id, &m5, sizeof(MSG)-sizeof(m2.type), IPC_NOWAIT) < 0) {
		perror("msgsnd error");
	}

	// 获得消息队列总数
	struct msqid_ds ds;
	if (msgctl(msq_id, IPC_STAT, &ds) < 0) {
		perror("msgctl error");
	}
	printf("msg total: %ld\n", ds.msg_qnum);
	return 0;
}

编译程序为a.out,执行
./a.out 10
此时一切正常,当调用系统命令

ipcrm --all=msg -v

之后,再次 ./a.out 3后,出现

key: 3
msq id: 0
msgsnd error: Invalid argument
msgsnd error: Invalid argument
msgsnd error: Invalid argument
msgsnd error: Invalid argument
msgsnd error: Invalid argument
msgctl error: Invalid argument
msg total: 17179869188

想问这是怎么回事?在虚拟机kali(Linux kali 5.5.0-kali1-amd64 #1 SMP Debian 5.5.13-2kali1 (2020-04-03) x86_64 GNU/Linux)同样出现相同的问题
本机 manjaro(Linux nsfoxerpc 5.4.40-1-MANJARO #1 SMP PREEMPT Sun May 10 14:17:40 UTC 2020 x86_64 GNU/Linux) 希望大佬解决问题,谢谢

离线

#2 2020-05-27 22:49:37

nsfoxer
会员
注册时间: 2020-04-17
帖子: 20

Re: linux的msgsnd()函数在使用ipcrm后调用失败

在cnetos上实验时,出现报错

msq id: 1
msgsnd error: Identifier removed
msgsnd error: Identifier removed
msgsnd error: Identifier removed
msgsnd error: Identifier removed
msgsnd error: Identifier removed
msgctl error: Identifier removed
msg total: 0

google已经找到是因为代码第26行括号闭合位置错误,感谢
不同发行版的perror()报错信息还不一样?还是因为centos内核版本低?

离线

#3 2020-05-27 23:24:16

依云
会员
所在地: a.k.a. 百合仙子
注册时间: 2011-08-21
帖子: 8,934
个人网站

Re: linux的msgsnd()函数在使用ipcrm后调用失败

呃,我想去给 gcc / clang 报 bug……

	if ((msq_id = msgget(key, IPC_CREAT | IPC_EXCL | 0666) < 0)) {

这一行,你仔细匹配一下括号。

另外,sizeof(MSG)-sizeof(long) 这样计算另一个字段的长度是错的,因为会有 padding。你应当用 sizeof(m1.mtext) 或者直接写长度(毕竟你程序里是固定值,用个宏就可以了)。

离线

#4 2020-05-28 12:27:34

nsfoxer
会员
注册时间: 2020-04-17
帖子: 20

Re: linux的msgsnd()函数在使用ipcrm后调用失败

哦哦,看懂了;因为内存对齐原因,所以会出现padding;
man magsnd 有一段描述:

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
......
The msgp argument is a pointer to caller-defined structure of the following general form:

struct msgbuf {
    long mtype;       /* message type, must be > 0 */
    char mtext[1];    /* message data */
};
The mtext field is an array (or other structure) whose size is specified by msgsz, a nonnegative integer value.

msgsnd的第三个参数指的是mtext[]大小,而由于内存对齐的原因,sizeof(MSG)-sizeof(long)可能会导致padding也被计算在其中。
感谢大佬

离线

页脚