Date: Mon, 15 Jul 2002 14:49:48 +0200 From: Thomas Moestl <tmoestl@gmx.net> To: Luigi Rizzo <luigi@FreeBSD.org> Cc: Mike Barcroft <mike@FreeBSD.org>, current@FreeBSD.org Subject: Re: different packing of structs in kernel vs. userland ? Message-ID: <20020715124947.GB314@crow.dom2ip.de> In-Reply-To: <20020715040008.A85276@iguana.icir.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>
next in thread | previous in thread | raw e-mail | index | archive | help
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 <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?20020715124947.GB314>