Problema
ho ricevuto una segnalazione di bug da utente segnala un segfault in libreria io sviluppo.std :: map discussione con vuoti brace-inizializzatori per segfaults argomento di default in GCC
L'esempio minima del codice difettoso è:
#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();
}
Quando viene compilato con GCC (I testato 4.8.2 e 4.7.3) la stampa sia corretta 0
la dimensione del contenitore, ma segfaults all'interno del loop (che non dovrebbe essere eseguito affatto).
Soluzioni alternative
Tuttavia, posso risolvere il problema cambiando la dichiarazione:
void f(std::map<std::string, std::string> m = std::map<std::string, std::string>{})
Copia dei map
opere così:
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";
}
}
Cambiando il parametro da const std::map<...>&
funziona anche
GCC 4.9.1 funziona correttamente.
Clang compila anche ed esegue il codice bene. (Anche quando si utilizza lo stesso libstdC++ in quanto non gcc 4.8.2)
lavoro esempio: http://coliru.stacked-crooked.com/a/eb64a7053f542efd
Domanda
La mappa non è decisamente in stato valido all'interno della funzione (dettagli sotto). Sembra un bug GCC (o libstdC++), ma voglio essere sicuro di non fare un errore stupido qui. È difficile credere che un tale errore rimanga in gcc per almeno 2 versioni principali.
Quindi la mia domanda è: E 'il modo di inizializzazione di default std::map
parametro sbagliato (e bug nel mio codice) o è un bug in stdlibc++
(o gcc
)?
Non sto cercando soluzioni alternative (come so cosa fare per far funzionare il codice) Quando integrato nell'applicazione, il codice incriminato viene eseguito correttamente su alcuni computer (anche se compilato con gcc 4.8.2) su alcuni no.
dettagli
compilo usando:
g++-4.8.2 -g -Wall -Wextra -pedantic -std=c++11 /tmp/c.cpp -o /tmp/t
Backtrace da 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.cpp: 9 è la linea con std::cout << ...
rapporti Asan:
AddressSanitizer: SEGV on unknown address 0xffffffffffffffe8
Questo mi sembra nullptr - 8
valgrind mostra:
==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
Guardando stato interno della mappa mostra che la il codice deve fallire davvero:
std::map::begin()
in libstdC++ restituisce valore
this->_M_impl._M_header._M_parent
dalla sua rappresentazione interna, std::map::end()
rendimenti:
&this->_M_impl._M_header
gdb mostra:
(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
Così valore della begin()
e end()
non sono la stessa (begin()
è nullptr) come richiesto dallo standard per lo std::map
vuoto.
FWIW, Quando ho sostituito 'std :: cout << s.first << "->" << s.second << "\ n"; 'da' std :: cout << "Came here \ n"; ', il programma stampa la riga una volta e poi si blocca. –
"È difficile credere che un tale errore rimanga in gcc per almeno 2 versioni principali." - Devi essere nuovo qui –