diff mbox

correct handling of non-constant width and precision (pr 78521)

Message ID yddmvgen359.fsf@CeBiTec.Uni-Bielefeld.DE
State New
Headers show

Commit Message

Rainer Orth Dec. 2, 2016, 8:31 a.m. UTC
Hi Martin,

> PR 78521 notes that the gimple-ssa-sprintf pass doesn't do the right

> thing (i.e., the -Wformat-length and -fprintf-return-value options

> behave incorrectly) when a conversion specification includes a width

> or precision with a non-constant value.  The code treats such cases

> as if they were not provided which is incorrect and results in

> the wrong bytes counts in warning messages and in the wrong ranges

> being generated for such calls (or in the case sprintf(0, 0, ...)

> for some such calls being eliminated).

>

> The attached patch corrects the handling of these cases, plus a couple

> of other edge cases in the same area: it adjusts the parser to accept

> precision in the form of just a period with no asterisk or decimal

> digits after it (this sets the precision to zero), and corrects the

> handling of zero precision and zero argument in integer directives

> to produce no bytes on output.

>

> Finally, the patch also tightens up the constraint on the upper bound

> of bounded functions like snprintf to be INT_MAX.  The functions cannot

> produce output in excess of INT_MAX + 1 bytes and some implementations

> (e.g., Solaris) fail with EINVAL when the bound is INT_MAX or more.

> This is the subject of PR 78520.


this patch broke Solaris bootstrap:

/vol/gcc/src/hg/trunk/local/gcc/gimple-ssa-sprintf.c: In function 'void {anonymous}::get_width_and_precision(const {anonymous}::conversion_spec&, long long int*, long long int*)':
/vol/gcc/src/hg/trunk/local/gcc/gimple-ssa-sprintf.c:777:45: error: call of overloaded 'abs(long long int)' is ambiguous
  width = abs (tree_to_shwi (spec.star_width));
                                             ^
/vol/gcc/src/hg/trunk/local/gcc/gimple-ssa-sprintf.c:777:45: note: candidates are:
In file included from /usr/include/stdlib.h:12:0,
                 from /vol/gcc/src/hg/trunk/local/gcc/system.h:258,
                 from /vol/gcc/src/hg/trunk/local/gcc/gimple-ssa-sprintf.c:49:
/usr/include/iso/stdlib_iso.h:205:16: note: long int std::abs(long int)
  inline long   abs(long _l) { return labs(_l); }
                ^
/usr/include/iso/stdlib_iso.h:160:12: note: int std::abs(int)
 extern int abs(int);
            ^

The following patch fixed this for me, but I've no idea if it's right.
It bootstrapped successfully on sparc-sun-solaris2.12,
i386-pc-solaris2.12, and x86_64-pc-linux-gnu.

	Rainer

-- 
-----------------------------------------------------------------------------
Rainer Orth, Center for Biotechnology, Bielefeld University


2016-12-02  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>

	* gimple-ssa-sprintf.c (get_width_and_precision): Use std::abs.

Comments

Martin Sebor Dec. 2, 2016, 3:52 p.m. UTC | #1
On 12/02/2016 01:31 AM, Rainer Orth wrote:
> Hi Martin,

>

>> PR 78521 notes that the gimple-ssa-sprintf pass doesn't do the right

>> thing (i.e., the -Wformat-length and -fprintf-return-value options

>> behave incorrectly) when a conversion specification includes a width

>> or precision with a non-constant value.  The code treats such cases

>> as if they were not provided which is incorrect and results in

>> the wrong bytes counts in warning messages and in the wrong ranges

>> being generated for such calls (or in the case sprintf(0, 0, ...)

>> for some such calls being eliminated).

>>

>> The attached patch corrects the handling of these cases, plus a couple

>> of other edge cases in the same area: it adjusts the parser to accept

>> precision in the form of just a period with no asterisk or decimal

>> digits after it (this sets the precision to zero), and corrects the

>> handling of zero precision and zero argument in integer directives

