linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Vlastimil Babka <vbabka@suse.cz>
To: Hyeonggon Yoo <42.hyeyoo@gmail.com>
Cc: kernel test robot <lkp@intel.com>,
	kbuild-all@lists.01.org,
	Linux Memory Management List <linux-mm@kvack.org>,
	Andrew Morton <akpm@linux-foundation.org>
Subject: Re: [linux-next:master 7012/7430] include/linux/compiler_types.h:328:38: error: call to '__compiletime_assert_183' declared with attribute error: unexpected size in kmalloc_index()
Date: Thu, 10 Jun 2021 13:43:08 +0200	[thread overview]
Message-ID: <513f82e6-175c-d040-691c-5d0e7dacfb83@suse.cz> (raw)
In-Reply-To: <20210608184501.GA5505@hyeyoo>

On 6/8/21 8:45 PM, Hyeonggon Yoo wrote:
>> > mm.. when the size passed to bpf_map_kmalloc_node is not constant,
>> > (__builtin_constant_p(size) && size <= KMALLOC_MAX_CACHE_SIZE) is false.
>> > then __builtin_constant_p(!!false) is true. So it calls kmalloc_index.
>> > 
>> > what change should be made?
>> > just checking CONFIG_PROFILE_ALL_BRANCHES to kmalloc_index's if condition
>> > doesn't make sense, because kmalloc_node is not working as expected.
>>
>> If I understood my colleagues right, the problem is that, while kmalloc_index()
>> seems to contains a number of *independent* "if (size <= X) conditions in a
>> sequence, the machinery of CONFIG_PROFILE_ALL_BRANCHES turns it to a deeply
>> nested if-then-else { if-then-else { if-then-else {...}}} thing (in fact using
>> the ternary operators, not if-then-else).
>> At some point of the deep nesting gcc
>> "forgets" that __builtin_constant_p() is true and starts behaving as if it wasn't.
>> 
>> Without CONFIG_PROFILE_ALL_BRANCHES it's able to keep track of it fine.
>>
> 
> I think you are talking about some if statements in kmalloc_index.
> 
> How do you know gcc "forgets" __builtin_constant_p() is true?
> can it be debugged using cvise? (not offending, just because
> I don't know about cvise yet).
> 
> Also, as I understand right, kmalloc_index doesn't have information
> about the value of __builtin_constant_p(size). the caller of
> kmalloc_index (kmalloc_node here) has that information.
> 
> If I understand right, what CONFIG_PROFILE_ALL_BRANCHES does is below.
> 
> replacing if(cond) { body } -> if (
> 						__builtin_constant_p(cond) ?
> 							then (cond)
> 						else (cond, record something)
> 					) { body }
> 
> I think it does not make deep nested statements.

OK, might have been a misunderstanding of cvise output.
So I don't know why exactly there are false positives with
CONFIG_PROFILE_ALL_BRANCHES.

> the below is some part of preprocessor output.
> CONFIG_PROFILE_ALL_BRANCHES makes some ugly ternary operators,
> but there is no deep-nested if-then-else statements.
> 
> if ( (__builtin_constant_p(!!(size <= 8)) ? (!!(size <= 8)) : ({ static struct ftrace_branch_data __attribute__((__aligned__(4))) __attribute__((__section__("_ftrace_branch"))) __if_trace = { .func = __func__, .file = "include/linux/slab.h", .line = 392, }; (!!(size <= 8)) ? (__if_trace.miss_hit[1]++,1) : (__if_trace.miss_hit[0]++,0); })) ) return 3;
> 
> if ( (__builtin_constant_p(!!(size <= 16)) ? (!!(size <= 16)) : ({ static struct ftrace_branch_data __attribute__((__aligned__(4))) __attribute__((__section__("_ftrace_branch"))) __if_trace = { .func = __func__, .file = "include/linux/slab.h", .line = 393, }; (!!(size <= 16)) ? (__if_trace.miss_hit[1]++,1) : (__if_trace.miss_hit[0]++,0); })) ) return 4;
> 
> if ( (__builtin_constant_p(!!(size <= 32)) ? (!!(size <= 32)) : ({ static struct ftrace_branch_data __attribute__((__aligned__(4))) __attribute__((__section__("_ftrace_branch"))) __if_trace = { .func = __func__, .file = "include/linux/slab.h", .line = 394, }; (!!(size <= 32)) ? (__if_trace.miss_hit[1]++,1) : (__if_trace.miss_hit[0]++,0); })) ) return 5;
> 
> .... and some if statements ...
> 
> And I think, the problem is on kmalloc_node, not on kmalloc_index.
> the original code of kmalloc_node is below:
> 
> 
> static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
>   {
>   #ifndef CONFIG_SLOB
>         if (__builtin_constant_p(size) &&
>               size <= KMALLOC_MAX_CACHE_SIZE) {
>               unsigned int i = kmalloc_index(size);
> 
> and which is changed to below: (by CONFIG_PROFILE_ALL_BRANCHES)
> 
> static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
> {
> 
> 	if ( (
> 		__builtin_constant_p(
> 		!!(__builtin_constant_p(size) && size <= (1UL << ((11 + 12 - 1) <= 25 ? (11 + 12 - 1) : 25)))
> 		)
> 			? (!!(__builtin_constant_p(size) && size <= (1UL << ((11 + 12 - 1) <= 25 ? (11 + 12 - 1) : 25)))) 
> 			: ({ static struct ftrace_branch_data __attribute__((__aligned__(4))) __attribute__((__section__("_ftrace_branch"))) __if_trace = { .func = __func__, .file = "include/linux/slab.h", .line = 601, }; (!!(__builtin_constant_p(size) && size <= (1UL << ((11 + 12 - 1) <= 25 ? (11 + 12 - 1) : 25)))) ? (__if_trace.miss_hit[1]++,1) : (__if_trace.miss_hit[0]++,0); })) )
>                                   {
>   unsigned int i = __kmalloc_index(size, true);
> 
> 
> they are so ugly but the point is:
> 
>> > It seems that gcc evaluates
>> > 
>> > __builtin_constant_p(
>> > 				!!(builtin_constant_p(size)
>> > 				&& size <= KMALLOC_MAX_CACHE_SIZE)
>> > 			)
>> > 	as true.
>> > 
>> > mm.. when the size passed to bpf_map_kmalloc_node is not constant,
>> > (__builtin_constant_p(size) && size <= KMALLOC_MAX_CACHE_SIZE) is false.
>> > then __builtin_constant_p(!!false) is true. So it calls kmalloc_index.
>> > 
>> > what change should be made?
>> > just checking CONFIG_PROFILE_ALL_BRANCHES to kmalloc_index's if condition
>> > doesn't make sense, because kmalloc_node is not working as expected.
> 
> some evidence to add:
> 
> 	there are 4 calls of bpf_map_kmalloc_node.
> 	if you comment out two calls of bpf_map_kmalloc_node with non-constant
> 	(in line 168, 508), it doesn't make an error. So I thought
> 	it was problem when non-constant size was passed.
> 
> 	And if "kmalloc_index makes problem with non-constant size" is
> 	true, then it is caller's fault because it is not allowed (except
> 	in __kmalloc_index)
> 
> 	kmalloc_node shouldn't call kmalloc_index if the size was not
> 	constant.

Yes. You could perhaps exclude CONFIG_PROFILE_ALL_BRANCHES for now, and fill
official gcc bugzilla with the preprocessed file.
Bonus points if you can use cvise in a way that reduces the testcase but does
not remove any of the important parts. All we could get were degenerate cases
like this one
https://paste.opensuse.org/9320186

>> > void *kmalloc_node(size_t size, gfp_t flags, int node){
>> > 
>> >  if ( (__builtin_constant_p(
>> >        !!(__builtin_constant_p(size)
>> >        && size <= (1UL << ((11 + 12 - 1) <= 25 ? (11 + 12 - 1) : 25))))
>> >             ? (!!(__builtin_constant_p(size) && size <= (1UL << ((11 + 12 - 1) <= 25 ? (11 + 12 - 1) : 25))))
> 
> 
>> > if ( (__builtin_constant_p(!!((0 || 110000 >= 110000) && size_is_constant)) ? (!!((0 || 110000 >= 110000) && size_is_constant)) : ({ static struct ftrace_branch_data __attribute__((__aligned__(4))) __attribute__((__section__("_ftrace_branch"))) __if_trace = { .func = __func__, .file = "include/linux/slab.h", .line = 416, }; (!!((0 || 110000 >= 110000) && size_is_constant)) ? (__if_trace.miss_hit[1]++,1) : (__if_trace.miss_hit[0]++,0); })) )
>> >   do {
>> > 
>> > 
>> >         extern void __compiletime_assert_131(void) ;
>> > 	  // here - compiletime_assert_131 does NOTHING
>> 
>> It doesn't seem to do nothing? see below
>> 
>> > 		if ( (__builtin_constant_p(!!(!(!(1))))
>> >               ? (!!(!(!(1))))
>> >               : ({ static struct ftrace_branch_data __attribute__((__aligned__(4))) __attribute__((__section__("_ftrace_branch"))) __if_trace = { .func = __func__, .file = "include/linux/slab.h", .line = 417, }; (!!(!(!(1)))) ? (__if_trace.miss_hit[1]++,1) : (__if_trace.miss_hit[0]++,0); })) ) __compiletime_assert_131(); } while (0);
>> 
>> The thing above seems to be exactly the "if (!(condition))
>> prefix ## suffix();   } while (0)" as the definition you posted below.
>> 
>> Anyway, you can verify that clang works by commenting out the highest size
>> checks and passing a constant size that makes it reach the  BUILD_BUG_ON_MSG() ?
>> 
> 
> I verified as below.
> clang didn't make an error, gcc worked as expected.
> 
> then I can explain why there is no error with clang:
> 	it just did nothing with BUILD_BUG_ON.

That might warrant a clang bug report too. We excluded clang 10 due to false
positives. If the BUILD_BUG_ON doesn't work at all in clang 11 we might have to
exclude clang completely.

> hyeyoo@hyeyoo:~/바탕화면/linux-next$ git diff
> diff --git a/include/linux/slab.h b/include/linux/slab.h
> index 8d8dd8571261..f2f9a6a7e663 100644
> --- a/include/linux/slab.h
> +++ b/include/linux/slab.h
> @@ -379,6 +379,9 @@ static __always_inline enum kmalloc_cache_type kmalloc_type(gfp_t flags)
>  static __always_inline unsigned int __kmalloc_index(size_t size,
>                                                     bool size_is_constant)
>  {
> +
> +       BUILD_BUG_ON(1);
> +
>         if (!size)
>                 return 0;
> 
> hyeyoo@hyeyoo:~/바탕화면/linux-next$ make mm/kfence/kfence_test.o CC=clang-11
>   CALL    scripts/checksyscalls.sh
> 
> 	... some headers omitted ...
> 
>   CC      mm/kfence/kfence_test.o
> In file included from <command-line>:
> In function ‘__kmalloc_index’,
>     inlined from ‘kmalloc_cache_alignment’ at mm/kfence/kfence_test.c:200:50:
> ././include/linux/compiler_types.h:328:38: error: call to ‘__compiletime_assert_131’ declared with attribute error: BUILD_BUG_ON failed: 1
>   328 |  _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
>       |                                      ^
> ././include/linux/compiler_types.h:309:4: note: in definition of macro ‘__compiletime_assert’
>   309 |    prefix ## suffix();    \
>       |    ^~~~~~
> ././include/linux/compiler_types.h:328:2: note: in expansion of macro ‘_compiletime_assert’
>   328 |  _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
>       |  ^~~~~~~~~~~~~~~~~~~
> ./include/linux/build_bug.h:39:37: note: in expansion of macro ‘compiletime_assert’
>    39 | #define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg)
>       |                                     ^~~~~~~~~~~~~~~~~~
> ./include/linux/build_bug.h:50:2: note: in expansion of macro ‘BUILD_BUG_ON_MSG’
>    50 |  BUILD_BUG_ON_MSG(condition, "BUILD_BUG_ON failed: " #condition)
>       |  ^~~~~~~~~~~~~~~~
> ./include/linux/slab.h:383:2: note: in expansion of macro ‘BUILD_BUG_ON’
>   383 |  BUILD_BUG_ON(1);
>       |  ^~~~~~~~~~~~
> In function ‘__kmalloc_index’,
>     inlined from ‘test_alloc’ at mm/kfence/kfence_test.c:271:47:
> ././include/linux/compiler_types.h:328:38: error: call to ‘__compiletime_assert_131’ declared with attribute error: BUILD_BUG_ON failed: 1
>   328 |  _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
>       |                                      ^
> ././include/linux/compiler_types.h:309:4: note: in definition of macro ‘__compiletime_assert’
>   309 |    prefix ## suffix();    \
>       |    ^~~~~~
> ././include/linux/compiler_types.h:328:2: note: in expansion of macro ‘_compiletime_assert’
>   328 |  _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
>       |  ^~~~~~~~~~~~~~~~~~~
> ./include/linux/build_bug.h:39:37: note: in expansion of macro ‘compiletime_assert’
>    39 | #define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg)
>       |                                     ^~~~~~~~~~~~~~~~~~
> ./include/linux/build_bug.h:50:2: note: in expansion of macro ‘BUILD_BUG_ON_MSG’
>    50 |  BUILD_BUG_ON_MSG(condition, "BUILD_BUG_ON failed: " #condition)
>       |  ^~~~~~~~~~~~~~~~
> ./include/linux/slab.h:383:2: note: in expansion of macro ‘BUILD_BUG_ON’
>   383 |  BUILD_BUG_ON(1);
>       |  ^~~~~~~~~~~~
> make[2]: *** [scripts/Makefile.build:272: mm/kfence/kfence_test.o] 오류 1
> make[1]: *** [scripts/Makefile.build:533: mm/kfence] 오류 2
> make: *** [Makefile:1948: mm] 오류 2
> 



  parent reply	other threads:[~2021-06-10 11:43 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-06-05  6:10 kernel test robot
2021-06-06 11:08 ` Hyeonggon Yoo
2021-06-07 11:40   ` Vlastimil Babka
2021-06-07 12:25     ` Hyeonggon Yoo
2021-06-07 15:27       ` Vlastimil Babka
2021-06-07 15:49         ` Hyeonggon Yoo
2021-06-08  7:57           ` Vlastimil Babka
2021-06-08 17:05             ` Hyeonggon Yoo
2021-06-08 17:27               ` Vlastimil Babka
2021-06-08 18:45                 ` Hyeonggon Yoo
2021-06-08 18:50                   ` Hyeonggon Yoo
2021-06-10  5:17                   ` Some logical errors on my words, but I still wonder Hyeonggon Yoo
2021-06-10 11:43                   ` Vlastimil Babka [this message]
     [not found]                     ` <CAB=+i9StdrGQWXXoQHKU5oLK3eKuNcuCAbrd88kPLzM_Yw==Jg@mail.gmail.com>
2021-06-11 16:56                       ` [linux-next:master 7012/7430] include/linux/compiler_types.h:328:38: error: call to '__compiletime_assert_183' declared with attribute error: unexpected size in kmalloc_index() Nathan Chancellor
2021-06-12  0:31                         ` Hyeonggon Yoo
     [not found]                       ` <d89798b1-ac4f-ab3e-27be-b1d40b8d7193@suse.cz>
     [not found]                         ` <CAB=+i9Snmu7ML3Zqrbii1-jtS0BF_KeGEhn-R49Z2bh=uW-rGg@mail.gmail.com>
2021-06-11 23:59                           ` Vlastimil Babka
2021-06-12  0:19                             ` Hyeonggon Yoo
2021-06-14  9:26                               ` [PATCH FIX -next] " Vlastimil Babka

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=513f82e6-175c-d040-691c-5d0e7dacfb83@suse.cz \
    --to=vbabka@suse.cz \
    --cc=42.hyeyoo@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=kbuild-all@lists.01.org \
    --cc=linux-mm@kvack.org \
    --cc=lkp@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox