C++ Segmentation Fault when using cout in static variable initialization
Asked Answered
C

3

16

I have a program where I use cout to emit debug information. The code is executed in the initialization of a static global variable, i.e. quite early in the program execution. When I use my own build script to build the program, it segfaults at the first use of cout (only a string literal is shifted into cout, so it cannot be the value). I used valgrind to check for earlier writes to invalid locations, but there are none (and there is also no code that would be likely to generate those writes, I dont do too much before the output). When I copy the source code to an eclipse project and let the eclipse built-in builder build it, then everything works fine. I used no weird builder settings simply compiled with -ggdb -std=c++0x, these are the only two flags.

So what can be the reason that a cout with a string literal segfaults, if there were no invalid writes before? How can the build configuration affect this?

(I am sorry I can give you no minimal example, as this example would simply compile fine at your machine, as it does for me when using the eclipse builder)

Edit: Here is the stacktrace:

0x00007ffff7b6d7d1 in std::ostream::sentry::sentry(std::ostream&) () from /usr/lib   /x86_64-linux-gnu/libstdc++.so.6
(gdb) backtrace
#0  0x00007ffff7b6d7d1 in std::ostream::sentry::sentry(std::ostream&) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#1  0x00007ffff7b6dee9 in std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) ()
from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#2  0x00007ffff7b6e2ef in std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) ()
  from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3  0x00000000004021be inTest::fill (this=0x6120f8, funcs=...) at inTest.cpp:92

The last frame is my code. Line 92 simply reads:

std::cout << "Test";
Cannibal answered 7/9, 2012 at 13:3 Comment(3)
Use a debugger to try and find out what it might be. And if nothing else, at least please post the relevant lines of code (after you confirmed in the debugger which they are).Hawkie
@JoachimPileborg Edited my post, included the backtrace of gdbCannibal
What are the complete compile and link commands you use?Blizzard
B
16

As Luchian has pointed out, you cannot use std::cout before the first instance of ios_base::Init has been constructed. You don't have to define an instance, however; including <iostream> should be enough.

Order of initialization is defined within a single translation unit. If you include <iostream> at the top of all files which have static instances, you should be OK. If the constructor of a static object calls a function in another translation unit, however, and the output is in that translation unit, it is not sufficient to include <iostream> only in the translation unit which does the output. You must include it in the translation unit where the static variable(s) are defined. Even if they don't do any output.

Blitz answered 7/9, 2012 at 13:32 Comment(12)
That was my problem! One static called a method of another translation unit and only that other translation unit included <iostream>. I moved the include of <iostream> into the header in able to make sure that every translation unit that includes the called function also includes <iostream>. Now it works.Cannibal
@gexicide: I could go a bit further and say that your problem is actually having static variables and dependencies on the order of initialization. What you say was your problem is actually the symptoms.Cleanthes
@DavidRodríguez-dribeas: I do not have order of initialization problems with my own code. I was just debugging some nasty bug in the initialization and used couts for it (I know, a debugger is usually better, but sometimes simply dumping out some debug text is better)Cannibal
@DavidRodríguez-dribeas There are (today) more or less standard idioms which you can use to avoid this sort of problem. std::cout doesn't use them, however. And his problem involved the order of initialization between his objects and std::cout.Blitz
@gexicide: From the description you provided: one static called a method of another translation unit, and that function in another translation unit depends on another static (cout). The moment that one static variable depends on anything (static object or function or otherwise) you are opening the door for the static initialization order fiascoCleanthes
@JamesKanze: Can you point me to what idioms do solve the static initailization order fiasco? (Other than not having namespace/class level static variables?)Cleanthes
@DavidRodríguez-dribeas: Yes, but the problem only existed during debugging. I wanted to point out that the original code is not flawed and I will surely not rewrite the code into not using statics only because it fails with debug couts :).Cannibal
@DavidRodríguez-dribeas The usual idiom today is the singleton pattern, where the initialization actually occurs in a function (and so occurs the first time the function is called). If iostream were being designed today, who knows. Perhaps we'd have to write std::cout().Blitz
@JamesKanze: Ah, ok, I knew that one, and it is not bulletproof either. It guarantees that the order of construction won't cause an issue, but it does not guarantee that the order of destruction will not cause it. That is if a static object depends on a different static object during destruction but not during construction, then the static local trick won't cut it. Then you can jump into the phoenix singleton that Alexandrescu wrote in Modern C++ Design and all that... but that brings it's own problems. I am not sure that the approach with cout is not better than the local static one...Cleanthes
... that is, it is guaranteed to work unless your static object depends on a function in a different translation unit and you are not including the <iostream> header in your translation unit. The problem is still that the static initialization is not self contained in a single translation unit.Cleanthes
@DavidRodríguez-dribeas In the usual singleton idiom, the object is never destructed. (An the standard requires that std::cout never be destructed.) The idiom used by std::cout is less secure, which is why the singleton idiom has become preferred.Blitz
+infinity for being exactly what I needed, comprehensively explaining why I was getting a segfault when a ctor used cout, but including <iostream> in a seemingly distant hpp fixed it. Turns out the ctor was invoked in a static variable, in a different cpp which included the other hpp. Adding <iostream> to the cpp defining the variable sorted it. Btw, the cout in ctor is only for debugging, I've commented why <iostream> is included in the static def file, and I've added a link to your post, too :-)Apotheosis
H
15

std::cout is an object in static storage. It's guaranteed to be initialized before entering main, but not necessarily before other statics in your code. Seems like the static initialization order fiasco.

After some digging:

27.4.2.1.6 Class ios_base::Init

Init ();

3) Effects: Constructs an object of class Init. If init_cnt is zero, the function stores the value one in init_- cnt , then constructs and initializes the objects cin, cout, cerr, clog (27.3.1), wcin, wcout, wcerr, and wclog (27.3.2). In any case, the function then adds one to the value stored in init_cnt .

Henni answered 7/9, 2012 at 13:7 Comment(11)
but doesnt std::cout use the nifty counter pattern to ensure that it is initialized before first use?Cannibal
@Cannibal I'm searching the standard now, but couldn't find anything yet.Henni
@gexicide: No, it isn't. It would have to be a function for that and it's not a function.Henshaw
@JanHudec: gexicide is actually right, it is done through the ios_base::Init objectsCleanthes
@DavidRodríguez-dribeas just found it, added.Henni
@Cannibal try instantiating the Init class before a call to cout, if it solves the problem, then you've found it.Henni
Hm, the C++11 specification says that including <iostream> should have an effect as if it created static instance if ios_base::Init (which causes it to be initialized before any other static objects in that translation unit), but C++03 one does not.Henshaw
Oh, and because we are talking about C++11, it would make it a bug in libstdc++!Henshaw
@JanHudec ah, but the current TU doesn't have to include <iostream> in order to indirectly call cout::operator <<.Henni
@Cannibal try including <iostream> in the translation unit that calls the method that prints.Henni
oh, okay. That was it! After moving the include of <iostream> from the cpp file to the header (to make sure that all translation units that include my file also include <iostream>) it works.Cannibal
C
0

Static variable initialization is a no-man's-land. You will avoid problems if you avoid doing significant work there. Maybe you should wrap the static variable in a Singleton pattern so you can defer initialization to the first time it's used.

Contortive answered 7/9, 2012 at 13:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.