7

I am surprised this compiles without any warning:

int main()
{ 
    *"abc" = '\0';
}

with gcc main.c -Wall -Wextra and clang main.c -Weverything.

Why is there no warning for this ? Is there any way this could not raise a segmentation fault ?

Bilow
  • 2,194
  • 1
  • 19
  • 34
  • 4
    An even better question is: why does `"abc"[0] = '\0';` give a warning? Seems like some inconsistency in gcc here. – Lundin Sep 07 '17 at 14:54
  • 1
    Why should it? A `char *` is not `const` qualified. If you find a compiler for any language wich will generate a diagnostic if the code is wrong, apply for the Nobel Price for solving the Halting Problem. And please provide a reference to the standard why there has to be a segfault or any other specific behaviour. – too honest for this site Sep 07 '17 at 14:58
  • 2
    @Olaf Maybe I could ask the other way around as Lundin says: why is there a warning `assignment of read-only location` with `"abc"[0] = '\0';` if the `char *` is not `const` qualified? – Bilow Sep 07 '17 at 15:00
  • 2
    You could probably come up with dozens of such examples for which gcc "doesn't warn". The question is whether it's required to. And the answer is it's not. Because your code invokes has *undefined behaviour*. While it'd be *nice* if gcc identifies those things (undefined or not), it can't do in general for *all* such cases. – P.P Sep 07 '17 at 15:02
  • 1
    @Bilow: `const` does not mean "read-only location". A string literal is not a `const char []` in C. And you still lack proof a warning is required for the code. Notice that I did not say it is correct code, but no C compiler will warn about all wrong usages of the language. – too honest for this site Sep 07 '17 at 15:05
  • The behavior on attempting to modify the contents of a string literal is *undefined*, and the compiler is not required to issue diagnostics for undefined behavior. That you get a warning for one form and not the other is a quality of implementation issue, but gcc isn't doing anything "wrong" here. – John Bode Sep 07 '17 at 15:09
  • So for the reasons you explained, gcc is nice to warn us about `"abc"[0] = '\0';`, but it is not required to ? – Bilow Sep 07 '17 at 15:12
  • @Bilow: Yes. gcc is technically going above and beyond by issuing a warning on `"abc"[0] = '\0';`. – John Bode Sep 07 '17 at 15:13
  • 1
    As a sidenote for @Lundin s comment: `*("ABC" + 0) = '\0';` also gives no warning. That would be the exact equivalent to the index-operator. – too honest for this site Sep 07 '17 at 15:13
  • @Bilow: As given in the answer, using the right options, you will get a warning. But that makes the code not strictly conforming. String literals not being `const` qualified is a legacy in C; IMO it should have been fixed with C11, but the commitee is very "careful" not clean up too many legacies at once. – too honest for this site Sep 07 '17 at 15:15
  • Should I mark anything as accepted or answered as several people helped me? Also why do you think have several people downvoted? – Bilow Sep 07 '17 at 15:25

1 Answers1

4

You can use -Wwrite-strings to get a warning for this code in GCC. From the GCC documentation:

-Wwrite-strings

When compiling C, give string constants the type const char[length] so that copying the address of one into a non-const char * pointer will get a warning. These warnings will help you find at compile time code that can try to write into a string constant, but only if you have been very careful about using const in declarations and prototypes. Otherwise, it will just be a nuisance. This is why we did not make -Wall request these warnings.

When compiling C++, warn about the deprecated conversion from string literals to char *. This warning is enabled by default for C++ programs.

"Is there any way this could not raise a segmentation fault ?" -> It is undefined behavior to modify a string litteral. So anything could happen, including not segfaulting.

Community
  • 1
  • 1
