enedil
ci dobrze pisze, ale bez wyjaśnien dla początkującego.
U mnie to wygląda tak:
$ clang++ -O1 -g -fsanitize=address buff.cpp -o buff -std=c++17
$ ./buff
=================================================================
==65295==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffee5906519 at pc 0x00010a357948 bp 0x7ffee59064b0 sp 0x7ffee5905c70
READ of size 30 at 0x7ffee5906519 thread T0
#0 0x10a357947 in wrap_strlen (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x17947)
#1 0x10a304c09 in std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::basic_string<std::nullptr_t>(char const*) string:819
#2 0x10a2fc8bb in readName(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) buff.cpp:155
#3 0x10a2faba3 in readCities(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&, std::__1::vector<City, std::__1::allocator<City> >&) buff.cpp:213
#4 0x10a2f9fab in main buff.cpp:57
#5 0x7fff7168bcc8 in start (libdyld.dylib:x86_64+0x1acc8)
Address 0x7ffee5906519 is located in stack of thread T0 at offset 57 in frame
#0 0x10a2fc64f in readName(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) buff.cpp:124
This frame has 4 object(s):
[32, 57) 'data' (line 131) <== Memory access at offset 57 overflows this variable
[96, 120) 'part' (line 133)
[160, 184) 'ref.tmp' (line 134)
[224, 248) 'test' (line 155)
Idąc po kolei wywołania #0
i #1
cię nie interesują, bo to jest standardowa biblioteka.
#2
kieruję cię na fukcję:
string readName(string & str)
{
if (str.size() < 10)
{
// "Pusty str"
return "";
}
char data[25];
string part = str.substr(0, str.find("\n"));
strncpy(data, part.substr(0, 24).c_str(), 24);
bool space = false;
for (int i = 0; i < 24; i++)
{
if (isspace(data[i]))
{
if (space == true)
{
data[i - 1] = '\0';
break;
}
space = true;
continue;
}
space = false;
}
string test = data; // to jest linia 155, gdzie błąd się manifestuje
return test;
}
Błąd mówi, że jest czytanie poza buforem, a w tym momencie odczytywany jest data
.
Przy konwersji char*
do std::string
, koniec napisu jest oznaczany wartością, zero. Jeśli jej brakuje, to nastąpi próba odczytania poza bufor.
Co to niby ma robić? Czemu tak to strasznie przekombinowałeś?
Te dane są proste do odczytania.
A twój kod się pewnie wykłada dlatego, że pierwsz kolumna tych danych ma więcej znaków niż 20.
Np Baranow (skierniewickie)
ma 24 znaki.
Swoją drogą, te dane są dziwne. Z jednej strony jest użyty UTF-8, bo tak zakodowany jest znak °
, a polskich znaków nie ma.