Problem
bekam ich einen Fehlerbericht von Benutzern eine segfault in der Bibliothek Berichterstattung ich entwickeln.std :: map Argument mit leeren Klammer-Initialisierer für Standardargument segfaults in GCC
Das minimale Beispiel des fehlerhaften Code ist:
#include <map>
#include <string>
#include <iostream>
void f(std::map<std::string, std::string> m = {})
{
std::cout << m.size() << "\n";
for (const auto& s: m) {
std::cout << s.first << "->" << s.second <<"\n";
}
}
int main()
{
f();
}
Wenn mit GCC kompiliert (I getestet 4.8.2 und 4.7.3) es richtig gedruckt 0
als Größe des Behälters, aber innerhalb der Schleife segfaults (was überhaupt nicht ausgeführt werden sollte).
Umgehungen
Allerdings kann ich beheben das Problem durch die Erklärung auf sich ändernde:
void f(std::map<std::string, std::string> m = std::map<std::string, std::string>{})
Kopieren der map
Werke auch:
void f(std::map<std::string, std::string> mx = {})
{
auto m = mx;
std::cout << m.size() << "\n";
for (const auto& s: m) {
std::cout << s.first << "->" << s.second <<"\n";
}
}
den Parameter auf const std::map<...>&
Ändern funktioniert auch.
GCC 4.9.1 funktioniert gut.
Clang kompiliert und führt den Code auch gut aus. (Auch wenn die gleichen libstdC++ verwenden wie gcc andernfalls 4.8.2)
Arbeiten Beispiel: http://coliru.stacked-crooked.com/a/eb64a7053f542efd
Frage
Die Karte ist auf jeden Fall nicht in gültigem Zustand innerhalb der Funktion (Details unten). Es sieht aus wie ein GCC (oder libstdC++) Fehler, aber ich möchte sicher sein, dass ich hier keinen dummen Fehler mache. Es ist schwer zu glauben, dass ein solcher Fehler für mindestens 2 Hauptversionen in gcc bleiben würde.
Also meine Frage ist: Ist der Weg Standard std::map
Parameter falsch (und Fehler in meinem Code) oder ist es ein Bug in stdlibc++
(oder gcc
) der Initialisierung?
Ich suche keine Problemumgehungen (wie ich weiß was zu tun ist, um Code zu arbeiten) Bei der Integration in die Anwendung wird der fehlerhafte Code auf einigen Computern (auch wenn mit gcc 4.8.2 kompiliert) auf manche nicht.
Einzelheiten
ich kompilieren mit:
g++-4.8.2 -g -Wall -Wextra -pedantic -std=c++11 /tmp/c.cpp -o /tmp/t
Backtrace von GDB:
#0 std::operator<< <char, std::char_traits<char>, std::allocator<char> > (__os=..., __str=...) at /usr/src/debug/sys-devel/gcc-4.8.2/build/x86_64-pc-linux-gnu/libstdc++-v3/include/bits/basic_string.h:2758
#1 0x0000000000400f36 in f (m=std::map with 0 elements) at /tmp/c.cpp:9
#2 0x0000000000400fe0 in main() at /tmp/c.cpp:15
/tmp/c.cav: 9 ist die Linie mit std::cout << ...
ASAN Berichte:
AddressSanitizer: SEGV on unknown address 0xffffffffffffffe8
Dies scheint nullptr - 8
valgrind zeigt:
==28183== Invalid read of size 8
==28183== at 0x4ECC863: std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) (in /usr/lib64/gcc/x86_64-pc-linux-gnu/4.8.2/libstdc++.so.6.0.18)
==28183== by 0x400BD5: f(std::map<std::string, std::string, std::less<std::string>, std::allocator<std::pair<std::string const, std::string> > >) (c.cpp:9)
==28183== by 0x400C7F: main (c.cpp:15)
==28183== Address 0xffffffffffffffe8 is not stack'd, malloc'd or (recently) free'd
im internen Zustand der Karte Suchen Sie zeigt, dass die Code hat wirklich zum scheitern verurteilt:
std::map::begin()
in libstdC++ liefert Wert von
this->_M_impl._M_header._M_parent
aus es interne Darstellung, std::map::end()
kehrt:
&this->_M_impl._M_header
gdb zeigt:
(gdb) print m._M_t._M_impl._M_header
$5 = {_M_color = std::_S_red, _M_parent = 0x0, _M_left = 0x7fffffffd6d8, _M_right = 0x7fffffffd6d8}
(gdb) print &m._M_t._M_impl._M_header
$6 = (std::_Rb_tree_node_base *) 0x7fffffffd6a8
So Wert von begin()
und end()
nicht gleich sind (begin()
wie für leere std::map
von Standard vorgeschrieben ist nullptr).
FWIW, wenn ich 'std :: cout << s.first << "->" << s.second << "\ n"; 'durch' std :: cout << "kam hier \ n"; ', Das Programm druckt die Zeile einmal und hängt dann. –
"Es ist schwer zu glauben, dass ein solcher Fehler in gcc für mindestens 2 Hauptversionen bleiben würde." - Sie müssen neu hier sein –