>> to produce no bytes on output.

>>

>> Finally, the patch also tightens up the constraint on the upper bound

>> of bounded functions like snprintf to be INT_MAX.  The functions cannot

>> produce output in excess of INT_MAX + 1 bytes and some implementations

>> (e.g., Solaris) fail with EINVAL when the bound is INT_MAX or more.

>> This is the subject of PR 78520.

>

> this patch broke Solaris bootstrap:

>

> /vol/gcc/src/hg/trunk/local/gcc/gimple-ssa-sprintf.c: In function 'void {anonymous}::get_width_and_precision(const {anonymous}::conversion_spec&, long long int*, long long int*)':

> /vol/gcc/src/hg/trunk/local/gcc/gimple-ssa-sprintf.c:777:45: error: call of overloaded 'abs(long long int)' is ambiguous

>   width = abs (tree_to_shwi (spec.star_width));

>                                              ^

> /vol/gcc/src/hg/trunk/local/gcc/gimple-ssa-sprintf.c:777:45: note: candidates are:

> In file included from /usr/include/stdlib.h:12:0,

>                  from /vol/gcc/src/hg/trunk/local/gcc/system.h:258,

>                  from /vol/gcc/src/hg/trunk/local/gcc/gimple-ssa-sprintf.c:49:

> /usr/include/iso/stdlib_iso.h:205:16: note: long int std::abs(long int)

>   inline long   abs(long _l) { return labs(_l); }

>                 ^

> /usr/include/iso/stdlib_iso.h:160:12: note: int std::abs(int)

>  extern int abs(int);

>             ^

>

> The following patch fixed this for me, but I've no idea if it's right.

> It bootstrapped successfully on sparc-sun-solaris2.12,

> i386-pc-solaris2.12, and x86_64-pc-linux-gnu.


Thanks for the heads up!  I just looked at that code yesterday while
analyzing bug 78608, wondering if it was safe.  Now I know it isn't.
I think it might be best to simply hand code the expression instead
of taking a chance on abs.  Let me take care of it today along with 78608.

Martin
Martin Sebor Dec. 5, 2016, 3:50 p.m. UTC | #2
On 12/02/2016 08:52 AM, Martin Sebor wrote:
> On 12/02/2016 01:31 AM, Rainer Orth wrote:

>> Hi Martin,

>>

>>> PR 78521 notes that the gimple-ssa-sprintf pass doesn't do the right

>>> thing (i.e., the -Wformat-length and -fprintf-return-value options

>>> behave incorrectly) when a conversion specification includes a width

>>> or precision with a non-constant value.  The code treats such cases

>>> as if they were not provided which is incorrect and results in

>>> the wrong bytes counts in warning messages and in the wrong ranges

>>> being generated for such calls (or in the case sprintf(0, 0, ...)

>>> for some such calls being eliminated).

>>>

>>> The attached patch corrects the handling of these cases, plus a couple

>>> of other edge cases in the same area: it adjusts the parser to accept

>>> precision in the form of just a period with no asterisk or decimal

>>> digits after it (this sets the precision to zero), and corrects the

>>> handling of zero precision and zero argument in integer directives

>>> to produce no bytes on output.

>>>

>>> Finally, the patch also tightens up the constraint on the upper bound

>>> of bounded functions like snprintf to be INT_MAX.  The functions cannot

>>> produce output in excess of INT_MAX + 1 bytes and some implementations

>>> (e.g., Solaris) fail with EINVAL when the bound is INT_MAX or more.

>>> This is the subject of PR 78520.

>>

>> this patch broke Solaris bootstrap:

>>

>> /vol/gcc/src/hg/trunk/local/gcc/gimple-ssa-sprintf.c: In function

>> 'void {anonymous}::get_width_and_precision(const

>> {anonymous}::conversion_spec&, long long int*, long long int*)':

>> /vol/gcc/src/hg/trunk/local/gcc/gimple-ssa-sprintf.c:777:45: error:

>> call of overloaded 'abs(long long int)' is ambiguous

