Thread: Remove unnecessary static type qualifiers

Remove unnecessary static type qualifiers

From
Japin Li
Date:
Hi, all

When I read the libpq source code, I found unnecessary static type qualifiers
in PQsetClientEncoding().

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 0258d9ace3c..300ddfffd55 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -7717,7 +7717,7 @@ int
 PQsetClientEncoding(PGconn *conn, const char *encoding)
 {
     char        qbuf[128];
-    static const char query[] = "set client_encoding to '%s'";
+    const char    query[] = "set client_encoding to '%s'";
     PGresult   *res;
     int            status;
 


-- 
Regrads,
Japin Li



Re: Remove unnecessary static type qualifiers

From
Junwang Zhao
Date:
On Tue, Apr 8, 2025 at 4:29 PM Japin Li <japinli@hotmail.com> wrote:
>
>
> Hi, all
>
> When I read the libpq source code, I found unnecessary static type qualifiers
> in PQsetClientEncoding().
>
> diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
> index 0258d9ace3c..300ddfffd55 100644
> --- a/src/interfaces/libpq/fe-connect.c
> +++ b/src/interfaces/libpq/fe-connect.c
> @@ -7717,7 +7717,7 @@ int
>  PQsetClientEncoding(PGconn *conn, const char *encoding)
>  {
>         char            qbuf[128];
> -       static const char query[] = "set client_encoding to '%s'";
> +       const char      query[] = "set client_encoding to '%s'";
>         PGresult   *res;
>         int                     status;
>

I doubt that, if you remove the *static*, it will allocate more memory
on stack and need more instructions to copy the string to that area.

You can check the assembly to prove this.

Here is what I got on macos M3 chip.

with static:

0000000000015710 <_PQsetClientEncoding>:
   15710: d10383ff      sub     sp, sp, #0xe0
   15714: a90d7bfd      stp     x29, x30, [sp, #0xd0]
   15718: 910343fd      add     x29, sp, #0xd0
   1571c: f00002a8      adrp    x8, 0x6c000 <_write+0x6c000>
   15720: f941a908      ldr     x8, [x8, #0x350]
   15724: f9400108      ldr     x8, [x8]
   15728: f81f83a8      stur    x8, [x29, #-0x8]
   1572c: f9001fe0      str     x0, [sp, #0x38]
   15730: f9001be1      str     x1, [sp, #0x30]
   15734: f9401fe8      ldr     x8, [sp, #0x38]
   15738: f1000108      subs    x8, x8, #0x0
   1573c: 1a9f17e8      cset    w8, eq
   15740: 37000108      tbnz    w8, #0x0, 0x15760 <_PQsetClientEncoding+0x50>
   15744: 14000001      b       0x15748 <_PQsetClientEncoding+0x38>
   15748: f9401fe8      ldr     x8, [sp, #0x38]
   1574c: b941f908      ldr     w8, [x8, #0x1f8]

without:

00000000000156ec <_PQsetClientEncoding>:
   156ec: d10443ff      sub     sp, sp, #0x110
   156f0: a90f6ffc      stp     x28, x27, [sp, #0xf0]
   156f4: a9107bfd      stp     x29, x30, [sp, #0x100]
   156f8: 910403fd      add     x29, sp, #0x100
   156fc: f00002a8      adrp    x8, 0x6c000 <_write+0x6c000>
   15700: f941a908      ldr     x8, [x8, #0x350]
   15704: f9400108      ldr     x8, [x8]
   15708: f81e83a8      stur    x8, [x29, #-0x18]
   1570c: f9001be0      str     x0, [sp, #0x30]
   15710: f90017e1      str     x1, [sp, #0x28]
   15714: f00001c9      adrp    x9, 0x50000 <_write+0x50000>
   15718: 913ded29      add     x9, x9, #0xf7b
   1571c: 3dc00120      ldr     q0, [x9]
   15720: 910103e8      add     x8, sp, #0x40
   15724: 3d8013e0      str     q0, [sp, #0x40]
   15728: 3cc0c120      ldur    q0, [x9, #0xc]
   1572c: 3c80c100      stur    q0, [x8, #0xc]
   15730: f9401be8      ldr     x8, [sp, #0x30]
   15734: f1000108      subs    x8, x8, #0x0
   15738: 1a9f17e8      cset    w8, eq
   1573c: 37000108      tbnz    w8, #0x0, 0x1575c <_PQsetClientEncoding+0x70>
   15740: 14000001      b       0x15744 <_PQsetClientEncoding+0x58>
   15744: f9401be8      ldr     x8, [sp, #0x30]
   15748: b941f908      ldr     w8, [x8, #0x1f8]

>
>
> --
> Regrads,
> Japin Li
>
>


--
Regards
Junwang Zhao



Re: Remove unnecessary static type qualifiers

From
Tom Lane
Date:
Junwang Zhao <zhjwpku@gmail.com> writes:
> On Tue, Apr 8, 2025 at 4:29 PM Japin Li <japinli@hotmail.com> wrote:
>> -       static const char query[] = "set client_encoding to '%s'";
>> +       const char      query[] = "set client_encoding to '%s'";

> I doubt that, if you remove the *static*, it will allocate more memory
> on stack and need more instructions to copy the string to that area.

Yeah, it's not an improvement as written.  This might be OK:

>> +       const char      *query = "set client_encoding to '%s'";

But I kinda doubt it's worth touching.

            regards, tom lane



Re: Remove unnecessary static type qualifiers

From
Peter Eisentraut
Date:
On 08.04.25 14:22, Junwang Zhao wrote:
>> When I read the libpq source code, I found unnecessary static type qualifiers
>> in PQsetClientEncoding().
>>
>> diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
>> index 0258d9ace3c..300ddfffd55 100644
>> --- a/src/interfaces/libpq/fe-connect.c
>> +++ b/src/interfaces/libpq/fe-connect.c
>> @@ -7717,7 +7717,7 @@ int
>>   PQsetClientEncoding(PGconn *conn, const char *encoding)
>>   {
>>          char            qbuf[128];
>> -       static const char query[] = "set client_encoding to '%s'";
>> +       const char      query[] = "set client_encoding to '%s'";
>>          PGresult   *res;
>>          int                     status;
>>
> 
> I doubt that, if you remove the *static*, it will allocate more memory
> on stack and need more instructions to copy the string to that area.

To avoid creating an array on the stack, you could maybe write it with a 
pointer instead, like:

const char * const query = "...";

I haven't tested whether that results in different or better compiled 
code.  The original code is probably good enough.




Re: Remove unnecessary static type qualifiers

From
David Rowley
Date:
On Wed, 9 Apr 2025 at 03:46, Peter Eisentraut <peter@eisentraut.org> wrote:
> To avoid creating an array on the stack, you could maybe write it with a
> pointer instead, like:
>
> const char * const query = "...";
>
> I haven't tested whether that results in different or better compiled
> code.  The original code is probably good enough.

I expect it's been done the way it has to make the overflow detection
code work. The problem with having a pointer to a string constant is
that sizeof() will return the size of the pointer and not the space
needed to store the string.

We can get rid of the variable and make the overflow work by checking
the return length of snprintf. I think that's all C99 spec now...

len = snprintf(qbuf, "set client_encoding to '%s'", encoding);
/* check query buffer overflow */
if (len >= sizeof(qbuf))
    return -1;

David



Re: Remove unnecessary static type qualifiers

From
Junwang Zhao
Date:
On Wed, Apr 9, 2025 at 5:22 AM David Rowley <dgrowleyml@gmail.com> wrote:
>
> On Wed, 9 Apr 2025 at 03:46, Peter Eisentraut <peter@eisentraut.org> wrote:
> > To avoid creating an array on the stack, you could maybe write it with a
> > pointer instead, like:
> >
> > const char * const query = "...";
> >
> > I haven't tested whether that results in different or better compiled
> > code.  The original code is probably good enough.
>
> I expect it's been done the way it has to make the overflow detection
> code work. The problem with having a pointer to a string constant is
> that sizeof() will return the size of the pointer and not the space
> needed to store the string.
>
> We can get rid of the variable and make the overflow work by checking
> the return length of snprintf. I think that's all C99 spec now...
>
> len = snprintf(qbuf, "set client_encoding to '%s'", encoding);
> /* check query buffer overflow */
> if (len >= sizeof(qbuf))
>     return -1;
>

Agree, this is a better coding style. Please see if the following code makes
sense to you.

diff --git a/src/interfaces/libpq/fe-connect.c
b/src/interfaces/libpq/fe-connect.c
index 0258d9ace3c..247d079faa6 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -7717,9 +7717,9 @@ int
 PQsetClientEncoding(PGconn *conn, const char *encoding)
 {
        char            qbuf[128];
-       static const char query[] = "set client_encoding to '%s'";
        PGresult   *res;
        int                     status;
+       int                     len;

        if (!conn || conn->status != CONNECTION_OK)
                return -1;
@@ -7731,12 +7731,11 @@ PQsetClientEncoding(PGconn *conn, const char *encoding)
        if (strcmp(encoding, "auto") == 0)
                encoding =
pg_encoding_to_char(pg_get_encoding_from_locale(NULL, true));

-       /* check query buffer overflow */
-       if (sizeof(qbuf) < (sizeof(query) + strlen(encoding)))
+       len = snprintf(qbuf, sizeof(qbuf), "set client_encoding to
'%s'", encoding);
+       if (len >= sizeof(qbuf))
                return -1;

        /* ok, now send a query */
-       sprintf(qbuf, query, encoding);
        res = PQexec(conn, qbuf);

        if (res == NULL)

> David



--
Regards
Junwang Zhao



Re: Remove unnecessary static type qualifiers

From
Japin Li
Date:
On Wed, 09 Apr 2025 at 10:34, Junwang Zhao <zhjwpku@gmail.com> wrote:
> On Wed, Apr 9, 2025 at 5:22 AM David Rowley <dgrowleyml@gmail.com> wrote:
>>
>> On Wed, 9 Apr 2025 at 03:46, Peter Eisentraut <peter@eisentraut.org> wrote:
>> > To avoid creating an array on the stack, you could maybe write it with a
>> > pointer instead, like:
>> >
>> > const char * const query = "...";
>> >
>> > I haven't tested whether that results in different or better compiled
>> > code.  The original code is probably good enough.
>>
>> I expect it's been done the way it has to make the overflow detection
>> code work. The problem with having a pointer to a string constant is
>> that sizeof() will return the size of the pointer and not the space
>> needed to store the string.
>>
>> We can get rid of the variable and make the overflow work by checking
>> the return length of snprintf. I think that's all C99 spec now...
>>
>> len = snprintf(qbuf, "set client_encoding to '%s'", encoding);
>> /* check query buffer overflow */
>> if (len >= sizeof(qbuf))
>>     return -1;
>>
>
> Agree, this is a better coding style. Please see if the following code makes
> sense to you.
>
> diff --git a/src/interfaces/libpq/fe-connect.c
> b/src/interfaces/libpq/fe-connect.c
> index 0258d9ace3c..247d079faa6 100644
> --- a/src/interfaces/libpq/fe-connect.c
> +++ b/src/interfaces/libpq/fe-connect.c
> @@ -7717,9 +7717,9 @@ int
>  PQsetClientEncoding(PGconn *conn, const char *encoding)
>  {
>         char            qbuf[128];
> -       static const char query[] = "set client_encoding to '%s'";
>         PGresult   *res;
>         int                     status;
> +       int                     len;
>
>         if (!conn || conn->status != CONNECTION_OK)
>                 return -1;
> @@ -7731,12 +7731,11 @@ PQsetClientEncoding(PGconn *conn, const char *encoding)
>         if (strcmp(encoding, "auto") == 0)
>                 encoding =
> pg_encoding_to_char(pg_get_encoding_from_locale(NULL, true));
>
> -       /* check query buffer overflow */
> -       if (sizeof(qbuf) < (sizeof(query) + strlen(encoding)))
> +       len = snprintf(qbuf, sizeof(qbuf), "set client_encoding to
> '%s'", encoding);
> +       if (len >= sizeof(qbuf))
>                 return -1;
>
>         /* ok, now send a query */
> -       sprintf(qbuf, query, encoding);
>         res = PQexec(conn, qbuf);
>
>         if (res == NULL)
>

Thank you for all the explanations! The above code looks good to me, except
for a minor issue; since snprintf may return a negative value, should we
check for this?

--
Regrads,
Japin Li



Re: Remove unnecessary static type qualifiers

From
Junwang Zhao
Date:
On Wed, Apr 9, 2025 at 12:25 PM Japin Li <japinli@hotmail.com> wrote:
>
> On Wed, 09 Apr 2025 at 10:34, Junwang Zhao <zhjwpku@gmail.com> wrote:
> > On Wed, Apr 9, 2025 at 5:22 AM David Rowley <dgrowleyml@gmail.com> wrote:
> >>
> >> On Wed, 9 Apr 2025 at 03:46, Peter Eisentraut <peter@eisentraut.org> wrote:
> >> > To avoid creating an array on the stack, you could maybe write it with a
> >> > pointer instead, like:
> >> >
> >> > const char * const query = "...";
> >> >
> >> > I haven't tested whether that results in different or better compiled
> >> > code.  The original code is probably good enough.
> >>
> >> I expect it's been done the way it has to make the overflow detection
> >> code work. The problem with having a pointer to a string constant is
> >> that sizeof() will return the size of the pointer and not the space
> >> needed to store the string.
> >>
> >> We can get rid of the variable and make the overflow work by checking
> >> the return length of snprintf. I think that's all C99 spec now...
> >>
> >> len = snprintf(qbuf, "set client_encoding to '%s'", encoding);
> >> /* check query buffer overflow */
> >> if (len >= sizeof(qbuf))
> >>     return -1;
> >>
> >
> > Agree, this is a better coding style. Please see if the following code makes
> > sense to you.
> >
> > diff --git a/src/interfaces/libpq/fe-connect.c
> > b/src/interfaces/libpq/fe-connect.c
> > index 0258d9ace3c..247d079faa6 100644
> > --- a/src/interfaces/libpq/fe-connect.c
> > +++ b/src/interfaces/libpq/fe-connect.c
> > @@ -7717,9 +7717,9 @@ int
> >  PQsetClientEncoding(PGconn *conn, const char *encoding)
> >  {
> >         char            qbuf[128];
> > -       static const char query[] = "set client_encoding to '%s'";
> >         PGresult   *res;
> >         int                     status;
> > +       int                     len;
> >
> >         if (!conn || conn->status != CONNECTION_OK)
> >                 return -1;
> > @@ -7731,12 +7731,11 @@ PQsetClientEncoding(PGconn *conn, const char *encoding)
> >         if (strcmp(encoding, "auto") == 0)
> >                 encoding =
> > pg_encoding_to_char(pg_get_encoding_from_locale(NULL, true));
> >
> > -       /* check query buffer overflow */
> > -       if (sizeof(qbuf) < (sizeof(query) + strlen(encoding)))
> > +       len = snprintf(qbuf, sizeof(qbuf), "set client_encoding to
> > '%s'", encoding);
> > +       if (len >= sizeof(qbuf))
> >                 return -1;
> >
> >         /* ok, now send a query */
> > -       sprintf(qbuf, query, encoding);
> >         res = PQexec(conn, qbuf);
> >
> >         if (res == NULL)
> >
>
> Thank you for all the explanations! The above code looks good to me, except
> for a minor issue; since snprintf may return a negative value, should we
> check for this?

Maybe, I checked the *dopr* implementation a little bit, it seems
wouldn't return
-1 for fmt %s, %c, %d, %u etc. there are some places don't check the -1, like
[1], [2], [3], but for consistency I think we should, I'm not sure if
it worth to
change other places too.

[1] https://github.com/postgres/postgres/blob/master/src/backend/postmaster/launch_backend.c#L469
[2] https://github.com/postgres/postgres/blob/master/src/bin/pg_upgrade/pg_upgrade.c#L262
[3] https://github.com/postgres/postgres/blob/master/src/bin/pg_rewind/pg_rewind.c#L983

>
> --
> Regrads,
> Japin Li



--
Regards
Junwang Zhao