Thread: arrayfuncs: fix read of uninitialized mem

arrayfuncs: fix read of uninitialized mem

From
Neil Conway
Date:
This patch fixes a read of uninitialized memory in array_out(). The code
was previously doing a strlen() on a stack-allocated char array that,
under some code paths, had never been assigned to. The problem doesn't
appear in REL7_4_STABLE, so there's no need for a backport.

I fixed it by initializing dims_str[0] to '\0' circa line 1018 in
current sources. While doing so I couldn't resist the temptation to fix
a few of arrayfunc.c's crimes against good programming practise, so the
attached patch includes some additional cosmetic improvements. If people
prefer I can just apply the bugfix to HEAD, and save the cleanup till we
branch for 8.1. Comments?

Barring any objections, I'll apply the patch within 24 hours.

-Neil


Attachment

Re: arrayfuncs: fix read of uninitialized mem

From
Tom Lane
Date:
Neil Conway <neilc@samurai.com> writes:
> I fixed it by initializing dims_str[0] to '\0' circa line 1018 in
> current sources. While doing so I couldn't resist the temptation to fix
> a few of arrayfunc.c's crimes against good programming practise, so the
> attached patch includes some additional cosmetic improvements.

I dislike what you did at lines 983-1012 (replace a local variable by
possibly-many stores into an array).  Also, as long as we're fixing
unreadable code, how about (line 1019)

    for (i = j = 0, k = 1; i < ndim; k *= dims[i++], j += k);

becomes

     for (i = j = 0, k = 1; i < ndim; i++)
        k *= dims[i], j += k;

or some such.  The empty loop body is a mistake waiting to happen.

Looks fine to me otherwise.

            regards, tom lane

Re: arrayfuncs: fix read of uninitialized mem

From
Joe Conway
Date:
Neil Conway wrote:
>
> Barring any objections, I'll apply the patch within 24 hours.
>

> ***************
> *** 965,978 ****
>        * (including any overhead such as escaping backslashes), and detect
>        * whether each item needs double quotes.
>        */
> !     values = (char **) palloc(nitems * sizeof(char *));
> !     needquotes = (bool *) palloc(nitems * sizeof(bool));

> --- 965,978 ----
>        * (including any overhead such as escaping backslashes), and detect
>        * whether each item needs double quotes.
>        */
> !     values = (char **) palloc(nitems * sizeof(*values));
> !     needquotes = (bool *) palloc(nitems * sizeof(*needquotes));

Personally I prefer the original style here. And I agree with Tom's
nearby comments. But otherwise looks good to me.

Joe

Re: arrayfuncs: fix read of uninitialized mem

From
Neil Conway
Date:
On Thu, 2004-09-16 at 03:32, Joe Conway wrote:
> Personally I prefer the original style here.

Personally I like the style I used, because it makes one class of
mistake more difficult -- getting the sizeof() wrong. Suppose the type
of the variable you're allocating changes -- if you use

ptr = malloc(sizeof(*ptr));

then the code is still right, but with

ptr = malloc(sizeof(some_type));

you need to remember to update the sizeof(); worse, the compiler won't
warn you about this.

-Neil



Re: arrayfuncs: fix read of uninitialized mem

From
Neil Conway
Date:
On Thu, 2004-09-16 at 00:18, Tom Lane wrote:
> I dislike what you did at lines 983-1012 (replace a local variable by
> possibly-many stores into an array).

Ok, I'll revert it.

> Also, as long as we're fixing unreadable code, how about (line 1019)
> [...]

Sounds good to me.

I'll update the patch and apply it later today.

-Neil



Re: arrayfuncs: fix read of uninitialized mem

From
Tom Lane
Date:
Neil Conway <neilc@samurai.com> writes:
> Personally I like the style I used, because it makes one class of
> mistake more difficult -- getting the sizeof() wrong. Suppose the type
> of the variable you're allocating changes -- if you use

> ptr = malloc(sizeof(*ptr));

> then the code is still right, but with

> ptr = malloc(sizeof(some_type));

> you need to remember to update the sizeof(); worse, the compiler won't
> warn you about this.

IMHO both of the above are poor style, precisely because the compiler
can't warn you about it if the sizeof calculation doesn't match the
pointer variable's type.  I prefer

    ptr = (foo *) malloc(sizeof(foo));
or
    ptr = (foo *) malloc(n * sizeof(foo));
since here you will get a warning if ptr is typed as something other
than foo *.  Now admittedly you are still relying on two bits of code to
match each other, namely the two occurrences of "foo" in this command
--- but they are at least adjacent in the source code whereas the
declaration of ptr might be some distance away.

No doubt you'll say that "ptr" is duplicated close together in your
preferred version, but I don't think it scales nicely to
slightly-more-complex cases.  Consider for instance

    ptrs[i++] = malloc(sizeof(*ptrs[i++]));

This is going to confuse people no matter what.  Either you don't write
the exact same thing on both sides, or you are relying on the reader to
realize the funny semantics of sizeof() and know that i isn't really
bumped twice by the above (not to mention relying on the compiler to
implement that correctly...).

I guess at bottom it's the funny semantics of sizeof-applied-to-an-
lvalue-expression that I don't like.  I think sizeof(type decl) is much
more obviously a compile-time constant.  Possibly this is just a
hangover from programming in other languages that had the one but not
the other, but it's what I find understandable.

            regards, tom lane

Re: arrayfuncs: fix read of uninitialized mem

From
Neil Conway
Date:
On Thu, 2004-09-16 at 12:19, Tom Lane wrote:
>   I prefer
>
>     ptr = (foo *) malloc(sizeof(foo));
> or
>     ptr = (foo *) malloc(n * sizeof(foo));
> since here you will get a warning if ptr is typed as something other
> than foo *.

I was leaving out the cast above because IMHO that's somewhat
orthogonal. If you like the cast (personally I'm in two minds about it),
then I'd argue for:

ptr = (foo *) malloc(sizeof(*ptr));

IMHO this is preferable because there is nothing that you need to change
when the type of "foo" changes that the compiler won't warn you about.
In your formulation you need to manually keep the two instances of "foo"
in sync: admittedly, not a huge deal because you need to change the
"foo" in the cast anyway, but IMHO it's worth enough to prefer the
sizeof(lvalue) style.

> No doubt you'll say that "ptr" is duplicated close together in your
> preferred version, but I don't think it scales nicely to
> slightly-more-complex cases.  Consider for instance
>
>     ptrs[i++] = malloc(sizeof(*ptrs[i++]));
>
> This is going to confuse people no matter what.

I try to avoid writing "clever" code like that in any case -- using
sizeof(type) would definitely make the above clearer, but IMHO that kind
of complex lvalue is best avoided in the first place.

> I guess at bottom it's the funny semantics of sizeof-applied-to-an-
> lvalue-expression that I don't like.  I think sizeof(type decl) is much
> more obviously a compile-time constant.

Granted, sizeof(lvalue) is a little unusual, but personally I think it's
just one of those C features that might be weird coming from other
languages, but is idiomatic C.

Anyway, I'm not religious about this -- since other people seem to
prefer the former style I'll revert the change.

-Neil



Re: arrayfuncs: fix read of uninitialized mem

From
Neil Conway
Date:
On Thu, 2004-09-16 at 09:18, Neil Conway wrote:
> I'll update the patch and apply it later today.

Applied to HEAD. The version of the patch that I applied is attached.

-Neil


Attachment