>>   width = abs (tree_to_shwi (spec.star_width));

>>                                              ^

>> /vol/gcc/src/hg/trunk/local/gcc/gimple-ssa-sprintf.c:777:45: note:

>> candidates are:

>> In file included from /usr/include/stdlib.h:12:0,

>>                  from /vol/gcc/src/hg/trunk/local/gcc/system.h:258,

>>                  from

>> /vol/gcc/src/hg/trunk/local/gcc/gimple-ssa-sprintf.c:49:

>> /usr/include/iso/stdlib_iso.h:205:16: note: long int std::abs(long int)

>>   inline long   abs(long _l) { return labs(_l); }

>>                 ^

>> /usr/include/iso/stdlib_iso.h:160:12: note: int std::abs(int)

>>  extern int abs(int);

>>             ^

>>

>> The following patch fixed this for me, but I've no idea if it's right.

>> It bootstrapped successfully on sparc-sun-solaris2.12,

>> i386-pc-solaris2.12, and x86_64-pc-linux-gnu.

>

> Thanks for the heads up!  I just looked at that code yesterday while

> analyzing bug 78608, wondering if it was safe.  Now I know it isn't.

> I think it might be best to simply hand code the expression instead

> of taking a chance on abs.  Let me take care of it today along with 78608.


I posted a bigger patch to fix this and other related problems on
Friday (https://gcc.gnu.org/ml/gcc-patches/2016-12/msg00262.html).
In hindsight, I should have probably committed the fix for this
on its own.  Please let me know if this is blocking you and I'll
commit this fix by itself today so you don't have to wait for
the bigger patch to get reviewed and approved.

Martin
Jakub Jelinek Dec. 5, 2016, 3:53 p.m. UTC | #3
On Mon, Dec 05, 2016 at 08:50:08AM -0700, Martin Sebor wrote:
> I posted a bigger patch to fix this and other related problems on

> Friday (https://gcc.gnu.org/ml/gcc-patches/2016-12/msg00262.html).

> In hindsight, I should have probably committed the fix for this

> on its own.  Please let me know if this is blocking you and I'll

> commit this fix by itself today so you don't have to wait for

> the bigger patch to get reviewed and approved.


You could just change the abs use to absu_hwi or abs_hwi if you need
something quickly working (depending on whether HOST_WIDE_INT_MIN can
appear or not).

	Jakub
Jeff Law Dec. 5, 2016, 6:25 p.m. UTC | #4
On 12/05/2016 08:50 AM, Martin Sebor wrote:
> On 12/02/2016 08:52 AM, Martin Sebor wrote:

>> On 12/02/2016 01:31 AM, Rainer Orth wrote:

>>> Hi Martin,

>>>

>>>> PR 78521 notes that the gimple-ssa-sprintf pass doesn't do the right

>>>> thing (i.e., the -Wformat-length and -fprintf-return-value options

>>>> behave incorrectly) when a conversion specification includes a width

>>>> or precision with a non-constant value.  The code treats such cases

>>>> as if they were not provided which is incorrect and results in

>>>> the wrong bytes counts in warning messages and in the wrong ranges

>>>> being generated for such calls (or in the case sprintf(0, 0, ...)

>>>> for some such calls being eliminated).

>>>>

>>>> The attached patch corrects the handling of these cases, plus a couple

>>>> of other edge cases in the same area: it adjusts the parser to accept

>>>> precision in the form of just a period with no asterisk or decimal

>>>> digits after it (this sets the precision to zero), and corrects the

>>>> handling of zero precision and zero argument in integer directives

>>>> to produce no bytes on output.

>>>>

>>>> Finally, the patch also tightens up the constraint on the upper bound

>>>> of bounded functions like snprintf to be INT_MAX.  The functions cannot

>>>> produce output in excess of INT_MAX + 1 bytes and some implementations

>>>> (e.g., Solaris) fail with EINVAL when the bound is INT_MAX or more.

>>>> This is the subject of PR 78520.

>>>

>>> this patch broke Solaris bootstrap:

>>>

>>> /vol/gcc/src/hg/trunk/local/gcc/gimple-ssa-sprintf.c: In function

>>> 'void {anonymous}::get_width_and_precision(const

>>> {anonymous}::conversion_spec&, long long int*, long long int*)':

>>> /vol/gcc/src/hg/trunk/local/gcc/gimple-ssa-sprintf.c:777:45: error:

>>> call of overloaded 'abs(long long int)' is ambiguous

>>>   width = abs (tree_to_shwi (spec.star_width));

>>>                                              ^

>>> /vol/gcc/src/hg/trunk/local/gcc/gimple-ssa-sprintf.c:777:45: note:

>>> candidates are:

>>> In file included from /usr/include/stdlib.h:12:0,

>>>                  from /vol/gcc/src/hg/trunk/local/gcc/system.h:258,

>>>                  from

>>> /vol/gcc/src/hg/trunk/local/gcc/gimple-ssa-sprintf.c:49:

>>> /usr/include/iso/stdlib_iso.h:205:16: note: long int std::abs(long int)

>>>   inline long   abs(long _l) { return labs(_l); }

>>>                 ^

>>> /usr/include/iso/stdlib_iso.h:160:12: note: int std::abs(int)

>>>  extern int abs(int);

>>>             ^

>>>

>>> The following patch fixed this for me, but I've no idea if it's right.

>>> It bootstrapped successfully on sparc-sun-solaris2.12,

>>> i386-pc-solaris2.12, and x86_64-pc-linux-gnu.

>>

>> Thanks for the heads up!  I just looked at that code yesterday while

>> analyzing bug 78608, wondering if it was safe.  Now I know it isn't.

>> I think it might be best to simply hand code the expression instead

>> of taking a chance on abs.  Let me take care of it today along with

>> 78608.

>

> I posted a bigger patch to fix this and other related problems on

> Friday (https://gcc.gnu.org/ml/gcc-patches/2016-12/msg00262.html).

> In hindsight, I should have probably committed the fix for this

> on its own.  Please let me know if this is blocking you and I'll

> commit this fix by itself today so you don't have to wait for

> the bigger patch to get reviewed and approved.

What's the concern with using std::abs?

We're already using std::min std::max, std::swap and others.

jeff
Marek Polacek Dec. 5, 2016, 6:30 p.m. UTC | #5
On Mon, Dec 05, 2016 at 11:25:02AM -0700, Jeff Law wrote:
> We're already using std::min std::max, std::swap and others.


Note we're not using std::min nor std::max.  I gave this a shot a while ago,
but it didn't pan out:
https://gcc.gnu.org/ml/gcc-patches/2015-07/msg00886.html

	Marek
Jakub Jelinek Dec. 5, 2016, 6:36 p.m. UTC | #6
On Mon, Dec 05, 2016 at 11:25:02AM -0700, Jeff Law wrote:
> >>

> >>Thanks for the heads up!  I just looked at that code yesterday while

> >>analyzing bug 78608, wondering if it was safe.  Now I know it isn't.

> >>I think it might be best to simply hand code the expression instead

> >>of taking a chance on abs.  Let me take care of it today along with

> >>78608.

> >

> >I posted a bigger patch to fix this and other related problems on

> >Friday (https://gcc.gnu.org/ml/gcc-patches/2016-12/msg00262.html).

> >In hindsight, I should have probably committed the fix for this

> >on its own.  Please let me know if this is blocking you and I'll

> >commit this fix by itself today so you don't have to wait for

> >the bigger patch to get reviewed and approved.

> What's the concern with using std::abs?


We already have abs_hwi and absu_hwi where you choose the semantics you
want.  std::abs might not even have the right overload for HWI.

	Jakub
Jeff Law Dec. 5, 2016, 6:37 p.m. UTC | #7
On 12/05/2016 11:30 AM, Marek Polacek wrote:
> On Mon, Dec 05, 2016 at 11:25:02AM -0700, Jeff Law wrote:

>> We're already using std::min std::max, std::swap and others.

>

> Note we're not using std::min nor std::max.  I gave this a shot a while ago,

> but it didn't pan out:

> https://gcc.gnu.org/ml/gcc-patches/2015-07/msg00886.html

>

> 	Marek

>

tree-ssa-phiprop.c uses std::min and std::max
Jeff
Jakub Jelinek Dec. 5, 2016, 6:39 p.m. UTC | #8
On Mon, Dec 05, 2016 at 11:37:23AM -0700, Jeff Law wrote:
> On 12/05/2016 11:30 AM, Marek Polacek wrote:

> >On Mon, Dec 05, 2016 at 11:25:02AM -0700, Jeff Law wrote:

> >>We're already using std::min std::max, std::swap and others.

> >

> >Note we're not using std::min nor std::max.  I gave this a shot a while ago,

> >but it didn't pan out:

> >https://gcc.gnu.org/ml/gcc-patches/2015-07/msg00886.html

> >

> >	Marek

> >

> tree-ssa-phiprop.c uses std::min and std::max


If you mean the
std::max(std::min(a0, c), std::min(std::max(a1, c), b))
line, that is in a comment.

	Jakub
Martin Sebor Dec. 5, 2016, 6:52 p.m. UTC | #9
On 12/05/2016 11:25 AM, Jeff Law wrote:
> On 12/05/2016 08:50 AM, Martin Sebor wrote:

>> On 12/02/2016 08:52 AM, Martin Sebor wrote:

>>> On 12/02/2016 01:31 AM, Rainer Orth wrote:

>>>> Hi Martin,

>>>>

>>>>> PR 78521 notes that the gimple-ssa-sprintf pass doesn't do the right

>>>>> thing (i.e., the -Wformat-length and -fprintf-return-value options

>>>>> behave incorrectly) when a conversion specification includes a width

>>>>> or precision with a non-constant value.  The code treats such cases

>>>>> as if they were not provided which is incorrect and results in

>>>>> the wrong bytes counts in warning messages and in the wrong ranges

>>>>> being generated for such calls (or in the case sprintf(0, 0, ...)

>>>>> for some such calls being eliminated).

>>>>>

>>>>> The attached patch corrects the handling of these cases, plus a couple

>>>>> of other edge cases in the same area: it adjusts the parser to accept

>>>>> precision in the form of just a period with no asterisk or decimal

>>>>> digits after it (this sets the precision to zero), and corrects the

>>>>> handling of zero precision and zero argument in integer directives

>>>>> to produce no bytes on output.

>>>>>

>>>>> Finally, the patch also tightens up the constraint on the upper bound

>>>>> of bounded functions like snprintf to be INT_MAX.  The functions

>>>>> cannot

>>>>> produce output in excess of INT_MAX + 1 bytes and some implementations

>>>>> (e.g., Solaris) fail with EINVAL when the bound is INT_MAX or more.

>>>>> This is the subject of PR 78520.

>>>>

>>>> this patch broke Solaris bootstrap:

>>>>

>>>> /vol/gcc/src/hg/trunk/local/gcc/gimple-ssa-sprintf.c: In function

>>>> 'void {anonymous}::get_width_and_precision(const

>>>> {anonymous}::conversion_spec&, long long int*, long long int*)':

>>>> /vol/gcc/src/hg/trunk/local/gcc/gimple-ssa-sprintf.c:777:45: error:

>>>> call of overloaded 'abs(long long int)' is ambiguous

>>>>   width = abs (tree_to_shwi (spec.star_width));

>>>>                                              ^

>>>> /vol/gcc/src/hg/trunk/local/gcc/gimple-ssa-sprintf.c:777:45: note:

>>>> candidates are:

>>>> In file included from /usr/include/stdlib.h:12:0,

>>>>                  from /vol/gcc/src/hg/trunk/local/gcc/system.h:258,

>>>>                  from

>>>> /vol/gcc/src/hg/trunk/local/gcc/gimple-ssa-sprintf.c:49:

>>>> /usr/include/iso/stdlib_iso.h:205:16: note: long int std::abs(long int)

>>>>   inline long   abs(long _l) { return labs(_l); }

>>>>                 ^

>>>> /usr/include/iso/stdlib_iso.h:160:12: note: int std::abs(int)

>>>>  extern int abs(int);

>>>>             ^

>>>>

>>>> The following patch fixed this for me, but I've no idea if it's right.

>>>> It bootstrapped successfully on sparc-sun-solaris2.12,

>>>> i386-pc-solaris2.12, and x86_64-pc-linux-gnu.

>>>

>>> Thanks for the heads up!  I just looked at that code yesterday while

>>> analyzing bug 78608, wondering if it was safe.  Now I know it isn't.

>>> I think it might be best to simply hand code the expression instead

>>> of taking a chance on abs.  Let me take care of it today along with

>>> 78608.

>>

>> I posted a bigger patch to fix this and other related problems on

>> Friday (https://gcc.gnu.org/ml/gcc-patches/2016-12/msg00262.html).

>> In hindsight, I should have probably committed the fix for this

>> on its own.  Please let me know if this is blocking you and I'll

>> commit this fix by itself today so you don't have to wait for

>> the bigger patch to get reviewed and approved.

> What's the concern with using std::abs?


My concern, when I wrote the reply n Friday, was that not all C++98
implementations may get std::abs right, declare it in the right header,
avoid defining the abs macro, or put it in namespace std.  (IIRC,
the standard itself wasn't quite right.)

I also need to avoid calling abs with a TYPE_MIN argument because
that's undefined and flagged by ubsan (as per the bug in the subject,
though it was not a result of calling abs but rather that of negating
it).

Besides avoiding the undefined behavior in the compiler I also need
diagnose it (in the program).  The test case for it goes like this:

   int n = sprintf (0, 0, "%*i", INT_MIN, 0);

where the INT_MIN is interpreted as the left justification flag
followed by a positive width of -(unsigned long)INT_MIN.  The
problem is that the function (declared to return int0 is being
asked to return INT_MAX + 1 which is undefined (in the program).

Martin
Jeff Law Dec. 6, 2016, 11:30 p.m. UTC | #10
On 12/05/2016 11:52 AM, Martin Sebor wrote:
>> What's the concern with using std::abs?

>

> My concern, when I wrote the reply n Friday, was that not all C++98

> implementations may get std::abs right, declare it in the right header,

> avoid defining the abs macro, or put it in namespace std.  (IIRC,

> the standard itself wasn't quite right.)

>

> I also need to avoid calling abs with a TYPE_MIN argument because

> that's undefined and flagged by ubsan (as per the bug in the subject,

> though it was not a result of calling abs but rather that of negating

> it).

I'm less concerned about the older C++ implementations as I am about the 
TYPE_MIN overflow.  Thanks for clarifying.


>

> Besides avoiding the undefined behavior in the compiler I also need

> diagnose it (in the program).  The test case for it goes like this:

>

>   int n = sprintf (0, 0, "%*i", INT_MIN, 0);

>

> where the INT_MIN is interpreted as the left justification flag

> followed by a positive width of -(unsigned long)INT_MIN.  The

> problem is that the function (declared to return int0 is being

> asked to return INT_MAX + 1 which is undefined (in the program).

Understood.  Thanks again.

jeff
diff mbox

Patch

diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c
--- a/gcc/gimple-ssa-sprintf.c
+++ b/gcc/gimple-ssa-sprintf.c
@@ -774,7 +774,7 @@  get_width_and_precision (const conversio
   if (spec.star_width)
     {
       if (TREE_CODE (spec.star_width) == INTEGER_CST)
-	width = abs (tree_to_shwi (spec.star_width));
+	width = std::abs (tree_to_shwi (spec.star_width));
       else
 	width = HOST_WIDE_INT_MIN;
     }