Bug 10138 - warn for uninitialized arrays passed as const* arguments
Summary: warn for uninitialized arrays passed as const* arguments
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 3.2
: P3 enhancement
Target Milestone: 11.0
Assignee: Martin Sebor
URL:
Keywords: diagnostic, patch
: 33086 69925 70987 (view as bug list)
Depends on: 27120 33086
Blocks: Wuninitialized 70987
  Show dependency treegraph
 
Reported: 2003-03-18 17:46 UTC by Hallvard B Furuseth
Modified: 2022-11-18 20:23 UTC (History)
6 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2020-05-15 00:00:00


Attachments
reduced testcase with one extra case (93 bytes, text/plain)
2003-05-24 14:37 UTC, Andrew Pinski
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Hallvard B Furuseth 2003-03-18 17:46:00 UTC
	A pointer to const parameter is almost always an input parameter
	to a function, so -Wuninitialized could warn if it has not been
	initialized.  (The function could cast away const on the parameter,
	but I've never seen the parameter being modified afterwards.)

Release:
3.2

Environment:
System: SunOS bombur.uio.no 5.8 Generic_108528-13 sun4u sparc SUNW,Ultra-5_10
Architecture: sun4

	
host: sparc-sun-solaris2.8
build: sparc-sun-solaris2.8
target: sparc-sun-solaris2.8
configured with: ../gcc-3.2/configure --prefix=/usit/bombur/hbf --enable-threads --enable-version-specific-runtime-libs --enable-languages=c

How-To-Repeat:
	gcc -Wuninitialized -O -S a.c

	int atoi(const char *);
	int foo()
	{
	    char buf[10];
	    return atoi(buf);
	}
Comment 1 Andrew Pinski 2003-05-24 14:37:04 UTC
Created attachment 4065 [details]
reduced testcase with one extra case
Comment 2 Andrew Pinski 2003-05-24 14:40:31 UTC
confirmed on mainline (20030524). Change title to reflect real bug.
Added another case to the testcases.
gcc should warn about buf in foo and a in g when -Wuninitialized is on.
Comment 3 Hallvard B Furuseth 2003-05-26 16:38:24 UTC
Subject: Re: [Bug other/10138] -Wuninitialized could catch uninitialized arrays

pinskia@physics.uc.edu writes:

> Change title to reflect real bug.

Oops, I have reported several suggestions which should be split up:

1) It could report use of uninitialized arrays as you say,

2) it could report pointers to uninitialized variables passed
   as const* arguments - as I said, that's almost always an error:

   void use(const int *);

   void foo(void)
   {
       int i;
       use(&i);
   }

3) Finally it could report the combination, as in my original example.

Comment 4 Andrew Pinski 2003-05-26 16:48:31 UTC
The second suggestion is already a different bug, and that is why I just changed it to this 
one(see bug 179).
Comment 5 Hallvard B Furuseth 2003-05-26 19:05:58 UTC
Subject: Re: [Bug other/10138] -Wuninitialized could catch uninitialized arrays

pinskia@physics.uc.edu writes:

> The second suggestion is already a different bug, and that is why I
> just changed it to this one(see bug 179).

No, bug 179 is a another bug, where - use(&i) would actually prevent
a preceding -Wuninitialized warning.  What I'd like is for use(&i)
itself to give a warning.

Comment 6 Andrew Pinski 2004-06-08 19:39:46 UTC
*** Bug 15880 has been marked as a duplicate of this bug. ***
Comment 7 Andrew Pinski 2004-09-07 16:57:38 UTC
Actually in both cases in this report we don't know if it is really used as an input parameter at all so this 
is invalid (even though there is a cast but still).
Comment 8 Wolfgang Bangerth 2004-09-07 22:41:22 UTC
I disagree -- the question whether an argument is actually used or not is secondary, 
the fact that we pass an uninitialized variable to which only read access is possible 
is definitely worth a warning. 
 
W. 
Comment 9 Manuel López-Ibáñez 2007-08-16 10:57:16 UTC
Let's simplify this report. This one is now about 

