diff mbox series

[mm] kfence: fix printk format for ptrdiff_t

Message ID 20210303121157.3430807-1-elver@google.com (mailing list archive)
State New, archived
Headers show
Series [mm] kfence: fix printk format for ptrdiff_t | expand

Commit Message

Marco Elver March 3, 2021, 12:11 p.m. UTC
Use %td for ptrdiff_t.

Link: https://lkml.kernel.org/r/3abbe4c9-16ad-c168-a90f-087978ccd8f7@csgroup.eu
Reported-by: Christophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: Marco Elver <elver@google.com>
---
 mm/kfence/report.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

Comments

Alexander Potapenko March 3, 2021, 12:27 p.m. UTC | #1
On Wed, Mar 3, 2021 at 1:12 PM Marco Elver <elver@google.com> wrote:
>
> Use %td for ptrdiff_t.
>
> Link: https://lkml.kernel.org/r/3abbe4c9-16ad-c168-a90f-087978ccd8f7@csgroup.eu
> Reported-by: Christophe Leroy <christophe.leroy@csgroup.eu>
> Signed-off-by: Marco Elver <elver@google.com>
Reviewed-by: Alexander Potapenko <glider@google.com>
Christophe Leroy March 16, 2021, 8:32 a.m. UTC | #2
+segher

Le 03/03/2021 à 13:27, Alexander Potapenko a écrit :
> On Wed, Mar 3, 2021 at 1:12 PM Marco Elver <elver@google.com> wrote:
>>
>> Use %td for ptrdiff_t.
>>
>> Link: https://lkml.kernel.org/r/3abbe4c9-16ad-c168-a90f-087978ccd8f7@csgroup.eu
>> Reported-by: Christophe Leroy <christophe.leroy@csgroup.eu>
>> Signed-off-by: Marco Elver <elver@google.com>
> Reviewed-by: Alexander Potapenko <glider@google.com>
> 

Still a problem.

I don't understand, gcc bug ?

The offending argument is 'const ptrdiff_t object_index'

We have:

arch/powerpc/include/uapi/asm/posix_types.h:typedef long		__kernel_ptrdiff_t;
include/linux/types.h:typedef __kernel_ptrdiff_t	ptrdiff_t;

And get:

   CC      mm/kfence/report.o
In file included from ./include/linux/printk.h:7,
                  from ./include/linux/kernel.h:16,
                  from mm/kfence/report.c:10:
mm/kfence/report.c: In function 'kfence_report_error':
./include/linux/kern_levels.h:5:18: warning: format '%td' expects argument of type 'ptrdiff_t', but 
argument 6 has type 'long int' [-Wformat=]
     5 | #define KERN_SOH "\001"  /* ASCII Start Of Header */
       |                  ^~~~~~
./include/linux/kern_levels.h:11:18: note: in expansion of macro 'KERN_SOH'
    11 | #define KERN_ERR KERN_SOH "3" /* error conditions */
       |                  ^~~~~~~~
./include/linux/printk.h:343:9: note: in expansion of macro 'KERN_ERR'
   343 |  printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
       |         ^~~~~~~~
