From owner-freebsd-current Mon Jul 15 5:49:11 2002 Delivered-To: freebsd-current@freebsd.org Received: from mx1.FreeBSD.org (mx1.FreeBSD.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 25F6237B405 for ; Mon, 15 Jul 2002 05:49:08 -0700 (PDT) Received: from mail.gmx.net (mail.gmx.net [213.165.64.20]) by mx1.FreeBSD.org (Postfix) with SMTP id 148E243E67 for ; Mon, 15 Jul 2002 05:49:06 -0700 (PDT) (envelope-from tmoestl@gmx.net) Received: (qmail 19410 invoked by uid 0); 15 Jul 2002 12:49:03 -0000 Received: from p5086fd16.dip.t-dialin.net (HELO forge.local) (80.134.253.22) by mail.gmx.net (mp012-rz3) with SMTP; 15 Jul 2002 12:49:03 -0000 Received: from tmm by forge.local with local (Exim 3.36 #1) id 17U5IS-0000hW-00; Mon, 15 Jul 2002 14:49:48 +0200 Date: Mon, 15 Jul 2002 14:49:48 +0200 From: Thomas Moestl To: Luigi Rizzo Cc: Mike Barcroft , current@FreeBSD.org Subject: Re: different packing of structs in kernel vs. userland ? Message-ID: <20020715124947.GB314@crow.dom2ip.de> Mail-Followup-To: Luigi Rizzo , Mike Barcroft , current@FreeBSD.org References: <20020714011810.A72236@iguana.icir.org> <20020714203642.GD314@crow.dom2ip.de> <20020714230821.C64412@espresso.q9media.com> <20020715105158.GA314@crow.dom2ip.de> <20020715040008.A85276@iguana.icir.org> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20020715040008.A85276@iguana.icir.org> User-Agent: Mutt/1.4i Sender: owner-freebsd-current@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG On Mon, 2002/07/15 at 04:00:08 -0700, Luigi Rizzo wrote: > sorry but all this just does not make sense to me. > > sizeof(foo) should give the same result irrespective of > where you use it. OK, let me rephrase it: as I explained before, struct ip_fw has padding after 'cmd' (the last member) to ensure that arrays can be built from it safely, so that the first member will always be properly aligned. Since the first members must/should be aligned on an 8-bit boundary on 64-bit platforms, this means that sizeof(struct ip_fw) must be a multiple of 8, the size of the padding is 4 bytes (unless the situation is changed by reordering structure members). This can easily be checked on a 64-bit platform. The following program fragment: struct ip_fw f; printf("sizeof(ip_fw) = %d\n", (int)sizeof(f)); printf("offsetof(ip_fw, cmd) = %d\n", (int)offsetof(struct ip_fw, cmd)); printf("sizeof(ip_fw.cmd) = %d\n", (int)sizeof(f.cmd)); Produces this output on sparc64: sizeof(ip_fw) = 56 offsetof(ip_fw, cmd) = 48 sizeof(ip_fw.cmd) = 4 This illustrates that indeed, padding is appended after 'cmd'. In the (userland) ipfw2.c, you basically do the following: ipfw_insn *dst; /* sizeof(ipfw_insn) = 4 */ dst = (ipfw_insn *)rule->cmd; /* Write n instructions and increase dst accordingly. */ rule->cmd_len = (u_int32_t *)dst - (u_int32_t *)(rule->cmd); i = (void *)dst - (void *)rule; if (getsockopt(s, IPPROTO_IP, IP_FW_ADD, rule, &i) == -1) err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD"); Let's consider the case where only one instruction was added. In this case, dst was incremented once and points directly after cmd, so i is 52 on a 64-bit platform. However, sizeof(struct ip_fw) is 56 because the aformentioned 4 bytes of padding following 'cmd', so i < sizeof(struct ip_fw). This explains why rules with just one instruction would not work properly in this case with just my first patch. Likewise, when adding more rules, the second one will be added to the memory location directly following 'cmd'. If padding is present, the second instruction will write into it. The size of the total structure will thus not be properly computed by the old RULESIZE macro: #define RULESIZE(rule) (sizeof(struct ip_fw) + \ ((struct ip_fw *)(rule))->cmd_len * 4 - 4) The '- 4' is meant to subtract the size of the cmd, which is accounted for in cmd_len. Still, you are counting the padding twice, once in the sizeof() and once in cmd_len. So, sizeof(struct ip_fw) is no different between userland and kernel, but the problem is that you don't use sizeof(struct ip_fw) in userland to compute the sizes (but pointer arithmetic), but you do use it for the checks in the kernel. - thomas -- Thomas Moestl http://www.tu-bs.de/~y0015675/ 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