Re: rationale for eliding modifications to string constants

2010-09-14 Thread Uday P. Khedker

Interesting example indeed!

Replace the declaration of s to

 char s[] = hello;

and see Hello being printed :-)

The point is: in your program is is only a pointer. When you pass s
as a parameter to printf, the compiler assumes that only s is being
used so the (effective) assignment

   *s = 'H'

is deleted as dead code when optimization is enabled.

If you do not optimize the program, you get a segmentation fault (rightly so).

When s is converted from pointer to array, the assignment s[0] is not
a dead assignment because the array base address is passed to the
printf function.

Hope that helps.

Uday.
--
Dr. Uday Khedker
Professor
Department of Computer Science  Engg.
IIT Bombay, Powai, Mumbai 400 076, India.
email   : u...@cse.iitb.ac.in
homepage: http://www.cse.iitb.ac.in/~uday
phone   : Office - 91 (22) 2572 2545 x 7717, 91 (22) 2576 7717 (Direct)
  Res.   - 91 (22) 2572 2545 x 8717, 91 (22) 2576 8717 (Direct)
--

Godmar Back wrote, On Tuesday 14 September 2010 11:08 PM:

int
main()
{
 char * s = (char *)hello; // read-only
 printf(%s\n, s);
 s[0] = 'H';// gcc -O elides this
 printf(%s\n, s);
 return 0;
}

Could someone briefly provide justification/rationale for this decision?


Re: rationale for eliding modifications to string constants

2010-09-14 Thread Daniel Jacobowitz
On Tue, Sep 14, 2010 at 11:50:11PM +0530, Uday P. Khedker wrote:
 The point is: in your program is is only a pointer. When you pass s
 as a parameter to printf, the compiler assumes that only s is being
 used so the (effective) assignment
 
*s = 'H'
 
 is deleted as dead code when optimization is enabled.

No, this is incorrect.  The issue must be specific to modification of
read-only data.

-- 
Daniel Jacobowitz
CodeSourcery


Re: rationale for eliding modifications to string constants

2010-09-14 Thread Ian Lance Taylor
Godmar Back god...@gmail.com writes:

 this may be a FAQ - in my class today when discussing how gcc
 generates code for x86, I was stumped when I showed an example of how
 gcc handles attempts to modify (read-only) string literals/constants.
 (I'm sending this to gcc rather than gcc-help because I'm asking for a
 design rationale - I believe I understand the semantics of string
 constants in C. If in appropriate, I'm happy to resend there.)

 Specifically, I was surprised to see that gcc 4.1.2, when invoked with
 -O, simply elided the offending statement s[0] = 'H' in the example
 below.

 int
 main()
 {
     char * s = (char *)hello;     // read-only
     printf(%s\n, s);
     s[0] = 'H';    // gcc -O elides this
     printf(%s\n, s);
     return 0;
 }

 Could someone briefly provide justification/rationale for this decision?

 Is the rationale simply that since the behavior of a program that
 attempts to modify a string constant is undefined (KR) you felt
 justified in silently discarding it (rather than letting it proceed or
 cause a runtime error if the string literal is mapped in a read-only
 section of the address space?)

 I note that even though the compiler knows it is taking advantage of a
 rule that allows it to produce code that contains undefined behavior,
 there appears to be no warning option to alert the user. Notably, gcc
 -Wall -Wwrite-string is silent for the above program.

I think this is simply a bug.  It doesn't happen with current gcc.  With
gcc 4.4.3 the assignment is being eliminated because it is considered to
be dead code.  

I agree that it is an error for gcc to simply eliminate this assignment
with no warning.

Ian


Re: rationale for eliding modifications to string constants

2010-09-14 Thread Axel Freyn
Hello Uday,
On Tue, Sep 14, 2010 at 11:50:11PM +0530, Uday P. Khedker wrote:
 [..]
 The point is: in your program is is only a pointer. When you pass s
 as a parameter to printf, the compiler assumes that only s is being
 used so the (effective) assignment

*s = 'H'

 is deleted as dead code when optimization is enabled.
I can't believe your argumentation is correct. Wouldn't that mean:
When I have a code, where I only pass the pointer to a function like:

void f(int *);
int main(){
  int *s = (int *)malloc(100,sizeof(int));
  for(int i = 0; i  100; ++i)
s[i] = 0;
  f(s);
  free(s);
}

The compiler would be allowed to erase the complete for-loop? And thus
the initialization of the array?

Or I did misunderstand your argumentation...

Axel


Re: rationale for eliding modifications to string constants

2010-09-14 Thread Uday P. Khedker

Attached please find two dumps t.c.032t.mergephi1 and t.c.033t.cddce1.
The assignment is present in the former while it disappears in the
latter. The latter dump is the output of the dead code elimination
pass pass_cd_dce. So this is indeed an instance of dead code elimination.

But may be you are right, what facilitate dead code elimination
be based on modification of read-only data. However, if that is
the case, I wonder what is the reason why change happens when s is
an array...


Daniel Jacobowitz wrote, On Tuesday 14 September 2010 11:54 PM:

On Tue, Sep 14, 2010 at 11:50:11PM +0530, Uday P. Khedker wrote:

The point is: in your program is is only a pointer. When you pass s
as a parameter to printf, the compiler assumes that only s is being
used so the (effective) assignment

*s = 'H'

is deleted as dead code when optimization is enabled.


No, this is incorrect.  The issue must be specific to modification of
read-only data.


;; Function printf (printf)

printf (const char * restrict __fmt)
{
  int D.1913;

bb 2:
  D.1913_2 = __printf_chk (1, __fmt_1(D), __builtin_va_arg_pack ());
  return D.1913_2;

}



;; Function main (main)

main ()
{
  int D.2657;
  int D.2657;
  int D.2654;
  int D.2654;
  const char * restrict D.2648;

bb 2:
  D.2648_2 = (const char * restrict) %s\n;
  D.2654_5 = __printf_chk (1, D.2648_2, hello[0]);
  hello[0] = 72;
  D.2648_3 = (const char * restrict) %s\n;
  D.2657_6 = __printf_chk (1, D.2648_3, hello[0]);
  return 0;

}



;; Function printf (printf)

printf (const char * restrict __fmt)
{
  int D.1913;

bb 2:
  D.1913_2 = __printf_chk (1, __fmt_1(D), __builtin_va_arg_pack ());
  return D.1913_2;

}



;; Function main (main)

main ()
{
  const char * restrict D.2648;

bb 2:
  D.2648_2 = (const char * restrict) %s\n;
  __printf_chk (1, D.2648_2, hello[0]);
  D.2648_3 = (const char * restrict) %s\n;
  __printf_chk (1, D.2648_3, hello[0]);
  return 0;

}




Re: rationale for eliding modifications to string constants

2010-09-14 Thread Andrew Pinski
On Tue, Sep 14, 2010 at 11:47 AM, Uday P. Khedker u...@cse.iitb.ac.in wrote:
 Attached please find two dumps t.c.032t.mergephi1 and t.c.033t.cddce1.
 The assignment is present in the former while it disappears in the
 latter. The latter dump is the output of the dead code elimination
 pass pass_cd_dce. So this is indeed an instance of dead code elimination.

 But may be you are right, what facilitate dead code elimination
 be based on modification of read-only data. However, if that is
 the case, I wonder what is the reason why change happens when s is
 an array...

What is being done is correct really.  Since the string has the type
of const char[]. Since you have an explicit cast to get rid of the
const qualifer, we don't warn.  I don't see a bug here at all really.
You are invoking an undefined behavior, GCC keep the assignment around
or get rid of it.

-- Pinski


Re: rationale for eliding modifications to string constants

2010-09-14 Thread Uday P. Khedker

You got me there :-)

