Re: rationale for eliding modifications to string constants
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
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
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
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
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
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
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
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
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
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