Samuel Peter
  • 4,136
  • 2
  • 34
  • 42
  • -Wall and -Wextra should have it covered though – savram Sep 07 '17 at 15:07
  • That does not answer why it does warn about the equivalent index-operator. – too honest for this site Sep 07 '17 at 15:08
  • @savram No, -Wall and -Wextra don't activate all possible warnings. – Samuel Peter Sep 07 '17 at 15:08
  • @savram: Read the last sentence of the first citation! – too honest for this site Sep 07 '17 at 15:10
  • Lol. One would think -Wall would cover, you know, all warnings. And if not -Wextra would cover the rest. How misleading. – savram Sep 07 '17 at 15:12
  • Do you have some link? I'm wondering how it could not segfault, even if I can't rely on the fact it will segfault. What else could happen? – Bilow Sep 07 '17 at 15:24
  • @Bilow It could overwrite the 'a' with a 0. It will only segfault if the linker indeed places string literals in some read only section, but it is not at all required to do that. – Samuel Peter Sep 07 '17 at 15:35
  • I didn't knew, thanks. Could still something else happen ? – Bilow Sep 07 '17 at 15:40
  • @Olaf "That does not answer why it does warn about the equivalent index-operator." -> This was not the question... Besides it is really a GCC implementation detail. The warning comes from the "readonly_warning" function in c-typeck.c. If you really want to know why using `*` makes GCC forget that it considers "abc" as read only, you could read the GCC code and find out under which condition this function is called: https://github.com/gcc-mirror/gcc/blob/master/gcc/c/c-typeck.c – Samuel Peter Sep 07 '17 at 15:40
  • @Bilow With undefined behavior, anything can happen :) But realistically the two likely outcomes are either an overwrite or an error (segfault or otherwise) – Samuel Peter Sep 07 '17 at 15:44
  • @SamuelPeter: " It will only segfault if the linker indeed places string literals in some read only section" - That still does not guarantee segfault. Most systems have no way to check access permissions. Some might even damage the hardware. UB is UB, no use in expecting a specific behaviour here. Considering systems which have an MMU or MPU are the minority, "realistically" the outcome is unpredictable. – too honest for this site Sep 07 '17 at 15:45
  • Even if theoretically possible, did one already have an UB fry the CPU or call something like `system("rm -rf /")`? Is this really possible? – Bilow Sep 07 '17 at 15:47
  • @Olaf Yes, I know, thanks... Just simplifying things to explain that segfault in this case would be because of a decision by the linker which it is not required to make – Samuel Peter Sep 07 '17 at 15:51
  • @Bilow: On a rough guess: You never worked with embedded systems, did you? – too honest for this site Sep 07 '17 at 15:53
  • 1
    @SamuelPeter: If we talk about full-OS systems like x86: No, it is not the linker, but the OS loader which places the `rodata` section into write-protected RAM. Things become a bit more complicated if we talk about shared libraries, i.e. dynamic linking/loading. But I would just have left it at UB; that's; all one needs to care about. Bringing segfault and the linker into the game is indeed confusing. Never change abstraction level if not really necessary. UB otoh is a fundamental concept in programming and C specifically. Askers are expected to understand these basics or do research. – too honest for this site Sep 07 '17 at 15:56
  • @Olaf Well you could make a linker script that places any `.rodata*` input section into the `.data` output section, and then the loader would load them in writable memory. But yeah I agree that so many things can happen, it's better to leave it at UB :) – Samuel Peter Sep 07 '17 at 16:19
  • 1
    @Olaf It's exactly because people like you don't explain anything beyond UB that I didn't get it yet. I'll ask new question for this. – Bilow Sep 07 '17 at 16:20
  • @Bilow: I could return that and notify that UB has been explained so very often here and elsewhere. Problem is there are way too mayn people expecting to be spoon-fed and not able to ally an abstract concept to their specific problem, even when being told. But for now, I'll leave it at pointing out that you did not show any research effort, nor which platorm you use or any other signal you at least tried to find the answer yourself. Feel free to have the last complaint. – too honest for this site Sep 07 '17 at 16:31
  • @Olaf Maybe I should have asked new question about UB in the first place in order to show research effort – Bilow Sep 07 '17 at 16:37
  • @Bilow: _sigh_ Read my comments carefully again! We are not a personal tutoring site, What is your problem with Wikipedia or google or the stack overflow search? – too honest for this site Sep 07 '17 at 16:42
  • @Bilow the first steps would be step one: https://en.wikipedia.org/wiki/Undefined_behavior , step two: http://en.cppreference.com/w/cpp/language/ub , step three: http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html – Shark Sep 07 '17 at 17:01