int atoi(const char *);
int foo()
{
    char buf[10];
    return atoi(buf);
}

As comment #3 mentions, this is a combination of 

1) Report use of uninitialized array elements (PR27120).
2) Report pointers to uninitialized variables passed as const* arguments (PR33086).

I guess that if we achieve both things, we will have a chance to achieve this one. In other words, both PRs are blocking this one.

Comment 10 Manuel López-Ibáñez 2007-08-20 14:49:08 UTC
I now think that Andrew is right and that PR33086 and this one are INVALID. 'const' does not mean read-only in C++ at all, and much less in C. atoi(const char *) could always initialize buf[]. However, perhaps it can apply to functions marked as "pure"...
Comment 11 Wolfgang Bangerth 2007-08-20 14:56:23 UTC
(In reply to comment #10)
> I now think that Andrew is right and that PR33086 and this one are INVALID.
> 'const' does not mean read-only in C++ at all, and much less in C. atoi(const
> char *) could always initialize buf[].

Uh, no, it can't. If it did (by casting away the 'const' from its argument
and then writing into the array), this would lead to a segfault:
-------------
const char a[3] = "10";
int main () {
  return atoi (a);
}
-------------
The reason being that compilers will typically place 'a' into a read-only
memory section.

Passing an uninitialized object as a const reference or pointer is a bad
idea in C++ and should get a warning as a rule. I can't see reasons that would
warrant exceptions from this rule.

