Search code examples
clinuxipcmq

Posix messages Bad adress at mq_open


Problem Summary

I am writing a program that is intended to fork multiple processes, each of which open a unique message queue for receiving messages. Every time I run my program, however, every single forked process encounters the Bad address error when initializing their respective queues with mq_open.

Some Details

My code is intended to generate message queue names dynamically, following the form "/_*, where * is some unique letter (a, b, c, etc.) However, upon trying the same code with the string "/hello"put in place of the dynamically generated names, the program still failed with the same error.

This has led me to believe that the issue is a failure to create a new queue, rather than an issue with the name itself. However, I believe I am passing O_CREAT correctly, so I can't figure out what the problem is.

I did find this previous thread on the subject, but it doesn't seem that that guy was having the same problems. I believe I have included all relevant code below, but please let me know if more is needed. Any help is much appreciated!

My code

Here is the wrapper function that actually calls mq_open:

mqd_t init_queue(char *desc, long m_flags, long m_max, long m_size)
{
  mqd_t mq_des;
  struct mq_attr attr;
  mode_t mode = 0664;
  attr.mq_maxmsg = m_max;
  attr.mq_msgsize = m_size;
  attr.mq_flags = m_flags;

  if ((mq_des = mq_open(desc, O_CREAT | O_RDWR, mode, attr)) == -1) {
    perror("Error at init_queue");
    exit(1);
  }

  return mq_des;
}

Here is the function that calls init_queue. I've pasted in the relevant macros and helper function (nid) at the top as well, so you can see those:


#define DESCPREF "/_"
#define DESCSIZE 4
#define FIRSTID 97
#define MAXMSGS 200
#define M_SIZE sizeof(struct _message)

char *nid(int id)
{
  char *desc = malloc(sizeof(char) * DESCSIZE);
  char c = id;
  snprintf(desc, DESCSIZE, "%s%c", DESCPREF, c);
  return desc;
}

int node(int id, int inc)
{
  /* INIT */
  proc_info me = malloc(PROCINF_SIZE);
  me->id = id;
  me->curr = id - FIRSTID + 1;
  me->inc = inc;
  char *mypath = nid(id);
  me->listen = init_queue(mypath, O_NONBLOCK, MAXMSGS, M_SIZE);

  /* Do some stuff ... */

  close_queue(me->listen);
  mq_unlink(mypath);
  free(me);
  return 0;
}

Finally, the bit of code that forks my individual processes:

int main(){

  pid_t pid;
  int nodes = TESTNODES;

  for (int i = 0; i < nodes; i++) {
    if ((pid = fork()) == -1) {
      perror("Fork error\n");
      exit(1);
    } else if (pid == 0) {
      node(FIRSTID + i, nodes);
      exit(0);
    } else {
      printf("Forked: %d\n", (int) pid);
    }
  }
  return 1;
}

Expected vs. Actual results

I would expect this code to simply run, printing the pids of forked processes, then exit. Instead I get the following errors (for one example run):

Forked: 27448
Forked: 27449
Error at init_queue: Bad address
Error at init_queue: Bad address
Forked: 27450
Error at init_queue: Bad address
Forked: 27451
Error at init_queue: Bad address
Forked: 27452
Error at init_queue: Bad address

As previously mentioned, I also tried this with the plain string "/hello" used as the input name for mq_open and received the same set of errors (all five failed in that case as well).


Solution

  • You need to pass the pointer to the mq_attr struct like:

    if ((mq_des = mq_open(desc, O_CREAT | O_RDWR, mode, &attr)) == -1) {
        perror("Error at init_queue");
        exit(1);
    }
    

    also as per the manual page make sure the values for max messages and msg size make sense otherwise you will get an EINVAL.

       EINVAL O_CREAT was specified in oflag, and attr was not NULL, but
              attr->mq_maxmsg or attr->mq_msqsize was invalid.  Both of
              these fields must be greater than zero.  In a process that is
              unprivileged (does not have the CAP_SYS_RESOURCE capability),
              attr->mq_maxmsg must be less than or equal to the msg_max
              limit, and attr->mq_msgsize must be less than or equal to the
              msgsize_max limit.  In addition, even in a privileged process,
              attr->mq_maxmsg cannot exceed the HARD_MAX limit.  (See
              mq_overview(7) for details of these limits.)