Обсуждение: [HACKERS] Constifying numeric.c's local vars

Поиск
Список
Период
Сортировка

[HACKERS] Constifying numeric.c's local vars

От
Andres Freund
Дата:
Hi,

For JIT inlining currently functions can't be inlined if they reference
non-constant static variables. That's because there's no way, at least
none I know of, to link to the correct variable, instead of duplicating,
the linker explicitly renames symbols after all (that's the whole point
of static vars).  There's a bunch of weird errors if you ignore that ;)

One large user of unnecessary non-constant static variables is
numeric.c.  More out of curiosity - numeric is slow enough in itself to
make inlining not a huge win - I converted it to use consts.

before:
andres@alap4:~/build/postgres/dev-assert/vpath$ size --format=SysV src/backend/utils/adt/numeric.o |grep -v debug|grep
-v'^.group'
 
src/backend/utils/adt/numeric.o  :
section             size   addr
.text              68099      0
.data                 64      0
.bss                   2      0
.rodata             4256      0
.data.rel.local      224      0
.comment              29      0
.note.GNU-stack        0      0
.eh_frame           5976      0
Total             395590


after:

$ size --format=SysV src/backend/utils/adt/numeric.o |grep -v debug|grep -v '^.group'
src/backend/utils/adt/numeric.o  :
section                size   addr
.text                 68108      0
.data                     0      0
.bss                      0      0
.rodata                4288      0
.data.rel.ro.local      224      0
.comment                 29      0
.note.GNU-stack           0      0
.eh_frame              5976      0
Total                395586

Nicely visible that the data is moved from a mutable segment to a
readonly one.

It's a bit ugly that some consts have to be casted away in the constant
definitions, but aside from just inlining the values, I don't quite see
a better solution?

Leaving JIT aside, I think stuff like this is worthwhile on its own...

Greetings,

Andres Freund

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Вложения

Re: [HACKERS] Constifying numeric.c's local vars

От
Tom Lane
Дата:
Andres Freund <andres@anarazel.de> writes:
> One large user of unnecessary non-constant static variables is
> numeric.c.  More out of curiosity - numeric is slow enough in itself to
> make inlining not a huge win - I converted it to use consts.

LGTM.

> It's a bit ugly that some consts have to be casted away in the constant
> definitions, but aside from just inlining the values, I don't quite see
> a better solution?

No, I don't either.  I'm not sure that writing the constant inline would
produce the desired results - the compiler might well decide that it had
to be in read-write storage.
        regards, tom lane


-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Re: [HACKERS] Constifying numeric.c's local vars

От
Mark Dilger
Дата:
> On Sep 11, 2017, at 5:10 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>
> Andres Freund <andres@anarazel.de> writes:
>> One large user of unnecessary non-constant static variables is
>> numeric.c.  More out of curiosity - numeric is slow enough in itself to
>> make inlining not a huge win - I converted it to use consts.
>
> LGTM.
>
>> It's a bit ugly that some consts have to be casted away in the constant
>> definitions, but aside from just inlining the values, I don't quite see
>> a better solution?
>
> No, I don't either.  I'm not sure that writing the constant inline would
> produce the desired results - the compiler might well decide that it had
> to be in read-write storage.
>
>             regards, tom lane

This patch got committed as c1898c3e1e235ae35b4759d233253eff221b976a
on Sun Sep 10 16:20:41 2017 -0700, but I've only just gotten around to
reviewing it.

I believe this is wrong and should be reverted, at least in part.

The NumericVar struct has the field 'digits' as non-const:

typedef struct NumericVar
{
    int         ndigits;        /* # of digits in digits[] - can be 0! */
    int         weight;         /* weight of first digit */
    int         sign;           /* NUMERIC_POS, NUMERIC_NEG, or NUMERIC_NAN */
    int         dscale;         /* display scale */
    NumericDigit *buf;          /* start of palloc'd space for digits[] */
    NumericDigit *digits;       /* base-NBASE digits */
} NumericVar;

The static const data which is getting put in read only memory sets that data
by casting away const as follows:

static const NumericDigit const_zero_data[1] = {0};
static const NumericVar const_zero =
{0, 0, NUMERIC_POS, 0, NULL, (NumericDigit *) const_zero_data};

This means that the const variable 'const_zero' contains a pointer that is
non-const, pointing at something that is static const, stored in read only
memory.  Yikes.

