Bug 25609 - too agressive printf optimization
Summary: too agressive printf optimization
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: rtl-optimization (show other bugs)
Version: 4.0.2
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-12-30 22:59 UTC by Ulrich Drepper
Modified: 2008-01-16 12:36 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ulrich Drepper 2005-12-30 22:59:35 UTC
At least glibc's printf, maybe others as well, print (null) in for code like

  printf ("%s", NULL)

gcc doesn't consider this when optimizing code where the pointer passed for a %s format specifier can be NULL.  Example:

#include <stdio.h>
int
main (int argc, char *argv[])
{
  printf ("%s\n", argc > 1 ? argv[1] : NULL);
  return 0;
}

Compiling and running this code (I use gcc 4.0.2) will result in a program which crashes because the printf is transformed into a puts() call and puts() does not allow NULL pointers.

There should at least be a mode in which gcc does not perform the transformation if it cannot be sure the pointer is not NULL.  The default for Linux and maybe other platforms should be to not perform this optimization if the pointer can be NULL.
Comment 1 Andrew Pinski 2005-12-30 23:01:38 UTC
The code is undefined so seg faulting is an okay thing to do.
Comment 2 Andrew Pinski 2005-12-30 23:05:28 UTC
Reopening to ....
Comment 3 Andrew Pinski 2005-12-30 23:05:42 UTC
Mark as a dup of bug 15574.

*** This bug has been marked as a duplicate of 15574 ***
Comment 4 Ulrich Drepper 2005-12-30 23:06:19 UTC
No, it's *NOT* undefined.  The libc interface decides what is defined and what is not and it is *EXPLICITLY* documented that NULL pointers are printed as (null).

The standard might leave it undefined but this does *NOT* mean the implementation cannot define it.
Comment 5 Andrew Pinski 2005-12-30 23:07:11 UTC
You are wrong.

