【问题标题】:stack smashing when receiving a single message through message queues通过消息队列接收单个消息时堆栈粉碎
【发布时间】:2022-01-31 22:03:47
【问题描述】:

我有以下发件人:

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <errno.h>

typedef struct message {
    long int mtype;
    int mtext[200];
} message;

int main(int argc, char *argv[]) {
    // msg queue
    int msgid;
    message msg;
    key_t key;
    
    // create msg queue key
    if ((key = ftok("master.c", 'b')) == -1) {
        perror("ftok");
    }

    // create msg queue
    if ((msgid = msgget(key, 0666 | IPC_CREAT)) == -1) {
        perror("msgget");
    }

    msg.mtype=10;
    msg.mtext[0] = 1;
    if ((msgsnd(msgid, &msg, sizeof(message), 0)) == -1) {
        perror("msgsnd");
    }
    sleep(5);

    // TODO: uncomment section
    if (msgctl(msgid, IPC_RMID, NULL) == -1) {
        perror("msgctl");
    }
    
    return 0;
}

和接收者:

#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <errno.h>

typedef struct message {
    long int mtype;
    int mtext[200];
} message;

int main(int argc, char *argv[]) {
    // msg queue
    message msg;
    int msgid;
    key_t key;
    
    // create msg queue key
    if ((key = ftok("master.c", 'b')) == -1) {
        perror("ftok");
    }

    // create msg queue
    if ((msgid = msgget(key, 0666)) == -1) {
        perror("msgget");
    }

    if ((msgrcv(msgid, &msg, sizeof(message), 10, 0)) == -1) {
        perror("msgrcv");
    }
    printf("%d\n", msg.mtext[0]);

    return 0;
}

问题是当我同时运行它们时,我得到了

*** stack smashing detected ***: terminated
Aborted (core dumped)

上面的短语是在整个代码按预期执行之后显示的,但这仍然意味着有些事情是不正确的。但是,如果我将msgrcv 置于无限循环中,一切都会按预期运行并且不会引发警告。由于我正在写入和读取相同大小的数据,错误可能来自哪里?

【问题讨论】:

  • 为什么你使用int 数组而不是uint8_t 更有意义?
  • 总的来说,这是使用“struct hack”的腐烂的 C99 之前的 API...另一个 *nix facepalm API...
  • @AdrianMole 是的!那是导致错误的原因。我以为我已经检查过了但没有工作,但我一定是做错了什么。谢谢!
  • @Lundin 很抱歉,我不明白您的第二条评论。但是,首先,为什么uint8_t 更有意义?你能给我发一份参考资料来看看吗?
  • 这个蹩脚的手册页:linux.die.net/man/2/msgrcv 说该函数需要struct msgbuf { long mtype; char mtext[1]; };,这反过来表明发明这些函数的人是无能的。不仅因为 struct hack,还因为实现定义的 char 符号和 long 的大小,这可能在 *nix 实现之间有所不同。这只是slop,除了unsigned char 的数组之外,我不会将任何东西传递给这些函数,或者谁知道可能会破坏什么。

标签: c message-queue


【解决方案1】:

根据the documentation,msgrcv 的 msgsz 参数应该指示消息结构的 .mtext 成员 的大小(以字节为单位),而不是大于整个结构的大小。

该结构通常比可用缓冲区大 4 或 8 个字节(取决于 long int 的定义方式),因此您的写入可能超出了可用/分配的内存 - 导致未定义的行为。

UB 的一个可能影响是为main 函数分配的堆栈损坏;如果该函数永远不会返回(就像您添加无限循环时一样),则堆栈损坏可能不会表现出来。

【讨论】:

  • 是否可以保证 sys lib 使用与应用程序相同的编译器进行编译?假设long 有一定的大小会很好。
  • @Lundin 不知道。对我来说,您对这个问题的看法似乎恰到好处。
  • 所以可能是试错,将一个零初始化的字节缓冲区传递给函数,看看它填满了多少。使用这些古老的库总是感觉像是考古学......肯定有人为 IPC 编写了一个更好的库,因为这个库被创建了。
  • @Lundin 不确定这是否重要,就堆栈粉碎问题而言。我们当然可以同意 sizeof(long) 将 > 0。
猜你喜欢
  • 2021-04-29
  • 2012-02-02
  • 1970-01-01
  • 2012-01-19
  • 1970-01-01
  • 1970-01-01
  • 2011-07-10
  • 2011-07-15
  • 2010-09-19
相关资源
最近更新 更多