The function set_var_from_var(const NumericVar *value, NumericVar *dest)
uses memcpy to copy the contents of value into dest.  In cases where the value
is a static const variable (eg, const_zero), the memcpy is copying a pointer to
static const read only data into the dest and implicitly casting away const.
Since that static const data is stored in read only memory, this has undefined
semantics, and I believe could lead to a server crash, at least on some
architectures with some compilers.

The idea that set_var_from_var might be called on const_zero (or const_one,
etc.) is not hypothetical.  It is being done in numeric.c.

If this is safe, somebody needs to be a lot clearer about why that is so.  There
are no comments explaining it in the file, and the conversation in this thread
never got into any details about it either.

Mark Dilger





Re: [HACKERS] Constifying numeric.c's local vars

От
Andres Freund
Дата:

On February 21, 2018 8:49:51 AM PST, Mark Dilger <hornschnorter@gmail.com> wrote:
>
>The idea that set_var_from_var might be called on const_zero (or
>const_one,
>etc.) is not hypothetical.  It is being done in numeric.c.
>
>If this is safe, somebody needs to be a lot clearer about why that is
>so.  There
>are no comments explaining it in the file, and the conversation in this
>thread
>never got into any details about it either.

Just getting started for the day, no coffee yet. But, uh, what you're appear to be saying is that we have code
modifyingthe digits of the zero value? That's seems unlikely. 

Andres
--
Sent from my Android device with K-9 Mail. Please excuse my brevity.


Re: [HACKERS] Constifying numeric.c's local vars

От
Mark Dilger
Дата:
> This patch got committed as c1898c3e1e235ae35b4759d233253eff221b976a
> on Sun Sep 10 16:20:41 2017 -0700, but I've only just gotten around to
> reviewing it.
>
> I believe this is wrong and should be reverted, at least in part.
>
> The NumericVar struct has the field 'digits' as non-const:
>
> typedef struct NumericVar
> {
>    int         ndigits;        /* # of digits in digits[] - can be 0! */
>    int         weight;         /* weight of first digit */
>    int         sign;           /* NUMERIC_POS, NUMERIC_NEG, or NUMERIC_NAN */
>    int         dscale;         /* display scale */
>    NumericDigit *buf;          /* start of palloc'd space for digits[] */
>    NumericDigit *digits;       /* base-NBASE digits */
> } NumericVar;
>
> The static const data which is getting put in read only memory sets that data
> by casting away const as follows:
>
> static const NumericDigit const_zero_data[1] = {0};
> static const NumericVar const_zero =
> {0, 0, NUMERIC_POS, 0, NULL, (NumericDigit *) const_zero_data};
>
> This means that the const variable 'const_zero' contains a pointer that is
> non-const, pointing at something that is static const, stored in read only
> memory.  Yikes.

I still believe this is unsafe.

> The function set_var_from_var(const NumericVar *value, NumericVar *dest)
> uses memcpy to copy the contents of value into dest.  In cases where the value
> is a static const variable (eg, const_zero), the memcpy is copying a pointer to
> static const read only data into the dest and implicitly casting away const.
> Since that static const data is stored in read only memory, this has undefined
> semantics, and I believe could lead to a server crash, at least on some
> architectures with some compilers.

This is probably safe, though, since NumericDigit seems to just be a typedef
to int16.  I should have checked that definition before complaining about that
part.



Re: [HACKERS] Constifying numeric.c's local vars

От
Tom Lane
Дата:
Mark Dilger <hornschnorter@gmail.com> writes:
>> This means that the const variable 'const_zero' contains a pointer that is
>> non-const, pointing at something that is static const, stored in read only
>> memory.  Yikes.

> I still believe this is unsafe.

I'm with Andres: I don't see the problem.  It's true that we've casted
away a chance for the compiler to notice a problem, but that's not the
only defense against problems.  If we did try to modify const_zero,
what should happen now is that we get a SIGSEGV from trying to scribble
on read-only memory.  But that's actually a step forward from before.
Before, we'd have successfully modified the value of const_zero and
thereby silently bollixed subsequent computations using it.  Since,
in fact, the code should never try to modify const_zero, the SIGSEGV
should never happen.  So effectively we have a hardware-enforced Assert
that we don't modify it, and that seems good.

As far as compiler-detectable mistakes go, Andres' changes to declare
various function inputs as const seem like a pretty considerable
improvement too, even if they aren't offering 100% coverage.

            regards, tom lane