[net.unix] Sys V IPC: My final word

hope@gatech.CSNET (Theodore Hope) (02/12/86)

Since I'm the one who originally asked for info regarding the use of the
message queue system calls, let me say a few things.  First of all, thanks
to all who responded.

The man pages for msgop(2) describe the msgbuf struct as containing

	long mtype;     /* message type */
	char mtext [];  /* message text */

This kind of struc, especially in a syscall-passing sense, seems odd to me.
It is obvious that mtext should be

	char mtext [some_number];

"Oh," said I.  "I'll bet that's a misprint.  Let's look at the <sys/msg.h>
file to see what they _really_ mean."  Well, surprise.  The .h file defines

	struct msgbuf {
	   long mtype;
	   char mtext [1];	<- Notice: it says [1]
	}

Am I overlooking something obvious?  After looking through the kernel source,
it appeared that the msgsnd and msgrcv syscalls expect the data to start at 
msg.mtext, so by defining my own structs as

	struct Msgbuf {
	   long mtype;
	   char mtext [MAXMTEXT];
	}

everything is ok.


Several folks suggested to read the Sys V IPC Primer, which I don't have handy.
Others suggested the book "Advanced Systems Programming with Unix" (I can't
remember the authors' names).
-- 
Theodore Hope
School of Information & Computer Science, Georgia Tech, Atlanta GA 30332
CSNet:	hope@gatech		ARPA:	Hope%GATech.CSNet @ CSNet-Relay.ARPA
uucp:	...!{akgua,allegra,amd,hplabs,ihnp4,seismo,ut-sally}!gatech!hope

friesen@psivax.UUCP (Stanley Friesen) (02/13/86)

In article <2666@gatech.CSNET> hope@gatech.CSNET (Theodore Hope) writes:
>
>This kind of struc, especially in a syscall-passing sense, seems odd to me.
>It is obvious that mtext should be
>
>       char mtext [some_number];
>
>"Oh," said I.  "I'll bet that's a misprint.  Let's look at the <sys/msg.h>
>file to see what they _really_ mean."  Well, surprise.  The .h file defines
>
>       struct msgbuf {
>          long mtype;
>          char mtext [1];      <- Notice: it says [1]
>       }
>
>Am I overlooking something obvious?  After looking through the kernel source,
>it appeared that the msgsnd and msgrcv syscalls expect the data to start at
>msg.mtext,
>
        Well, it really isn't that obvious. The man page is *not* a
misprint, and the .h file is "correct" also. What is happening here is
a rather tricky piece of "C" coding to permit *variable* sized arrays
to be passed without allocating all the space necessary for the
maximum size, and without any real maximum size. Basically it is
taking advantage of the fact that "C" doesn't check array subscripts
and the way in which address calculation is done. Basically the
declared array in the struct is only being used as the *base* of the
array. Subscripting off that base will access succesively higher
addresses, so that a unit "array" at the end of a struct can
effectively be extended indefinately, merely by allocating space at
the end of it. The way this is intended to be used is

    struct msgbuf *msgptr;

    msgptr = (struct msgbuf *)malloc(sizeof(struct msgbuf) + sizeof(message));

This way your msgbuf exactly matches the size of your message.

Yeah, I know, a really obscure trick. I know about it because it is
also used in the game Hack.
--

                                Sarima (Stanley Friesen)

UUCP: {ttidca|ihnp4|sdcrdcf|quad1|nrcvax|bellcore|logico}!psivax!friesen
ARPA: ttidca!psivax!friesen@rand-unix.arpa

bet@ecsvax.UUCP (Bennett E. Todd III) (02/13/86)

In article <2666@gatech.CSNET> hope@gatech.CSNET (Theodore Hope) writes:
> [...]
>The man pages for msgop(2) describe the msgbuf struct as containing
>
>	long mtype;     /* message type */
>	char mtext [];  /* message text */
>
> [...] The .h file defines
>
>	struct msgbuf {
>	   long mtype;
>	   char mtext [1];	<- Notice: it says [1]
>	}
> [...]

You should follow net.lang.c; this has popped up there. What you are
seeing is a C hack to permit variable-length structs. What you want to
say is

	struct msgbuf {
		long mtype;	/* message type */
		char mtext [];	/* variable length, NULL-terminated */
	}

but the C compiler croaks on that, so you use an array dimension of 1.
Note that the only member of a struct that can get away with being
varying length is the last member, and that only works because C doesn't
do array bounds checking. So anyway, how do you use it? Like so. Say,
perhaps, I am building messages in my own private array

	char textbuff[MAXMSGLEN];

then when I want to pass one in I roll up an empty struct msgbuf as
follows:
	struct msgbuf *tmp_ptr;
	char *malloc();
	...
	tmp_ptr = (struct msgbuf *) malloc(sizeof(struct msgbuf) +
						strlen(textbuff));
	if (tmp_ptr == NULL)
		perror(...);
	strcpy(tmp_ptr.mtext, textbuff);

I kind of like the technique; it allows you to use as much space as
needed and no more, without too much overhead or nuisance. Last I
recall, the concensus was that the technique should be reasonably
portable to any but the most rabidly pathological machine architectures.

-Bennett
-- 

Bennett Todd -- Duke Computation Center, Durham, NC 27706-7756; (919) 684-3695
UUCP: ...{decvax,seismo,philabs,ihnp4,akgua}!mcnc!ecsvax!duccpc!bet

bet@ecsvax.UUCP (Bennett E. Todd III) (02/13/86)

In article <2666@gatech.CSNET> hope@gatech.CSNET (Theodore Hope) writes:
> [...]
>The man pages for msgop(2) describe the msgbuf struct as containing
>
>	long mtype;     /* message type */
>	char mtext [];  /* message text */
>
> [...] The .h file defines
>
>	struct msgbuf {
>	   long mtype;
>	   char mtext [1];	<- Notice: it says [1]
>	}
> [...]

You should follow net.lang.c; this has popped up there. What you are
seeing is a C hack to permit variable-length structs. What you want to
say is

	struct msgbuf {
		long mtype;	/* message type */
		char mtext [];	/* variable length, NULL-terminated */
	}

but the C compiler croaks on that, so you use an array dimension of 1.
Note that the only member of a struct that can get away with being
varying length is the last member, and that only works because C doesn't
do array bounds checking. So anyway, how do you use it? Like so. Say,
perhaps, I am building messages in my own private array

	char textbuff[MAXMTEXT];

then when I want to pass one in I roll up an empty struct msgbuf as
follows:
	struct msgbuf *tmp_ptr;
	char *malloc();
	...
	tmp_ptr = (struct msgbuf *) malloc(sizeof(struct msgbuf) +
						strlen(textbuff));
	if (tmp_ptr == NULL)
		perror(...);
	strcpy(tmp_ptr.mtext, textbuff);

I kind of like the technique; it allows you to use as much space as
needed and no more, without too much overhead or nuisance. Last I
recall, the consensus was that the technique should be reasonably
portable to any but the most rabidly pathological machine architectures.

-Bennett
-- 

Bennett Todd -- Duke Computation Center, Durham, NC 27706-7756; (919) 684-3695
UUCP: ...{decvax,seismo,philabs,ihnp4,akgua}!mcnc!ecsvax!duccpc!bet

gwyn@brl-smoke.ARPA (Doug Gwyn ) (02/16/86)

In article <2666@gatech.CSNET> hope@gatech.CSNET (Theodore Hope) writes:
>
>The man pages for msgop(2) describe the msgbuf struct as containing
>
>	long mtype;     /* message type */
>	char mtext [];  /* message text */
>
>This kind of struc, especially in a syscall-passing sense, seems odd to me.
>It is obvious that mtext should be
>
>	char mtext [some_number];
>
>"Oh," said I.  "I'll bet that's a misprint.  Let's look at the <sys/msg.h>
>file to see what they _really_ mean."  Well, surprise.  The .h file defines
>
>	struct msgbuf {
>	   long mtype;
>	   char mtext [1];	<- Notice: it says [1]
>	}
>
>Am I overlooking something obvious?  After looking through the kernel source,
>it appeared that the msgsnd and msgrcv syscalls expect the data to start at 
>msg.mtext, so by defining my own structs as
>
>	struct Msgbuf {
>	   long mtype;
>	   char mtext [MAXMTEXT];
>	}
>
>everything is ok.

You got it right.  The C language provides no way to declare
a variable-length array in a struct, so the prototype in the
documentation and the declaration in the header file represent
the array as best they can.  From a design standpoint it would
have been preferable for the struct to have contained a
pointer to the message buffer rather than the buffer itself,
but that's not the way they designed it.