समस्या
में डिफ़ॉल्ट तर्क segfaults के लिए खाली ब्रेस-initializers के साथ std :: नक्शा तर्क मुझे प्रयोक्ता की ओर एक बग रिपोर्ट पुस्तकालय में एक segfault मैं विकसित रिपोर्टिंग मिला है।जीसीसी
दोषपूर्ण कोड के न्यूनतम उदाहरण है:
#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();
}
जब जीसीसी के साथ संकलित (मैं 4.8.2 और 4.7.3 परीक्षण किया) इसे सही ढंग से 0
कंटेनर के आकार के रूप प्रिंट, लेकिन पाश अंदर segfaults (सभी पर क्रियान्वित नहीं किया जाना चाहिए जो जा सकती है)।
void f(std::map<std::string, std::string> m = std::map<std::string, std::string>{})
रूप में अच्छी तरह से काम करता है map
को कॉपी करना::
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";
}
}
const std::map<...>&
पैरामीटर बदलने
समाधान
हालांकि, मैं समस्या का घोषणा बदलकर ठीक कर सकते हैं यह भी काम करता है।
जीसीसी 4.9.1 ठीक काम करता है।
क्लैंग भी संकलित करता है और कोड को ठीक करता है।
(तब भी जब जीसीसी 4.8.2 में नाकाम रहने के रूप में एक ही libstdC++ का प्रयोग करके) कार्य करना उदाहरण: http://coliru.stacked-crooked.com/a/eb64a7053f542efd
प्रश्न
नक्शा निश्चित रूप से समारोह के अंदर वैध राज्य में नहीं है (विवरण bellow)। यह एक जीसीसी (या libstdC++) बग की तरह लग रहा है, लेकिन मुझे यकीन है कि मैं कुछ बेवकूफ गलती यहाँ नहीं बना रहा हूं होना चाहता हूँ। यह एक बग कम से कम 2 मुख्य संस्करण के लिए जीसीसी में रहना होता था पर विश्वास करना मुश्किल है।
तो मेरा सवाल यह है: क्या डिफ़ॉल्ट std::map
पैरामीटर गलत (और मेरे कोड में बग) शुरू करने का तरीका है या यह stdlibc++
(या gcc
) में एक बग है?
मैं कामकाज की तलाश नहीं कर रहा हूं (जैसा कि मुझे पता है कि कोड काम करने के लिए क्या करना है) एप्लिकेशन में एकीकृत होने पर, अपमानजनक कोड कुछ कंप्यूटरों पर ठीक निष्पादित करता है (यहां तक कि जब gcc 4.8.2 के साथ संकलित किया जाता है) कुछ नहीं करता है।
विवरण
मैं इसे का उपयोग कर संकलन:
gdb सेg++-4.8.2 -g -Wall -Wextra -pedantic -std=c++11 /tmp/c.cpp -o /tmp/t
पश्व-अनुरेखन:
#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/सी।सीपीपी:
AddressSanitizer: SEGV on unknown address 0xffffffffffffffe8
यह लगता है nullptr - 8
तरह
valgrind पता चलता है::
==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
मानचित्र की आंतरिक स्थिति को देखते हुए पता चलता है कि 9 std::cout << ...
आसन रिपोर्ट के साथ लाइन है कोड वास्तव में विफल होना है:
libstdc मेंरिटर्न
this->_M_impl._M_header._M_parent
का मूल्य से यह आंतरिक प्रतिनिधित्व, std::map::end()
रिटर्न है:
&this->_M_impl._M_header
gdb पता चलता है:
(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
तो begin()
और end()
का मूल्य ही नहीं हैं (begin()
nullptr है) खाली std::map
के लिए मानक द्वारा अनिवार्य है।
Fwiw, जब मैं << प्रतिस्थापित 'std :: अदालत << "-> s.first" << s.second << "\ n"; 'द्वारा std :: अदालत' << "यहाँ \ n" आया, ', कार्यक्रम एक बार लाइन को प्रिंट करता है और फिर लटकता है। –
"यह विश्वास करना मुश्किल है कि इस तरह की एक बग कम से कम 2 प्रमुख संस्करण के लिए जीसीसी में रहेगी।" - आपको यहां नया होना चाहिए –