Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 14 Jul 2002 22:36:42 +0200
From:      Thomas Moestl <tmoestl@gmx.net>
To:        Luigi Rizzo <luigi@freebsd.org>
Cc:        current@freebsd.org
Subject:   Re: different packing of structs in kernel vs. userland ?
Message-ID:  <20020714203642.GD314@crow.dom2ip.de>
In-Reply-To: <20020714011810.A72236@iguana.icir.org>
References:  <20020714011810.A72236@iguana.icir.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Sun, 2002/07/14 at 01:18:10 -0700, Luigi Rizzo wrote:
> Hi,
> the following message seems to suggest that the compiler
> (the way it is invoked) packs structures differently
> when building the kernel and userland.
> 
> The stize of the structure in question is computed
> by both kernel and userland app using sizeof(),
> so there is no assumption on the size of its members,
> so i believe the only possibility of a mismatch is
> the one above.
> 
> Any ideas ?

(Disclaimer: my solution below is untested, so it may all be bogus)

No, you are not accounting for "external" structure padding. Take a
look: 

  struct ip_fw {
	  struct ip_fw	*next;		/* linked list of rules	*/
	  u_int16_t	act_ofs;	/* offset of action in 32-bit units */
	  u_int16_t	cmd_len;	/* # of 32-bit words in cmd	*/
	  u_int16_t	rulenum;	/* rule number			*/
	  u_int16_t	_pad;		/* padding			*/

	  /* These fields are present in all rules.			*/
	  u_int64_t	pcnt;		/* Packet counter		*/
	  u_int64_t	bcnt;		/* Byte counter			*/
	  u_int32_t	timestamp;	/* tv_sec of last match		*/

	  struct ip_fw *next_rule;	/* ptr to next rule		*/

	  ipfw_insn	cmd[1];		/* storage for commands		*/
  };

On a 64-bit architecture, pointers are obviously 8 bytes in size;
structure members must or should be on natural borders, depending on
the architecture.
So, next_rule will not be on a natural border; 4 bytes of padding will
be inserted before it. With that, the total structure size would be
52.
The compiler must account for the fact that an array of struct ip_fws
may be used. For obvious reasons, it can not just insert extra padding
in the array case; instead, the structure size must be chosen so that
in this situation, the first member will be on a natural border.
This results in an extra 4 bytes of "external" padding at the end,
after the member 'cmd'.
The macro you use to compute the size in the kernel is:

  #define RULESIZE(rule)  (sizeof(struct ip_fw) + \
	  ((struct ip_fw *)(rule))->cmd_len * 4 - 4)

In the userland code, you start at &foo.cmd and append data
directly. This means that the padding will also be used to store
data, so the '- 4' (= sizeof(foo.cmd)) will not always be enough. The
following definition of RULESIZE (untested) should fix this:

  #define RULESIZE(rule)  (offsetof(struct ip_fw, cmd) + \
	  ((struct ip_fw *)(rule))->cmd_len * 4)

It also removes the explicit 4 for sizeof(ipfw_insn).

	- thomas

-- 
Thomas Moestl <tmoestl@gmx.net>	http://www.tu-bs.de/~y0015675/
              <tmm@FreeBSD.org>	http://people.FreeBSD.org/~tmm/
PGP fingerprint: 1C97 A604 2BD0 E492 51D0  9C0F 1FE6 4F1D 419C 776C

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020714203642.GD314>