W.
Comment 12 Manuel López-Ibáñez 2007-08-20 15:03:44 UTC
(In reply to comment #11)
> (In reply to comment #10)
> > I now think that Andrew is right and that PR33086 and this one are INVALID.
> > 'const' does not mean read-only in C++ at all, and much less in C. atoi(const
> > char *) could always initialize buf[].
> 
> Uh, no, it can't. If it did (by casting away the 'const' from its argument
> and then writing into the array), this would lead to a segfault:
> -------------
> const char a[3] = "10";
> int main () {
>   return atoi (a);
> }
> -------------

This testcase has nothing to do with uninitialized variables. If the variable is 'const' already, then there will never be a warning. Will it produce segmentation fault for a local automatic uninitialized pointer?
Comment 13 Manuel López-Ibáñez 2007-08-20 15:08:35 UTC
(In reply to comment #12)
> 
> This testcase has nothing to do with uninitialized variables. If the variable
> is 'const' already, then there will never be a warning. Will it produce
> segmentation fault for a local automatic uninitialized pointer?
> 

Of course, I mean pointer to (or array of, in this case) uninitialized data, not that the pointer itself is uninitialized. Sorry for the confusion.
Comment 14 Wolfgang Bangerth 2007-08-20 15:54:16 UTC
(In reply to comment #12)

> This testcase has nothing to do with uninitialized variables.

No, of course. I only meant to reply to your assertion that there could be
cases where a function initializes an object that is passed as a const
pointer. That may work in C, but not in C++. I agree that my example may
have been confusing, so take this slight variant of it ('a' is here non-const
and uninitialized):
-------------------
char a[3];
int main () {
  return atoi (a);
}
-------------------
It is my understanding that C++ allows 'a' to be put into read-only memory
because the only access is read-only. What that means is that functions like
atoi that take constant arguments have no legitimate way to initialize the
objects they get, and every uninitialized object passed to them is necessarily
a source of bugs.

This is meant to only counter your point that:
> 'const' does not mean read-only in C++ at all, and much less in C. atoi(const
> char *) could always initialize buf[].
This simply isn't true. In C++, atoi can't do that.

W.

Comment 15 Manuel López-Ibáñez 2007-08-20 16:15:26 UTC
(In reply to comment #14)
> This is meant to only counter your point that:
> > 'const' does not mean read-only in C++ at all, and much less in C. atoi(const
> > char *) could always initialize buf[].
> This simply isn't true. In C++, atoi can't do that.
> 

Please, take a look at the example given by Andrew http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33086#c3. I can compile and run a similar example:

#include <cstdio>
void use(const int *a)
{
  int * b = (int *)a;
  b[0] = 5;
}
int main(void)
{
  int i=0;
  use(&i);
  printf("%d\n", i);
  return 0;
}

Of course, the output is '5' and not '0'. So yes, atoi() seems perfectly able to  initialize buf. (or perhaps, I am still confused).
Comment 16 Wolfgang Bangerth 2007-08-20 16:21:50 UTC
(In reply to comment #15)

> Of course, the output is '5' and not '0'. So yes, atoi() seems perfectly able
> to  initialize buf. (or perhaps, I am still confused).

I think you are. This program here segfaults:
---------------------
#include <cstdio>

const int i=0;

void use(const int *a)
{
  int * b = (int *)a;
  b[0] = 5;
}

int main(void)
{
  use(&i);
  printf("%d\n", i);
  return 0;
}
----------------------------
Since use() (like atoi) can't know whether its argument is a local automatic
or a global variable, there is no way for it to reliably initialize its
argument. Casting away constness invokes undefined behavior if the static
type of the object is const.

W.

Comment 17 Manuel López-Ibáñez 2007-08-20 16:44:23 UTC
(In reply to comment #16)
> (In reply to comment #15)
> 
> > Of course, the output is '5' and not '0'. So yes, atoi() seems perfectly able
> > to  initialize buf. (or perhaps, I am still confused).
> 
> Since use() (like atoi) can't know whether its argument is a local automatic
> or a global variable, there is no way for it to reliably initialize its
> argument. Casting away constness invokes undefined behavior if the static
> type of the object is const.

But it seems that the current policy of GCC is to not assume that such functions actually take this into account, since when optimizing constants are not propagated beyond a call to such function. This is either the intended behaviour or a missed-optimisation. It would be nice if it would be a missed-optimisation. Fixing that will probably fix PR33086 and help to fix this one. Otherwise, if this is the intended behaviour, then both PRs are invalid as Andrew said.
Comment 18 Manuel López-Ibáñez 2007-08-20 16:46:53 UTC
When I say "constant are not propagated" I mean "the constant value of a variable" such as:

  int i=0;
  use(&i);
  foo(i);

Here, GCC does not propagate the value of i to do foo(0). Remove the call to use and then it will.
Comment 19 Wolfgang Bangerth 2007-08-20 16:58:46 UTC
(In reply to comment #18)
> When I say "constant are not propagated" I mean "the constant value of a
> variable" such as:
> 
>   int i=0;
>   use(&i);
>   foo(i);
> 
> Here, GCC does not propagate the value of i to do foo(0). Remove the call to
> use and then it will.

What if you had "const int i=0"? As I said before, use() may do a const-cast
to get rid of the constness of its argument, but the result is only well-defined
if the object pointed to is actually non-const. That is the case here, so use()
may do exactly this and clobber 'i'. On the other hand, if 'i' was const, then
the result of any const-cast use() may do on its argument are undefined, and
it would seem legitimate to propagate the initial value of 'i' into the call
to foo().

W.
I think that in 

Comment 20 Manuel López-Ibáñez 2007-08-20 17:12:01 UTC
(In reply to comment #19)
> 
> What if you had "const int i=0"? As I said before, use() may do a const-cast
> to get rid of the constness of its argument, but the result is only
> well-defined
> if the object pointed to is actually non-const. That is the case here, so use()
> may do exactly this and clobber 'i'. On the other hand, if 'i' was const, then
> the result of any const-cast use() may do on its argument are undefined, and
> it would seem legitimate to propagate the initial value of 'i' into the call
> to foo().
> 

Wolfgang, I understand perfectly what you explain. Yet, from the point of view of Wuninitialized, only local non-const objects are interesting. And it seems that for those, GCC does not assume that the function is not going to modify the object. Thus, it doesn't make much sense for Wuninitialized to assume it. And, from a technical point of view, it would be difficult to maintain such dichotomy, since Wuninitialized relies on the SSA representation and the work of the optimisation passes.
Comment 21 gdr@cs.tamu.edu 2007-08-20 18:50:49 UTC
Subject: Re:  warn for uninitialized arrays passed as const* arguments

"manu at gcc dot gnu dot org" <gcc-bugzilla@gcc.gnu.org> writes:

| When I say "constant are not propagated" I mean "the constant value of a
| variable" such as:
| 
|   int i=0;
|   use(&i);
|   foo(i);
| 
| Here, GCC does not propagate the value of i to do foo(0). Remove the call to
| use and then it will.

Which is all it can do, assuming the body is not "available".

-- Gaby
Comment 22 Hallvard B Furuseth 2007-08-20 22:45:50 UTC
Subject: Re:  warn for uninitialized arrays passed as const* arguments

manu at gcc dot gnu dot org writes:
> But it seems that the current policy of GCC is to not assume that such
> functions actually take this into account, since when optimizing
> constants are not propagated beyond a call to such function. This is
> either the intended behaviour or a missed-optimisation.
> It would be nice if it would be a missed-optimisation.

A "const" in a function parameter in C is not a promise to the compiler;
it would break the C standard to optimize on it.

> Otherwise, if this
> is the intended behaviour, then both PRs are invalid as Andrew said.

They are requests for warning messages, not error messages, because they
are _likely_ to be programmer errors.  That's what warnings are for.
-Wuninitialized is giving false positives anyway, on code which the
compiler cannot tell is correct but the programmer can.

Comment 23 Matt Hargett 2009-12-31 01:44:25 UTC
I just ran into a bug that this feature would have found for me at compile-time. Instead, it required exercising the code under valgrind, which took quite some time. If voting were enabled, I would vote for this bug.
Comment 24 Manuel López-Ibáñez 2016-02-23 22:01:52 UTC
*** Bug 69925 has been marked as a duplicate of this bug. ***
Comment 25 Martin Sebor 2016-09-06 23:43:20 UTC
*** Bug 70987 has been marked as a duplicate of this bug. ***
Comment 26 Martin Sebor 2016-09-06 23:45:49 UTC
It seems that it should be possible to enhance the warn_uninitialized_vars function in tree-ssa-uninit.c to detect this case by iterating over a callee's arguments and warn on uninitialized variables whose address is passed to it via a const pointer parameter.
Comment 27 Martin Sebor 2017-03-29 19:01:15 UTC
*** Bug 33086 has been marked as a duplicate of this bug. ***
Comment 28 Martin Sebor 2019-09-29 21:44:55 UTC
The patch I developed for pr80806 introduces the read_only and read_write attributes that both enable this warning and also make optimizations possible:

$ cat pr10138.c && gcc -O -S -Wall pr10138.c
__attribute__ ((read_only))	int atoi (const char *);

int foo()
{
  char buf[10];
  return atoi (buf);
}
pr10138.c: In function ‘foo’:
pr10138.c:6:10: warning: ‘buf’ is used uninitialized in this function [-Wuninitialized]
    6 |   return atoi (buf);
      |          ^~~~~~~~~~

For read-only functions like atoi it would be easy to issue the warning even in the absence of the attribute.  There's some potential for false positives, such as in C++ and mutable members, but I expect those would be rare and more than offset by the bugs the warning would find.  Let me see about it.
Comment 30 GCC Commits 2020-06-04 22:10:31 UTC
The master branch has been updated by Martin Sebor <msebor@gcc.gnu.org>:

https://gcc.gnu.org/g:b825a22890740f341eae566af27e18e528cd29a7

commit r11-959-gb825a22890740f341eae566af27e18e528cd29a7
Author: Martin Sebor <msebor@redhat.com>
Date:   Thu Jun 4 16:06:10 2020 -0600

    Implement a solution for PR middle-end/10138 and PR middle-end/95136.
    
    PR middle-end/10138 - warn for uninitialized arrays passed as const arguments
    PR middle-end/95136 - missing -Wuninitialized on an array access with a variable offset
    
    gcc/c-family/ChangeLog:
    
            PR middle-end/10138
            PR middle-end/95136
            * c-attribs.c (append_access_attrs): Handle attr_access::none.
            (handle_access_attribute): Same.
    
    gcc/ChangeLog:
    
            PR middle-end/10138
            PR middle-end/95136
            * attribs.c (init_attr_rdwr_indices): Move function here.
            * attribs.h (rdwr_access_hash, rdwr_map): Define.
            (attr_access): Add 'none'.
            (init_attr_rdwr_indices): Declared function.
            * builtins.c (warn_for_access)): New function.
            (check_access): Call it.
            * builtins.h (checK-access): Add an optional argument.
            * calls.c (rdwr_access_hash, rdwr_map): Move to attribs.h.
            (init_attr_rdwr_indices): Declare extern.
            (append_attrname): Handle attr_access::none.
            (maybe_warn_rdwr_sizes): Same.
            (initialize_argument_information): Update comments.
            * doc/extend.texi (attribute access): Document 'none'.
            * tree-ssa-uninit.c (struct wlimits): New.
            (maybe_warn_operand): New function.
            (maybe_warn_pass_by_reference): Same.
            (warn_uninitialized_vars): Refactor code into maybe_warn_operand.
            Also call for function calls.
            (pass_late_warn_uninitialized::execute): Adjust comments.
            (execute_early_warn_uninitialized): Same.
    
    gcc/testsuite/ChangeLog:
    
            PR middle-end/10138
            PR middle-end/95136
            * c-c++-common/Wsizeof-pointer-memaccess1.c: Prune out valid
            Wuninitialized.
            * c-c++-common/uninit-pr51010.c: Adjust expected warning format.
            * c-c++-common/goacc/uninit-dim-clause.c: Same.
            * c-c++-common/goacc/uninit-firstprivate-clause.c: Same.
            * c-c++-common/goacc/uninit-if-clause.c: Same.
            * c-c++-common/gomp/pr70550-1.c: Same.
            * c-c++-common/gomp/pr70550-2.c: Adjust.
            * g++.dg/20090107-1.C: Same.
            * g++.dg/20090121-1.C: Same.
            * g++.dg/ext/attr-access.C: Avoid -Wuninitialized.
            * gcc.dg/tree-ssa/forwprop-6.c: Prune out -Wuninitialized.
            * gcc.dg/Warray-bounds-52.c: Prune out valid -Wuninitialized.
            * gcc.dg/Warray-bounds-53.c: Same.
            * gcc.dg/Warray-bounds-54.c: Same.
            * gcc.dg/Wstringop-overflow-33.c: New test.
            * gcc.dg/attr-access-none.c: New test.
            * gcc.dg/attr-access-read-only.c: Adjust.
            * gcc.dg/attr-access-read-write.c: Same.
            * gcc.dg/attr-access-write-only.c: Same.
            * gcc.dg/pr71581.c: Adjust text of expected warning.
            * gcc.dg/uninit-15.c: Same.
            * gcc.dg/uninit-32.c: New test.
            * gcc.dg/uninit-33.c: New test.
            * gcc.dg/uninit-34.c: New test.
            * gcc.dg/uninit-36.c: New test.
            * gcc.dg/uninit-B-O0.c: Adjust text of expected warning.
            * gcc.dg/uninit-I-O0.c: Same.
            * gcc.dg/uninit-pr19430-O0.c: Same.
            * gcc.dg/uninit-pr19430.c: Same.
            * gcc.dg/uninit-pr95136.c: New test.
            * gfortran.dg/assignment_4.f90: Expect -Wuninitialized.
            * gfortran.dg/goacc/uninit-dim-clause.f95: Adjust text of expected
            warning.
            * gfortran.dg/goacc/uninit-firstprivate-clause.f95
            * gfortran.dg/goacc/uninit-if-clause.f95
            * gfortran.dg/pr66545_2.f90
Comment 31 Martin Sebor 2020-06-04 22:12:46 UTC
Done for GCC 11.