Yes you are right. The reason I gave for dead code elimination is not
sound! Should have thought a bit before writing :-(

Uday.

Axel Freyn wrote, On Wednesday 15 September 2010 12:05 AM:

Hello Uday,
On Tue, Sep 14, 2010 at 11:50:11PM +0530, Uday P. Khedker wrote:

[..]
The point is: in your program is is only a pointer. When you pass s
as a parameter to printf, the compiler assumes that only s is being
used so the (effective) assignment

*s = 'H'

is deleted as dead code when optimization is enabled.

I can't believe your argumentation is correct. Wouldn't that mean:
When I have a code, where I only pass the pointer to a function like:

void f(int *);
int main(){
   int *s = (int *)malloc(100,sizeof(int));
   for(int i = 0; i  100; ++i)
 s[i] = 0;
   f(s);
   free(s);
}

The compiler would be allowed to erase the complete for-loop? And thus
the initialization of the array?

Or I did misunderstand your argumentation...

Axel


Re: rationale for eliding modifications to string constants

2010-09-14 Thread Godmar Back
On Tue, Sep 14, 2010 at 2:35 PM, Ian Lance Taylor i...@google.com wrote:

 I think this is simply a bug.  It doesn't happen with current gcc.  With
 gcc 4.4.3 the assignment is being eliminated because it is considered to
 be dead code.

 I agree that it is an error for gcc to simply eliminate this assignment
 with no warning.


Thanks, that's what I thought.

 - Godmar


Re: rationale for eliding modifications to string constants

2010-09-14 Thread Dave Korn
On 14/09/2010 19:47, Uday P. Khedker wrote:

 But may be you are right, what facilitate dead code elimination
 be based on modification of read-only data. However, if that is
 the case, I wonder what is the reason why change happens when s is
 an array...

  Because the array, unlike the string, isn't const.

char *s = (char *)string;

- s is a pointer to a string (that the compiler happens to know is constant).

char s[] = string;

- s is an array of non-constant chars, initialised at startup from a string
constant; it's the same as writing

char s[] = { 's', 't', 'r', 'i', 'n', 'g', '\0' };

  Arrays and pointers are not the same thing in C!

cheers,
  DaveK



Re: rationale for eliding modifications to string constants

2010-09-14 Thread Ian Lance Taylor
Andrew Pinski pins...@gmail.com writes:

 On Tue, Sep 14, 2010 at 11:47 AM, Uday P. Khedker u...@cse.iitb.ac.in wrote:
 Attached please find two dumps t.c.032t.mergephi1 and t.c.033t.cddce1.
 The assignment is present in the former while it disappears in the
 latter. The latter dump is the output of the dead code elimination
 pass pass_cd_dce. So this is indeed an instance of dead code elimination.

 But may be you are right, what facilitate dead code elimination
 be based on modification of read-only data. However, if that is
 the case, I wonder what is the reason why change happens when s is
 an array...

 What is being done is correct really.  Since the string has the type
 of const char[]. Since you have an explicit cast to get rid of the
 const qualifer, we don't warn.  I don't see a bug here at all really.
 You are invoking an undefined behavior, GCC keep the assignment around
 or get rid of it.

I agree that this is technically correct but I still think it is a bad
choice.  Fortunately it does seem to work as I want in mainline.

Ian