[RFC patch] vsprintf: Allow %pe to print non PTR_ERR %pe uses as decimal

From: Joe Perches
Date: Wed Mar 24 2021 - 13:21:31 EST


On Wed, 2021-03-24 at 09:52 -0700, Joe Perches wrote:
> On Wed, 2021-03-24 at 17:42 +0100, Arnd Bergmann wrote:
> > On Wed, Mar 24, 2021 at 3:20 PM Joe Perches <joe@xxxxxxxxxxx> wrote:
> []
> > > > diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
> > > []
> > > > @@ -197,6 +197,12 @@ static void imx_ldb_encoder_enable(struct drm_encoder *encoder)
> > > >       int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
> > > >       int mux = drm_of_encoder_active_port_id(imx_ldb_ch->child, encoder);
> > > >
> > > > + if (mux < 0 || mux >= ARRAY_SIZE(ldb->clk_sel)) {
> > > > + dev_warn(ldb->dev, "%s: invalid mux %d\n",
> > > > + __func__, ERR_PTR(mux));
> > >
> > > This does not compile without warnings.
> > >
> > > drivers/gpu/drm/imx/imx-ldb.c: In function ‘imx_ldb_encoder_enable’:
> > > drivers/gpu/drm/imx/imx-ldb.c:201:22: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘void *’ [-Wformat=]
> > >   201 | dev_warn(ldb->dev, "%s: invalid mux %d\n",
> > >       | ^~~~~~~~~~~~~~~~~~~~~~
> > >
> > > If you want to use ERR_PTR, the %d should be %pe as ERR_PTR
> > > is converting an int a void * to decode the error type and
> > > emit it as a string.
> >
> > Sorry about that.
> >
> > I decided against using ERR_PTR() in order to also check for
> > positive array overflow, but the version I tested was different from
> > the version I sent.
> >
> > v3 coming.
>
> Thanks. No worries.
>
> Up to you, vsprintf would emit the positive mux as a funky hashed
> hex value by default if you use ERR_PTR with mux > ARRAY_SIZE so
> perhaps %d without the ERR_PTR use makes the most sense.
>
>

Maybe it's better to output non PTR_ERR %pe uses as decimal so this
sort of code would work.
---
lib/vsprintf.c | 24 +++++++++++++-----------
1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 3600db686fa4..debdd1c62038 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -619,19 +619,23 @@ static char *string_nocheck(char *buf, char *end, const char *s,
return widen_string(buf, len, end, spec);
}

-static char *err_ptr(char *buf, char *end, void *ptr,
- struct printf_spec spec)
+static noinline_for_stack
+char *err_ptr(char *buf, char *end, void *ptr, struct printf_spec spec)
{
int err = PTR_ERR(ptr);
- const char *sym = errname(err);

- if (sym)
- return string_nocheck(buf, end, sym, spec);
+ if (IS_ERR(ptr)) {
+ const char *sym = errname(err);
+
+ if (sym)
+ return string_nocheck(buf, end, sym, spec);
+ }

/*
- * Somebody passed ERR_PTR(-1234) or some other non-existing
- * Efoo - or perhaps CONFIG_SYMBOLIC_ERRNAME=n. Fall back to
- * printing it as its decimal representation.
+ * Somebody passed ERR_PTR(-1234) or some other non-existing -E<FOO>
+ * or perhaps CONFIG_SYMBOLIC_ERRNAME=n
+ * or perhaps a positive number like an array index
+ * Fall back to printing it as its decimal representation.
*/
spec.flags |= SIGN;
spec.base = 10;
@@ -2407,9 +2411,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
case 'x':
return pointer_string(buf, end, ptr, spec);
case 'e':
- /* %pe with a non-ERR_PTR gets treated as plain %p */
- if (!IS_ERR(ptr))
- break;
+ /* %pe with a non-ERR_PTR(ptr) gets treated as %ld */
return err_ptr(buf, end, ptr, spec);
case 'u':
case 'k':

---