mm/kfence/report.c:213:3: note: in expansion of macro 'pr_err'
   213 |   pr_err("Out-of-bounds %s at 0x%p (%luB %s of kfence-#%td):\n",
       |   ^~~~~~
./include/linux/kern_levels.h:5:18: warning: format '%td' expects argument of type 'ptrdiff_t', but 
argument 4 has type 'long int' [-Wformat=]
     5 | #define KERN_SOH "\001"  /* ASCII Start Of Header */
       |                  ^~~~~~
./include/linux/kern_levels.h:11:18: note: in expansion of macro 'KERN_SOH'
    11 | #define KERN_ERR KERN_SOH "3" /* error conditions */
       |                  ^~~~~~~~
./include/linux/printk.h:343:9: note: in expansion of macro 'KERN_ERR'
   343 |  printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
       |         ^~~~~~~~
mm/kfence/report.c:222:3: note: in expansion of macro 'pr_err'
   222 |   pr_err("Use-after-free %s at 0x%p (in kfence-#%td):\n",
       |   ^~~~~~
./include/linux/kern_levels.h:5:18: warning: format '%td' expects argument of type 'ptrdiff_t', but 
argument 2 has type 'long int' [-Wformat=]
     5 | #define KERN_SOH "\001"  /* ASCII Start Of Header */
       |                  ^~~~~~
./include/linux/kern_levels.h:24:19: note: in expansion of macro 'KERN_SOH'
    24 | #define KERN_CONT KERN_SOH "c"
       |                   ^~~~~~~~
./include/linux/printk.h:385:9: note: in expansion of macro 'KERN_CONT'
   385 |  printk(KERN_CONT fmt, ##__VA_ARGS__)
       |         ^~~~~~~~~
mm/kfence/report.c:229:3: note: in expansion of macro 'pr_cont'
   229 |   pr_cont(" (in kfence-#%td):\n", object_index);
       |   ^~~~~~~
./include/linux/kern_levels.h:5:18: warning: format '%td' expects argument of type 'ptrdiff_t', but 
argument 3 has type 'long int' [-Wformat=]
     5 | #define KERN_SOH "\001"  /* ASCII Start Of Header */
       |                  ^~~~~~
./include/linux/kern_levels.h:11:18: note: in expansion of macro 'KERN_SOH'
    11 | #define KERN_ERR KERN_SOH "3" /* error conditions */
       |                  ^~~~~~~~
./include/linux/printk.h:343:9: note: in expansion of macro 'KERN_ERR'
   343 |  printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
       |         ^~~~~~~~
mm/kfence/report.c:239:3: note: in expansion of macro 'pr_err'
   239 |   pr_err("Invalid free of 0x%p (in kfence-#%td):\n", (void *)address,
       |   ^~~~~~


Christophe
Segher Boessenkool March 16, 2021, 3:33 p.m. UTC | #3
On Tue, Mar 16, 2021 at 09:32:32AM +0100, Christophe Leroy wrote:
> +segher

I cannot see through the wood of #defines here, sorry.

> Still a problem.
> 
> I don't understand, gcc bug ?

Rule #1: If you do not understand what is happening, it is not a
compiler bug.  I'm not saying that it isn't, just that it is much more
likely something else.

> The offending argument is 'const ptrdiff_t object_index'
> 
> We have:
> 
> arch/powerpc/include/uapi/asm/posix_types.h:typedef long	 
> __kernel_ptrdiff_t;

So this is a 64-bit build.

> include/linux/types.h:typedef __kernel_ptrdiff_t	ptrdiff_t;
> 
> And get:
> 
>   CC      mm/kfence/report.o
> In file included from ./include/linux/printk.h:7,
>                  from ./include/linux/kernel.h:16,
>                  from mm/kfence/report.c:10:
> mm/kfence/report.c: In function 'kfence_report_error':
> ./include/linux/kern_levels.h:5:18: warning: format '%td' expects argument 
> of type 'ptrdiff_t', but argument 6 has type 'long int' [-Wformat=]

This is declared as
        const ptrdiff_t object_index = meta ? meta - kfence_metadata : -1;
so maybe something with that goes wrong?  What happens if you delete the
(useless) "const" here?


Segher
Christophe Leroy March 16, 2021, 3:40 p.m. UTC | #4
Le 16/03/2021 à 16:33, Segher Boessenkool a écrit :
> On Tue, Mar 16, 2021 at 09:32:32AM +0100, Christophe Leroy wrote:
>> +segher
> 
> I cannot see through the wood of #defines here, sorry.
> 
>> Still a problem.
>>
>> I don't understand, gcc bug ?
> 
> Rule #1: If you do not understand what is happening, it is not a
> compiler bug.  I'm not saying that it isn't, just that it is much more
> likely something else.
> 
>> The offending argument is 'const ptrdiff_t object_index'
>>
>> We have:
>>
>> arch/powerpc/include/uapi/asm/posix_types.h:typedef long	
>> __kernel_ptrdiff_t;
> 
> So this is a 64-bit build.

No it's 32 bits. The code in posix-types.h is

#ifdef __powerpc64__
...
#else
...
typedef long		__kernel_ptrdiff_t;


> 
>> include/linux/types.h:typedef __kernel_ptrdiff_t	ptrdiff_t;
>>
>> And get:
>>
>>    CC      mm/kfence/report.o
>> In file included from ./include/linux/printk.h:7,
>>                   from ./include/linux/kernel.h:16,
>>                   from mm/kfence/report.c:10:
>> mm/kfence/report.c: In function 'kfence_report_error':
>> ./include/linux/kern_levels.h:5:18: warning: format '%td' expects argument
>> of type 'ptrdiff_t', but argument 6 has type 'long int' [-Wformat=]
> 
> This is declared as
>          const ptrdiff_t object_index = meta ? meta - kfence_metadata : -1;
> so maybe something with that goes wrong?  What happens if you delete the
> (useless) "const" here?

No change.

Christophe
David Laight March 17, 2021, 12:51 p.m. UTC | #5
From: Christophe Leroy
> Sent: 16 March 2021 15:41
...
> >> include/linux/types.h:typedef __kernel_ptrdiff_t	ptrdiff_t;
> >>
> >> And get:
> >>
> >>    CC      mm/kfence/report.o
> >> In file included from ./include/linux/printk.h:7,
> >>                   from ./include/linux/kernel.h:16,
> >>                   from mm/kfence/report.c:10:
> >> mm/kfence/report.c: In function 'kfence_report_error':
> >> ./include/linux/kern_levels.h:5:18: warning: format '%td' expects argument
> >> of type 'ptrdiff_t', but argument 6 has type 'long int' [-Wformat=]
> >
> > This is declared as
> >          const ptrdiff_t object_index = meta ? meta - kfence_metadata : -1;
> > so maybe something with that goes wrong?  What happens if you delete the
> > (useless) "const" here?

The obvious thing to try is changing it to 'int'.
That will break 64bit builds, but if it fixes the 32bit one
it will tell you what type gcc is expecting.

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
Christophe Leroy March 17, 2021, 5:35 p.m. UTC | #6
Le 17/03/2021 à 13:51, David Laight a écrit :
> From: Christophe Leroy
>> Sent: 16 March 2021 15:41
> ...
>>>> include/linux/types.h:typedef __kernel_ptrdiff_t	ptrdiff_t;
>>>>
>>>> And get:
>>>>
>>>>     CC      mm/kfence/report.o
>>>> In file included from ./include/linux/printk.h:7,
>>>>                    from ./include/linux/kernel.h:16,
>>>>                    from mm/kfence/report.c:10:
>>>> mm/kfence/report.c: In function 'kfence_report_error':
>>>> ./include/linux/kern_levels.h:5:18: warning: format '%td' expects argument
>>>> of type 'ptrdiff_t', but argument 6 has type 'long int' [-Wformat=]
>>>
>>> This is declared as
>>>           const ptrdiff_t object_index = meta ? meta - kfence_metadata : -1;
>>> so maybe something with that goes wrong?  What happens if you delete the
>>> (useless) "const" here?
> 
> The obvious thing to try is changing it to 'int'.
> That will break 64bit builds, but if it fixes the 32bit one
> it will tell you what type gcc is expecting.
> 

Yes, if defining 'object_index' as int, gcc is happy.
If removing the powerpc re-definition of ptrdiff_t typedef in 
https://elixir.bootlin.com/linux/v5.12-rc3/source/arch/powerpc/include/uapi/asm/posix_types.h , it 
works great as well.

So seems like gcc doesn't take into account the typedef behind ptrdiff_t, it just expects it to be 
int on 32 bits ?

Christophe
David Laight March 18, 2021, 9:14 a.m. UTC | #7
From: Christophe Leroy
> Sent: 17 March 2021 17:35
> 
> Le 17/03/2021 à 13:51, David Laight a écrit :
> > From: Christophe Leroy
> >> Sent: 16 March 2021 15:41
> > ...
> >>>> include/linux/types.h:typedef __kernel_ptrdiff_t	ptrdiff_t;
> >>>>
> >>>> And get:
> >>>>
> >>>>     CC      mm/kfence/report.o
> >>>> In file included from ./include/linux/printk.h:7,
> >>>>                    from ./include/linux/kernel.h:16,
> >>>>                    from mm/kfence/report.c:10:
> >>>> mm/kfence/report.c: In function 'kfence_report_error':
> >>>> ./include/linux/kern_levels.h:5:18: warning: format '%td' expects argument
> >>>> of type 'ptrdiff_t', but argument 6 has type 'long int' [-Wformat=]
> >>>
> >>> This is declared as
> >>>           const ptrdiff_t object_index = meta ? meta - kfence_metadata : -1;
> >>> so maybe something with that goes wrong?  What happens if you delete the
> >>> (useless) "const" here?
> >
> > The obvious thing to try is changing it to 'int'.
> > That will break 64bit builds, but if it fixes the 32bit one
> > it will tell you what type gcc is expecting.
> >
> 
> Yes, if defining 'object_index' as int, gcc is happy.
> If removing the powerpc re-definition of ptrdiff_t typedef in
> https://elixir.bootlin.com/linux/v5.12-rc3/source/arch/powerpc/include/uapi/asm/posix_types.h , it
> works great as well.
> 
> So seems like gcc doesn't take into account the typedef behind ptrdiff_t, it just expects it to be
> int on 32 bits ?

gcc never cares how ptrdiff_t (or any of the related types) is defined
it requires int or long for the format depending on the architecture.
The error message will say ptrdiff_t or size_t (etc) - but that is just
in the error message.

So the ppc32 uapi definition of __kernel_ptrdiff_t is wrong.
However it is probably set in stone.

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
Christophe Leroy March 18, 2021, 9:38 a.m. UTC | #8
Le 18/03/2021 à 10:14, David Laight a écrit :
> From: Christophe Leroy
>> Sent: 17 March 2021 17:35
>>
>> Le 17/03/2021 à 13:51, David Laight a écrit :
>>> From: Christophe Leroy
>>>> Sent: 16 March 2021 15:41
>>> ...
>>>>>> include/linux/types.h:typedef __kernel_ptrdiff_t	ptrdiff_t;
>>>>>>
>>>>>> And get:
>>>>>>
>>>>>>      CC      mm/kfence/report.o
>>>>>> In file included from ./include/linux/printk.h:7,
>>>>>>                     from ./include/linux/kernel.h:16,
>>>>>>                     from mm/kfence/report.c:10:
>>>>>> mm/kfence/report.c: In function 'kfence_report_error':
>>>>>> ./include/linux/kern_levels.h:5:18: warning: format '%td' expects argument
>>>>>> of type 'ptrdiff_t', but argument 6 has type 'long int' [-Wformat=]
>>>>>
>>>>> This is declared as
>>>>>            const ptrdiff_t object_index = meta ? meta - kfence_metadata : -1;
>>>>> so maybe something with that goes wrong?  What happens if you delete the
>>>>> (useless) "const" here?
>>>
>>> The obvious thing to try is changing it to 'int'.
>>> That will break 64bit builds, but if it fixes the 32bit one
>>> it will tell you what type gcc is expecting.
>>>
>>
>> Yes, if defining 'object_index' as int, gcc is happy.
>> If removing the powerpc re-definition of ptrdiff_t typedef in
>> https://elixir.bootlin.com/linux/v5.12-rc3/source/arch/powerpc/include/uapi/asm/posix_types.h , it
>> works great as well.
>>
>> So seems like gcc doesn't take into account the typedef behind ptrdiff_t, it just expects it to be
>> int on 32 bits ?
> 
> gcc never cares how ptrdiff_t (or any of the related types) is defined
> it requires int or long for the format depending on the architecture.
> The error message will say ptrdiff_t or size_t (etc) - but that is just
> in the error message.
> 
> So the ppc32 uapi definition of __kernel_ptrdiff_t is wrong.
> However it is probably set in stone.
> 

Yes it seems to be wrong. It was changed by commit d27dfd3887 ("Import pre2.0.8"), so that's long 
time ago. Before that it was an 'int' for ppc32.

gcc provides ptrdiff_t in stddef.h via __PTRDIFF_TYPE__
gcc defined __PTRDIFF_TYPE__ as 'int' at build time.

Should we fix it in arch/powerpc/include/uapi/asm/posix_types.h ? Anyway 'long' and 'int' makes no 
functionnal difference on 32 bits so there should be no impact for users if any.

Christophe
Segher Boessenkool March 19, 2021, 11:37 a.m. UTC | #9
On Thu, Mar 18, 2021 at 10:38:43AM +0100, Christophe Leroy wrote:
> Yes it seems to be wrong. It was changed by commit d27dfd3887 ("Import 
> pre2.0.8"), so that's long time ago. Before that it was an 'int' for ppc32.
> 
> gcc provides ptrdiff_t in stddef.h via __PTRDIFF_TYPE__
> gcc defined __PTRDIFF_TYPE__ as 'int' at build time.

(On 32-bit PowerPC Linux.)

> Should we fix it in arch/powerpc/include/uapi/asm/posix_types.h ?

I think so, yes.

> Anyway 
> 'long' and 'int' makes no functionnal difference on 32 bits so there should 
> be no impact for users if any.

Except that long and int are different types, which causes errors like
what you have here.  There may be similar fallout from changing it back.


Segher
diff mbox series

Patch

diff --git a/mm/kfence/report.c b/mm/kfence/report.c
index ab83d5a59bb1..519f037720f5 100644
--- a/mm/kfence/report.c
+++ b/mm/kfence/report.c
@@ -116,12 +116,12 @@  void kfence_print_object(struct seq_file *seq, const struct kfence_metadata *met
 	lockdep_assert_held(&meta->lock);
 
 	if (meta->state == KFENCE_OBJECT_UNUSED) {
-		seq_con_printf(seq, "kfence-#%zd unused\n", meta - kfence_metadata);
+		seq_con_printf(seq, "kfence-#%td unused\n", meta - kfence_metadata);
 		return;
 	}
 
 	seq_con_printf(seq,
-		       "kfence-#%zd [0x%p-0x%p"
+		       "kfence-#%td [0x%p-0x%p"
 		       ", size=%d, cache=%s] allocated by task %d:\n",
 		       meta - kfence_metadata, (void *)start, (void *)(start + size - 1), size,
 		       (cache && cache->name) ? cache->name : "<destroyed>", meta->alloc_track.pid);
@@ -204,7 +204,7 @@  void kfence_report_error(unsigned long address, bool is_write, struct pt_regs *r
 
 		pr_err("BUG: KFENCE: out-of-bounds %s in %pS\n\n", get_access_type(is_write),
 		       (void *)stack_entries[skipnr]);
-		pr_err("Out-of-bounds %s at 0x%p (%luB %s of kfence-#%zd):\n",
+		pr_err("Out-of-bounds %s at 0x%p (%luB %s of kfence-#%td):\n",
 		       get_access_type(is_write), (void *)address,
 		       left_of_object ? meta->addr - address : address - meta->addr,
 		       left_of_object ? "left" : "right", object_index);
@@ -213,14 +213,14 @@  void kfence_report_error(unsigned long address, bool is_write, struct pt_regs *r
 	case KFENCE_ERROR_UAF:
 		pr_err("BUG: KFENCE: use-after-free %s in %pS\n\n", get_access_type(is_write),
 		       (void *)stack_entries[skipnr]);
-		pr_err("Use-after-free %s at 0x%p (in kfence-#%zd):\n",
+		pr_err("Use-after-free %s at 0x%p (in kfence-#%td):\n",
 		       get_access_type(is_write), (void *)address, object_index);
 		break;
 	case KFENCE_ERROR_CORRUPTION:
 		pr_err("BUG: KFENCE: memory corruption in %pS\n\n", (void *)stack_entries[skipnr]);
 		pr_err("Corrupted memory at 0x%p ", (void *)address);
 		print_diff_canary(address, 16, meta);
-		pr_cont(" (in kfence-#%zd):\n", object_index);
+		pr_cont(" (in kfence-#%td):\n", object_index);
 		break;
 	case KFENCE_ERROR_INVALID:
 		pr_err("BUG: KFENCE: invalid %s in %pS\n\n", get_access_type(is_write),
@@ -230,7 +230,7 @@  void kfence_report_error(unsigned long address, bool is_write, struct pt_regs *r
 		break;
 	case KFENCE_ERROR_INVALID_FREE:
 		pr_err("BUG: KFENCE: invalid free in %pS\n\n", (void *)stack_entries[skipnr]);
-		pr_err("Invalid free of 0x%p (in kfence-#%zd):\n", (void *)address,
+		pr_err("Invalid free of 0x%p (in kfence-#%td):\n", (void *)address,
 		       object_index);
 		break;
 	}