*** This bug has been marked as a duplicate of 15685 ***
Comment 6 Ulrich Drepper 2005-12-30 23:08:10 UTC
This is NOT a dup of 15574.
Comment 7 Andrew Pinski 2005-12-30 23:08:26 UTC
(In reply to comment #4)
> The standard might leave it undefined but this does *NOT* mean the
> implementation cannot define it.

That is true but GCC is a C compiler and not a glibc implemention C compiler.
Comment 8 Ulrich Drepper 2005-12-30 23:14:58 UTC
> That is true but GCC is a C compiler and not a glibc implemention C compiler.

This doesn't mean anything.  As soon as you configure gcc to target it to Linux the behavior of the runtime is as defined by the C library.  gcc doesn't come with it's own C library so it cannot possibly override any decisions made about undefined behavior.  I explicitly said that this optimization need ony be disabled for platforms using glibc.  I don't give a rats ass what other platforms do.
Comment 9 Andrew Pinski 2005-12-30 23:36:59 UTC
I should note that glibc is not the world.

Also the patch which added the transformations:
http://gcc.gnu.org/ml/gcc-patches/2000-09/msg00826.html


If you see that RTH approved it without any objections.

I still say that this is valid no matter what and people are wrong in assuming that GCC is not going to it as it is undefined code which means depending on it is going to cause portablity issues.
Comment 10 Ulrich Drepper 2005-12-30 23:44:57 UTC
glibc *is* the world as far as Linux is concerned.  You consistently and deliberately misinterpret what I write: I'm not talking about any platform which does not use glibc or glibc's behavior.

And RTH already concurred in private that this is a problem.
Comment 11 Andrew Pinski 2005-12-30 23:49:35 UTC
(In reply to comment #10)
> glibc *is* the world as far as Linux is concerned. 

That is not true at all and you know that.  There is uclibc.

This is still undefined code even if the underlaying printf defines it.
This is still a dup of bug 15685 as that is the orginal bug about this issue.

*** This bug has been marked as a duplicate of 15685 ***
Comment 12 Ulrich Drepper 2005-12-31 00:19:04 UTC
> That is not true at all and you know that.  There is uclibc.

Now you've completely given up on logic?  First of all, uclibc and whatever other libc immitation is out there does not define the linux API.  glibc *is* the world, all the others are just replacements of varying degree of conformance.  This can be seen in the fact that even uclibc implements printf with the behavior in question.

But more importantly here: even if there were one piece of code which behaves differently, this does not disqualify the argument that the API for Linux defines the behavior in question.  This is an OR operation, not AND.  glibc defines the behavior and this means the compiler must handle such code approriately if compiled for Linux.
Comment 13 joseph@codesourcery.com 2006-01-01 22:18:47 UTC
Subject: Re:   New: too agressive printf optimization

On Fri, 30 Dec 2005, drepper at redhat dot com wrote:

> There should at least be a mode in which gcc does not perform the
> transformation if it cannot be sure the pointer is not NULL.  The default for

The mode is -fno-builtin-printf.  The same applies for users with custom 
printf format handlers which modify static variables; they may also need 
to use -fno-builtin-printf.

Comment 14 Manuel López-Ibáñez 2007-11-16 16:17:01 UTC
Is there any difference in the standard behaviour between printf("%s", NULL) and puts(NULL)? I mean, why printf("%s", NULL) receives special consideration but neither puts(NULL) nor fprintf(stdout, "%s", NULL) do?

Anyway, can this be closed as a duplicate of bug 15685 ?
Comment 15 pinskia@gmail.com 2007-11-16 22:11:03 UTC
Subject: Re:  too agressive printf optimization

> Is there any difference in the standard behaviour between printf("%s", NULL)
> and puts(NULL)? I mean, why printf("%s", NULL) receives special consideration
> but neither puts(NULL) nor fprintf(stdout, "%s", NULL) do?

No both are undefined.

-- Pinski
Comment 16 Gustavo De Nardin (spuk) 2008-01-15 17:20:32 UTC
"Glibc being Linux being the world" is not really relevant, IMHO. What is relevant is printf() (or any function) is, fundamentally, implemented by library, not by compiler, so compiler should not prevent library from defining behavior not defined in the standard.

So I think gcc should either:
- provide means to disable printf (or more generaly, any specific function) optimization based on library being linked
- not optimize printf in this way, unless requested (i.e. do not include this optimization in any predefined optimizations list
- probably other alternatives
Comment 17 Manuel López-Ibáñez 2008-01-15 18:51:44 UTC
This will be fixed yesterday if printf("%s\n", s) were equivalent to puts(s) in glibc.

Also there is a way to disable the optimization: "-fno-builtin-printf".

People that don't rely on undefined behaviour don't deserve to be punished with suboptimal code.
Comment 18 Manuel López-Ibáñez 2008-01-15 20:48:55 UTC
There is an explanation for the optimisation, a potential fix [*] and there is a workaround.

[*] http://sourceware.org/bugzilla/show_bug.cgi?id=5618

Comment 19 Gustavo De Nardin (spuk) 2008-01-15 21:08:30 UTC
(In reply to comment #17)
> This will be fixed yesterday if printf("%s\n", s) were equivalent to puts(s) in
> glibc.

[+] The standard requires them to be equivalent? Per standard, they can't be equivalent if both are undefined when NULL is passed, right?


> Also there is a way to disable the optimization: "-fno-builtin-printf".
> 
> People that don't rely on undefined behaviour don't deserve to be punished with
> suboptimal code.

It is not undefined, per glibc. GCC is defining undefined behavior, just as much as glibc, to optimize, that should be documented or fixed.


(In reply to comment #18)
> There is an explanation for the optimisation, a potential fix [*] and there is
> a workaround.
> 
> [*] http://sourceware.org/bugzilla/show_bug.cgi?id=5618

[+]
Comment 20 Manuel López-Ibáñez 2008-01-15 21:49:36 UTC
(In reply to comment #19)
> (In reply to comment #17)
> > This will be fixed yesterday if printf("%s\n", s) were equivalent to puts(s) in
> > glibc.
> 
> [+] The standard requires them to be equivalent? Per standard, they can't be
> equivalent if both are undefined when NULL is passed, right?

I didn't say the standard requires them to be equivalent. Per standard, two undefined invocations of printf don't need to be equivalent.

Anyway, if you really want to believe that printf("%s\n",s) and puts(s) should not have the same effect for defined behaviour, then we will have to agree to disagree.
Comment 21 Gustavo De Nardin (spuk) 2008-01-16 01:52:17 UTC
(In reply to comment #20)
> Anyway, if you really want to believe that printf("%s\n",s) and puts(s) should
> not have the same effect for defined behaviour, then we will have to agree to
> disagree.

That's confused, what is being discussed is undefined behavior X optimization trusting it. Still, the manpage for puts() says "output of characters and strings", while the one for printf() says "formatted output conversion". puts() just sends a string to stdout, printf() converts data into their string representation. So I agree to disagree about the expectation on what they do about NULL: puts() should do nothing or merely return error, while printf() *could* convert or otherwise print a string representation of it.

Given the impasse, and given Glibc defines what it does, I understand the next correct thing for someone who cares to do, is to report a bug on GCC about this issue on any specific distributions using GCC together with Glibc.

cya
Comment 22 Manuel López-Ibáñez 2008-01-16 12:36:13 UTC
(In reply to comment #21)
> (In reply to comment #20)
> > Anyway, if you really want to believe that printf("%s\n",s) and puts(s) should
> > not have the same effect for defined behaviour, then we will have to agree to
> > disagree.
> 
> That's confused, what is being discussed is undefined behavior X optimization
> trusting it.

No, if we follow your reasoning, as you repeat constantly, "It is not undefined, per glibc."

> Still, the manpage for puts() says "output of characters and
> strings", while the one for printf() says "formatted output conversion". puts()
> just sends a string to stdout, printf() converts data into their string
> representation. So I agree to disagree about the expectation on what they do
> about NULL: puts() should do nothing or merely return error, while printf()
> *could* convert or otherwise print a string representation of it.

Finally, we agree about something. :-) Anyway, this has little to do with this bug. This is my personal opinion on how glic could fix if they really wanted. I guess other GCC developers think: "There is nothing to fix, expecting something from undefined behaviour is wrong and the optimisation is valid for all defined cases".

> Given the impasse, and given Glibc defines what it does, I understand the next
> correct thing for someone who cares to do, is to report a bug on GCC about this
> issue on any specific distributions using GCC together with Glibc.

What you want us to do? We should avoid optimising printf("%s\n", s) to puts(s) just because s may be NULL? So, in your opinion, we should punish people that don't rely on printf("%s\n", NULL) being defined, and defined as something different as puts(NULL)? Sorry, we disagree.

You are welcome to waste your (and others people) time reporting duplicated bugs. We will point them to this discussion. I think there is far enough information here and, in particular, in http://sourceware.org/bugzilla/show_bug.cgi?id=5618 , for anyone to make their own opinion about the issue. If distributions want to patch GCC or use -fno-builtin-printf by default, they are allow to do it. Good luck with that. Please, I am sure you are not that kind of internet character that needs to have the last word on everything, so accept that this is closed. Thanks.