add drivers/misc/build-asserts.c to test BUILD_BUG_DECL. BUILD_BUG_DECL works as intended, but __attribute((unused)) appears to be ineffective in the macro: cmp_ints() run at __init time is able to reference the storage w/o warnings (no section complaints, even though those functions are not explicitly marked as __init - I guess thats inferred..). cmp_ints() run from mod-param getter/setter callbacks pukes badly. I guess this is to be expected, since __initdata is dropped once boot is complete. But why no compile warnings ?? root@voyage:~# cat /sys/module/build_asserts/parameters/* build_asserts.cbint_get: got bufp:c65cd000='' kp:c8bb967c build_asserts.cbint_get: kp-name:cbint build_asserts.cbint_get: kp-arg:c8bb9113 build_asserts.cbint_get: kp-ops:c8bb973c build_asserts.cbint_get: kp-ops-set:c8bb9179 build_asserts.cbint_get: kp-ops-get:c8bb9000 build_asserts.cbint_get: cbint_get me:c8bb9000 BUG: unable to handle kernel paging request at c8bbb000 IP: [<c8bb90d8>] cbint_get+0xd8/0x113 [build_asserts] *pde = 06c76067 *pte = 00000000 Oops: 0000 [#1] PREEMPT Modules linked in: build_asserts scx200_gpio scx200_hrt pc8736x_gpio nsc_gpio pc87360 hwmon_vid scx200_acb acx_mac80211(O) arc4 rtl8180 mac80211 eeprom_93cx6 scx200 cfg80211 ohci_hcd pata_sc1200 [last unloaded: build_asserts] Pid: 1364, comm: cat Tainted: G O 3.4.0-rc1-ske+ #24 EIP: 0060:[<c8bb90d8>] EFLAGS: 00010282 CPU: 0 EIP is at cbint_get+0xd8/0x113 [build_asserts] EAX: 00000035 EBX: c65cd000 ECX: c7450000 EDX: 00000003 ESI: c8bb967c EDI: c65cd000 EBP: c7451efc ESP: c7451ee0 DS: 007b ES: 007b FS: 0000 GS: 00e0 SS: 0068 CR0: 8005003b CR2: c8bbb000 CR3: 066b7000 CR4: 00000000 DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 DR6: ffff0ff0 DR7: 00000400 Process cat (pid: 1364, ti=c7450000 task=c6524f80 task.ti=c7450000) Stack: c8bb945e c8bb96bc c8bb9000 c65cd000 c8bb967c ffffffff c675c270 c7451f10 c012f536 c675c270 c8bb9790 c012f503 c7451f24 c012f35b c6507740 c60deb40 c043eb28 c7451f70 c02010d5 c6753680 00000000 c7451f44 c027fe90 c6753680 Call Trace: [<c8bb9000>] ? 0xc8bb8fff [<c012f536>] param_attr_show+0x33/0x57 [<c012f503>] ? __kernel_param_unlock+0x14/0x14 [<c012f35b>] module_attr_show+0x21/0x26 [<c02010d5>] sysfs_read_file+0x9e/0x154 [<c027fe90>] ? security_file_permission+0x27/0x2b [<c01bb5ee>] ? rw_verify_area+0xd0/0xf2 [<c01bb956>] vfs_read+0x8d/0xd3 [<c0201037>] ? sysfs_open_file+0x1fa/0x1fa [<c01bb9de>] sys_read+0x42/0x63 [<c043592c>] syscall_call+0x7/0xb Code: 04 24 3a 94 bb c8 89 44 24 08 e8 89 7c 87 f7 c7 44 24 08 00 90 bb c8 c7 44 24 04 bc 96 bb c8 c7 04 24 5e 94 bb c8 e8 6d 7c 87 f7 <a1> 00 b0 bb c8 c7 44 24 04 bc 96 bb c8 89 44 24 0c 89 44 24 08 EIP: [<c8bb90d8>] cbint_get+0xd8/0x113 [build_asserts] SS:ESP 0068:c7451ee0 CR2: 00000000c8bbb000 ---[ end trace bfbcc6aee803d03b ]--- Signed-off-by: Jim Cromie <jim.cromie@xxxxxxxxx> --- drivers/misc/Makefile | 2 + drivers/misc/build-asserts.c | 239 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 241 insertions(+), 0 deletions(-) create mode 100644 drivers/misc/build-asserts.c diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 3e1d801..5aff6bb 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -49,3 +49,5 @@ obj-y += carma/ obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/ obj-$(CONFIG_MAX8997_MUIC) += max8997-muic.o + +obj-m += build-asserts.o diff --git a/drivers/misc/build-asserts.c b/drivers/misc/build-asserts.c new file mode 100644 index 0000000..4a051b5 --- /dev/null +++ b/drivers/misc/build-asserts.c @@ -0,0 +1,239 @@ + +#define pr_fmt(fmt) KBUILD_MODNAME ".%s: " fmt, __FUNCTION__ + +#include <linux/kernel.h> +#include <linux/bug.h> +#include <linux/stringify.h> +#include <linux/module.h> +#include <linux/init.h> + +int a[] = {1,2,3,4}; +int b[] = {1,2,3,5}; +int c[] = {3,5}; +long d[] = {1,2}; + +const char *names[] = { "bart", "lisa", "homer", "marge" }; + +struct bridge { + int member_ids[4]; + char *names[4]; + char *snacks[3]; // hungry ? +} clubs[4]; + +BUILD_BUG_DECL(foo, ARRAY_SIZE(a) != ARRAY_SIZE(b)); +BUILD_BUG_DECL(buz, sizeof(a) != sizeof(b)); // good +// BUILD_BUG_DECL(a, sizeof(a) != sizeof(d)); // brittle +BUILD_BUG_DECL(b, ARRAY_SIZE(a) != ARRAY_SIZE(names)); // good, on different types + +// BUILD_BUG_DECL(d, ARRAY_SIZE(a) != ARRAY_SIZE(d)); // compile err, correct +// BUILD_BUG_DECL(bonk, sizeof(a) != sizeof(names)); // breaks, correct +// BUILD_BUG_DECL(ac, sizeof(a) != sizeof(c)); // err + + +BUILD_BUG_DECL(joe, ARRAY_SIZE(a) != ARRAY_SIZE(clubs)); +BUILD_BUG_DECL(bob, ARRAY_SIZE(a) != ARRAY_SIZE(clubs[0].member_ids)); +BUILD_BUG_DECL(mike, ARRAY_SIZE(a) != ARRAY_SIZE(clubs[0].names)); + +// BUILD_BUG_DECL(sue, ARRAY_SIZE(a) != ARRAY_SIZE(clubs[0].snacks)); +// cant use typeof like this +// BUILD_BUG_DECL(ike, typeof(clubs[0].snacks) != typeof(clubs[0].names)); + +union { + int a; + long b; + char c; + char *s; + int arr[4]; +} pba; + +// these cause warning at file scope, but ok inside fn. +// warning: variably modified ‘field’ at file scope [enabled by default] +// BUILD_BUG_DECL(x, (void*)&pba.a != (void*)&pba.b); +// BUILD_BUG_DECL(y, (void*)&pba.a != (void*)&pba.c); + +int cmp_ints(int sz, int *arg1, int *arg2) +{ + int i; + + // NG: compiler doesnt know the arrays passed. + // BUILD_BUG_DECL(y, ARRAY_SIZE(*arg1) != ARRAY_SIZE(*arg2)); + + pr_notice("all equal ?\n"); + for (i=0; i<sz; i++) { + pr_notice("%d ?= %d\n", arg1[i], arg2[i]); + if (arg1[i] != arg2[i]) { + pr_notice("nope\n"); + return 1; + } + } + pr_notice("yup\n"); + i = BUILD_BUG_DECL_mike[0].BUILD_BUG_DECL_mike[0]; + pr_notice("i-mike %d\n", i); + return 0; +} + +// ok, but hmm +BUILD_BUG_DECL(fn, sizeof(cmp_ints) != sizeof(cmp_ints)); + +int use_cmp_ints(void) +{ + int i = 20, j = 30; + + BUILD_BUG_DECL(foo, ARRAY_SIZE(a) != ARRAY_SIZE(b)); + BUILD_BUG_DECL(a, (void*)&pba.a != (void*)&pba.b); + + pr_notice("hello\n"); + cmp_ints(4, a, b); + + pr_notice("i:%d j:%d\n", i, j); + + // derefs w/o error !! + i = BUILD_BUG_DECL_a[0].BUILD_BUG_DECL_a[0]; + j = BUILD_BUG_DECL_mike[0].BUILD_BUG_DECL_mike[0]; + + pr_notice("access a? %d, %d\n", i, + BUILD_BUG_DECL_a[0].BUILD_BUG_DECL_a[0]); + pr_notice("access mike? %d, %d\n", i, + BUILD_BUG_DECL_mike[0].BUILD_BUG_DECL_mike[0]); + + //BUILD_BUG_DECL_a[0].a_sizecheck = 1; + return 0; +} +// ok, but obviously useless +BUILD_BUG_DECL(fn2, sizeof(cmp_ints) != sizeof(use_cmp_ints)); + +/* + for some reason, refs to BUILD_BUG_DECL_* declarations works in + *cmp_ints(), despite unused attribute and placement in __initdata. + Maybe this is cuz *cmp_ints() is (so far) called from module_init, + where it should work. + + So code below adds mod-params and getter/setters to try to invoke it + during runtime, to see what happens. + + Apparently what happens is kernel fault. That makes some sense + given that __init is no longer current, and has been dropped. But + why is referencing initdata not flagged by compiler ?? + +root@voyage:~# cat /sys/module/build_asserts/parameters/cbint +build_asserts.cbint_get: got bufp:c65cd000='' kp:c8bb967c +build_asserts.cbint_get: kp-name:cbint +build_asserts.cbint_get: kp-arg:c8bb9113 +build_asserts.cbint_get: kp-ops:c8bb973c +build_asserts.cbint_get: kp-ops-set:c8bb9179 +build_asserts.cbint_get: kp-ops-get:c8bb9000 +build_asserts.cbint_get: cbint_get me:c8bb9000 +BUG: unable to handle kernel paging request at c8bbb000 +IP: [<c8bb90d8>] cbint_get+0xd8/0x113 [build_asserts] +*pde = 06c76067 *pte = 00000000 +Oops: 0000 [#1] PREEMPT +Modules linked in: build_asserts scx200_gpio scx200_hrt pc8736x_gpio nsc_gpio pc87360 hwmon_vid scx200_acb acx_mac80211(O) arc4 rtl8180 mac80211 eeprom_93cx6 scx200 cfg80211 ohci_hcd pata_sc1200 [last unloaded: build_asserts] + +Pid: 1364, comm: cat Tainted: G O 3.4.0-rc1-ske+ #24 +EIP: 0060:[<c8bb90d8>] EFLAGS: 00010282 CPU: 0 +EIP is at cbint_get+0xd8/0x113 [build_asserts] +EAX: 00000035 EBX: c65cd000 ECX: c7450000 EDX: 00000003 +ESI: c8bb967c EDI: c65cd000 EBP: c7451efc ESP: c7451ee0 + DS: 007b ES: 007b FS: 0000 GS: 00e0 SS: 0068 +CR0: 8005003b CR2: c8bbb000 CR3: 066b7000 CR4: 00000000 +DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000 +DR6: ffff0ff0 DR7: 00000400 +Process cat (pid: 1364, ti=c7450000 task=c6524f80 task.ti=c7450000) +Stack: + c8bb945e c8bb96bc c8bb9000 c65cd000 c8bb967c ffffffff c675c270 c7451f10 + c012f536 c675c270 c8bb9790 c012f503 c7451f24 c012f35b c6507740 c60deb40 + c043eb28 c7451f70 c02010d5 c6753680 00000000 c7451f44 c027fe90 c6753680 +Call Trace: + [<c8bb9000>] ? 0xc8bb8fff + [<c012f536>] param_attr_show+0x33/0x57 + [<c012f503>] ? __kernel_param_unlock+0x14/0x14 + [<c012f35b>] module_attr_show+0x21/0x26 + [<c02010d5>] sysfs_read_file+0x9e/0x154 + [<c027fe90>] ? security_file_permission+0x27/0x2b + [<c01bb5ee>] ? rw_verify_area+0xd0/0xf2 + [<c01bb956>] vfs_read+0x8d/0xd3 + [<c0201037>] ? sysfs_open_file+0x1fa/0x1fa + [<c01bb9de>] sys_read+0x42/0x63 + [<c043592c>] syscall_call+0x7/0xb + + */ + +int decl_user(void) +{ + // BUILD_BUG_DECL(ac, sizeof(a) != sizeof(c)); // errors, properly + + // no complaints testing the union from here. + BUILD_BUG_DECL(x, (void*)&pba.a != (void*)&pba.c); + // fine for use inside a struct + BUILD_BUG_DECL(y, ARRAY_SIZE(clubs[1].names) + != ARRAY_SIZE(clubs[0].member_ids)); + + return 0; +} + +// not usable as a mod-param, boot-only I guess +// also, gives unused warning at compile ? +static int __init bar_setup(char *str) +{ + pr_notice("bar setup: %s\n", str); + decl_user(); + use_cmp_ints(); + return 1; +} +__setup("bar=", bar_setup); + +static int cbvar = 0; +static int cbint_set(const char *val, const struct kernel_param *kp) +{ + int i; + int err = param_set_int(val, kp); + + pr_notice("err: %d val:%s", err, val); + if (err) + return err; + + i = BUILD_BUG_DECL_mike[0].BUILD_BUG_DECL_mike[0]; + pr_notice("access mike? %d, %d\n", i, + BUILD_BUG_DECL_mike[0].BUILD_BUG_DECL_mike[0]); + + return 0; +} +static int cbint_get(char *buffer, const struct kernel_param *kp) +{ + int i; + + pr_notice("got bufp:%p='%s' kp:%p\n", buffer, buffer, kp); + pr_notice("kp-name:%s\n", kp->name); + pr_notice("kp-arg:%p\n", kp->arg); + pr_notice("kp-ops:%p\n", kp->ops); + pr_notice("kp-ops-set:%p\n", kp->ops->set); + pr_notice("kp-ops-get:%p\n", kp->ops->get); + pr_notice("cbint_get me:%p\n", &cbint_get); + + i = BUILD_BUG_DECL_mike[0].BUILD_BUG_DECL_mike[0]; + pr_notice("access mike? %d, %d\n", i, + BUILD_BUG_DECL_mike[0].BUILD_BUG_DECL_mike[0]); + + strcpy(buffer, "hello from cbint_get"); + return strlen(buffer); +} +static struct kernel_param_ops cbint_ops = { + .set = cbint_set, + .get = cbint_get, // need one, no default provided +}; +module_param_cb(cbint, &cbint_ops, "cbint-arg", 0644); + +static int fooint; +module_param_named(foo, fooint, int, 0644); + +void myexit(void) +{ + pr_notice("bye\n"); +} + +module_init(use_cmp_ints); +module_exit(myexit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("jim.cromie@xxxxxxxxx"); +MODULE_DESCRIPTION("test BUILD_BUG_DECL"); -- 1.7.8.1 _______________________________________________ Kernelnewbies mailing list Kernelnewbies@xxxxxxxxxxxxxxxxx http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies