Gra się crashuje przy zapisywaniu zaraz po tym:
System message from server: Serializing game info...
Gra się crashuje przy zapisywaniu zaraz po tym:
System message from server: Serializing game info...
Czy to odtwarzalne? Czy zachodzi na wszystkich mapach?
Spróbuj zdebugować sewer, bo wpis w logu jest mało pomocny (serializacja informacji o grze, to dość sporo pracy).
Tak zachodzi na każdej mapie, a co do debugowania, to za bardzo nie wiem jak się za to wziąć, attach to PID nie bardzo działa, frezuje całą aplikacje, a z miejsca tego nie zrobię bo serwer jest przecież uruchamiany z poziomu klienta.
Podczas kompilacji GeniusAI
/usr/lib/gcc/i486-linux-gnu/4.3.3/../../../../lib/crt1.o: In function `_start':
/build/buildd/glibc-2.9/csu/../sysdeps/i386/elf/start.S:115: undefined reference to `main'
collect2: ld returned 1 exit status
nie wiem czy tu mój błąd czy z coś innego.
Wydaje mi się że nie kompilujesz tego jako lib.
===
Co jak co ale debbugera to ja obsługiwać nie potrafię Tutaj log z crasha przy zapisie gry:
E:\Install\Heroes3>gdb.exe VCMI_server.exe 1280
GNU gdb 6.3
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i686-pc-mingw32"...
Attaching to program `E:\Install\Heroes3/VCMI_server.exe', process 1280
[Switching to thread 1280.0x560]
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
[Switching to thread 1280.0x224]
0x00486c38 in std::string::length () at iostream:77
77 static ios_base::Init __ioinit;
(gdb) bt
#0 0x00486c38 in std::string::length () at iostream:77
#1 0x00455aef in COSer<CSaveFile>::saveSerializable (this=0x162f87c,
data=@0xd990f4) at Connection.h:275
#2 0x0044298c in SaveSerializable<CSaveFile, std::string>::invoke (
s=@0x162f87c, data=@0xd990f4) at Connection.h:69
#3 0x00459122 in COSer<CSaveFile>::save<std::string> (this=0x162f87c,
data=@0xd990f4) at Connection.h:240
#4 0x0045c296 in COSer<CSaveFile>::operator<< <std::string> (this=0x162f87c,
t=@0xd990f4) at Connection.h:185
#5 0x0045a4a2 in COSer<CSaveFile>::operator&<std::string> (this=0x162f87c,
t=@0xd990f4) at Connection.h:192
#6 0x004369dd in PlayerInfo::serialize<COSer<CSaveFile> > (this=0xd990d4,
h=@0x162f87c, version=63) at map.h:129
#7 0x00455de0 in COSer<CSaveFile>::saveSerializable<PlayerInfo> (
this=0x162f87c, data=@0xd990d4) at Connection.h:245
#8 0x00442388 in SaveSerializable<CSaveFile, PlayerInfo>::invoke (
s=@0x162f87c, data=@0xd990d4) at Connection.h:69
#9 0x004581f2 in COSer<CSaveFile>::save<PlayerInfo> (this=0x162f87c,
data=@0xd990d4) at Connection.h:240
#10 0x0045ae56 in COSer<CSaveFile>::operator<< <PlayerInfo> (this=0x162f87c,
t=@0xd990d4) at Connection.h:185
#11 0x00455db0 in COSer<CSaveFile>::saveSerializable<PlayerInfo> (
this=0x162f87c, data=@0xd141f4) at Connection.h:253
---Type <return> to continue, or q <return> to quit---
#12 0x00442d28 in SaveSerializable<CSaveFile, std::vector<PlayerInfo, std::alloc
ator<PlayerInfo> > >::invoke (s=@0x162f87c, data=@0xd141f4) at Connection.h:69
#13 0x004595c6 in COSer<CSaveFile>::save<std::vector<PlayerInfo, std::allocator<
PlayerInfo> > > (this=0x162f87c, data=@0xd141f4) at Connection.h:240
#14 0x0045c8c6 in COSer<CSaveFile>::operator<< <std::vector<PlayerInfo, std::all
ocator<PlayerInfo> > > (this=0x162f87c, t=@0xd141f4) at Connection.h:185
#15 0x0045a802 in COSer<CSaveFile>::operator&<std::vector<PlayerInfo, std::alloc
ator<PlayerInfo> > > (this=0x162f87c, t=@0xd141f4) at Connection.h:192
#16 0x00435e61 in CMapHeader::serialize<COSer<CSaveFile> > (this=0xd14198,
h=@0x162f87c, Version=63) at map.h:226
#17 0x00455ca8 in COSer<CSaveFile>::saveSerializable<CMapHeader> (
this=0x162f87c, data=@0xd14198) at Connection.h:245
#18 0x00442350 in SaveSerializable<CSaveFile, CMapHeader>::invoke (
s=@0x162f87c, data=@0xd14198) at Connection.h:69
#19 0x00458186 in COSer<CSaveFile>::save<CMapHeader> (this=0x162f87c,
data=@0xd14198) at Connection.h:240
#20 0x0045adc6 in COSer<CSaveFile>::operator<< <CMapHeader> (this=0x162f87c,
t=@0xd14198) at Connection.h:185
#21 0x0040dbdd in CGameHandler::handleConnection (this=0x22fb54, players=
{_M_t = {_M_impl = {<std::allocator<std::_Rb_tree_node<int> >> = {<__g
nu_cxx::new_allocator<std::_Rb_tree_node<int> >> = {<No data fields>}, <No data
fields>}, _M_key_compare = {<> = {<No data fields>}, <No data fields>}, _M_heade
r = {_M_color = 14095560, _M_parent = 0xd91e80, _M_left = 0x0, _M_right = 0x7c91
---Type <return> to continue, or q <return> to quit---
0098}, _M_node_count = 2009244481}}}, c=@0xd714c8) at CGameHandler.cpp:460
#22 0x00483091 in boost::_mfi::mf2<void, CGameHandler, std::set<int, std::less<i
nt>, std::allocator<int> >, CConnection&>::operator() (this=0x24b050,
p=0x22fb54, a1=
{_M_t = {_M_impl = {<std::allocator<std::_Rb_tree_node<int> >> = {<__g
nu_cxx::new_allocator<std::_Rb_tree_node<int> >> = {<No data fields>}, <No data
fields>}, _M_key_compare = {<> = {<No data fields>}, <No data fields>}, _M_heade
r = {_M_color = 14095560, _M_parent = 0xd87748, _M_left = 0xd91e80, _M_right = 0
xd714c8}, _M_node_count = 2292564}}}, a2=@0xd714c8) at mem_fn_template.hpp:274
#23 0x00461e8c in boost::_bi::list3<boost::_bi::value<CGameHandler*>, boost::_bi
::value<std::set<int, std::less<int>, std::allocator<int> > >, boost::reference_
wrapper<CConnection> >::operator()<boost::_mfi::mf2<void, CGameHandler, std::set
<int, std::less<int>, std::allocator<int> >, CConnection&>, boost::_bi::list0>
(this=0x24b058, f=@0x24b050, a=@0x162ff0f) at bind.hpp:371
#24 0x00462d1d in boost::_bi::bind_t<void, boost::_mfi::mf2<void, CGameHandler,
std::set<int, std::less<int>, std::allocator<int> >, CConnection&>, boost::_bi::
list3<boost::_bi::value<CGameHandler*>, boost::_bi::value<std::set<int, std::les
s<int>, std::allocator<int> > >, boost::reference_wrapper<CConnection> > >::oper
ator() (this=0x24b050) at bind_template.hpp:20
#25 0x0046e294 in boost::detail::thread_data<boost::_bi::bind_t<void, boost::_mf
i::mf2<void, CGameHandler, std::set<int, std::less<int>, std::allocator<int> >,
CConnection&>, boost::_bi::list3<boost::_bi::value<CGameHandler*>, boost::_bi::v
alue<std::set<int, std::less<int>, std::allocator<int> > >, boost::reference_wra
Cannot access memory at address 0x1630000
Jesteś wielki a mi wróciła wiara w to, że jednak potrafię kompilować wystarczyło dodać -shared. Zaraz przetestuję i zobaczę
dikamilo, nie mam pojęcia czemu to wywołanie length() na stringu sypie. Gdyby to jeszcze był string pod jakimś wskaźnikiem, to by można spekulować, czy jest on poprawny, ale tak… wskaźnik będący normalnym polem klasy nie powinien robić problemów, zwłaszcza jeśli kilka poprzednich pól się zserializowało, więc okoliczna pamięc jest dostępna.
Problem może być z runtimem (runtime libraries - biblioteki uruchomieniowe). Nie wiem jak jest to zorganizowane w MinGW-ie, ale Visual posiada kilka wariantów runtime’u i wybiera się odpowiedni. Są bodajże wersje statycznie włączane do aplikacji jedno- i wielowątkowych oraz wersja w osobnej dll-ce. VCMI musi mieć runtime w dll-ce. W innym wypadku dochodzi do błędów, ponieważ zarówno do liba jak i klienta włączany jest runtime i otrzymujemy dwa runtime’y niekompatybilne ze sobą (dwie osobne sterty, nieprzenośne wskaźniki itp).
Przyjrzałbym się, jak to wygląda w MinGW-u.
EDIT:
Problem można by w sumie obejść jeszcze inaczej - pozbyć się liba jako autonomicznej części. Można by go albo ręcznie wepchać do klienta i serwera (po prostu modyfikując ich projekty, dodając pliki z liba), albo zbudować jako bibliotekę statyczną i ją potem włączać (chyba też zadziała?).
O ile to jest faktycznie problem z runtimem.
Pobawiłem się trochę debuggerem, ogólnie to sypie się przy serializowaniu zmiennej mainHeroName z PlayerInfo, w trakcie debugger pokazuje taką zawartość:
(gdb) display mainHeroName
1: this->mainHeroName = {static npos = 4294967295,
_M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<
No data fields>}, <No data fields>}, _M_p = 0xd8ae0c ""}}
Próbowałem zmienić w locie zawartość tej zmiennej to wyskakuje takie coś:
(gdb) set mainHeroName="oko"
Invalid cast.
Można natomiast zmienić na jakąś liczbę, ale przecież ta zmienna jest stringiem ? Ogólnie to problem z tą zmienną był chyba również przy błędach z mapami.
Ja tam będę obstawał, że to może być problem z runtimem, albo coś innego, niekonwencjonalnego.
Ten string jest w 3 miejscach używany. Gdy powstaje, przy wyborze mapy (MapSel::select - sprawdzamy jego długość i ew. kopiujemy do ustawień gracz) i w serializacji.
Jeżeli podczas wyboru mapy wywołanie length() na tym stringu nie powodowało problemów i potem nie był on ruszany, to w żaden konwencjonalny sposób nie miał prawa się popsuć i sypać później, przy serializacji. Albo runtime psuje, albo jest przez coś nadpisywany - ale w to drugie nie bardzo wierzę, jeste nad nim kilka raczej niegroźnych pól.
Co prawda po stronie serwera wyboru mapy i nie ma i ten string nie jest w ogóle ruszany, ale powstaje wskutek identycznej procedury, więc nie ma możliwości, by był inny.
Co do zawartości stringa wg debuggera, to generalnie dlatego nie lubię gdb, że nie bardzo wiadomo co jest w kontenerach STL-owskich w tych jego podglądach.
Czy to _M_p = 0xd8ae0c “” oznacza, że pod adresem 0xd8ae0c jest NULL (to by wskazywało na pusty string, rozsądnie zakładając, że _M_p to wskaźnik na początek tekstu). No ale nawet pusty string nie ma prawa sypać (length() powinien wtedy grzecznie zwrócić 0).
Teza o runtime tym bardziej uzasadniona, że przy crashu jeszcze są jakieś awantury o "static ios_base::Init __ioinit; ". Choć na moje oko, to w takim układzie toto powinno sypać inaczej…
Choć do końca nic nie potrafię tu powiedzieć…
Dziwne problemy.
Może sam powinienem w wolnej chwili zacisnąć zęby i spróbować skompilować VCMI MinGW-em…
Nie, to nie takie proste. Problem jest takie, że w C/C++ nie masz takiego typu jak string. std::string jest tak naprawdę klasą opakowującą wskaźnik na ciąg bajtów (znaków), długość i jakieś inne wewnętrzne sprawy implementacji. (debugger zresztą Ci wyświetla z czego tak naprawdę ten string się składa)
Z poziomu debuggera nie da się do czegoś takiego łatwo przypisać innej wartości.
EDIT:
A tak z ciekawości - jeśli byś wykomentował serializację tych imion (map.h l.130) bohaterów, to co się stanie? Jakiś inny string sypnie, czy przejdzie?
Po wywaleniu mainHeroName z (template void serialize(Handler &h, const int version)) : 127, nie wywala żadnego błędu, gra się zapisuje i nawet poprawnie ładuje.
Co do rutime’a mam ustawione standardowo na dynamic (DLL), przy zmianie na static sypało błędami, nie odnajdowało referencji do funkcji, myślę że dużo by trzeba było zmieniać w kodzie aby to zadziałało tak jak pisałeś w poprzednim poście.
Ma być właśnie na dynamic dll. Czyli dobrze jest, mój trop był błędny.
Cóż, skoro zakomentowanie serializacji tamtego stringu cudownie naprawiło sytuację, to możesz go sobie trzymać zakomentowany. Tak naprawdę nie jest on jeszcze nigdzie wykrozystywany - to imię głównego bohatera, które powinno być (nie jest) wyświetlane w oknie zaawansowanych opcji w pregamie.
Ale nadal nie mam pojęcia, dlaczego to sypało. Ktoś ma jakiś pomysł?
ja mam!
problem z wartością wskaźnika (string jest wskaźnikiem (char*) )
źle ustawiony wskaźnik powoduje niedozwoloną operację w length, z powodu zabezpieczeń pamięci w linuksie (brak sprawdzania warunków krytycznych), gdb sprawdza co i jak i zamiast się sypnąć daje NULLa (nie widzi nic sensownego)
błędy mogą wystąpić przez złę ustawienie wskaźnika, ustawienie w runtime wartości do (const (char )) (a może to było ((const char)) ?) niezgodność typów wskaźnikowych (np. podstawienie zvoidowanego wskaźnika nie do stringu lub przypisanie stałej liczby do wskaźnika) lub problem z samym length (sypie na static cośtam, zmienne wewnętrzne źle się ustawiają (zwłaszcza wskaźniki brrrrrr! - ten sam problem co wyżej) )
również problemem może być zapis do pamięci read-only, przypisanie danych do zawartości wskaźnika NULL zwróconego przez funkcję zarządzania pamięci (np. alloc), wyjście poza dozwolony zakres pamięci (pamięć bez praw do czytania przez proces)
proponuje update bibliotek (zwłaszcza tych domyślnych wraz z kompilatorem) i sprawdzenie czy dalej się sypie
ewentualnie w kodzie możesz wstawić globalny (char ) z wstawionym stringiem np “test string” i za pomocą gdb przypisać wątpliwemu wskaźnikowi (char) wstawić wartość tego globalnego wskaźnika (równe wskaźniki pokazują na to samo, co nie?)
W bardzo, bardzo dużym przybliżeniu. To jest klasa i ma jeszcze zazwyczej kilka innych pól oprócz tego wskaźnika.
Windowsy też sprawdzają pamięć a na nich nie sypie. Poza tym skoro gdb może odczytać wskaźnik, to prawdopodobnie length też powinno móc (gdy gdb nie może się dostać do pamięci, to daje “Cannot access memory at address”, a nie udaje, że tam jest NULL).
Jakie const char * i co to za nawiasy? Jaka niezgodność typów? Jakie zmienne wewnętrzne? Możesz składniej i bardziej po polsku, bo to mi wygląda na bełkot?
Wymieniasz wszystkie możliwe przyczyny sypania się programu, jakie znasz? My też je znamy, i jeszcze trochę innych. Lepiej napisz, co to na pewno nie jest, bardziej pomoże (bo na napisanie przez ciebie co to na pewno jest nie liczę).
Wiem, że nie zawsze można ufać bibliotekom standardowym, szczególnie z projrktów otwartych, ale bez przesady. Tego typu błędy w stringach są praktycznie wykluczone, kiedyś możnaby myśleć, że nie zrobili zabezpieczeń dla jednoczesnego korzystania ze stringa przez wiele wątków, ale na moje oko ani to ten przypadek, ani te czasy.
Dobra, a skąd wiesz że to nie psuje kompletnie stringa i nic z nim nie da się robić za pomocą zaimplementowanych metod? Nie wydaje mi się, żeby to mogło do czegokolwiek prowadzić.
Moim zdaniem bardziej interesujące jest, czemu wierzchołek stosu jest taki jaki jest (0x00486c38 in std::string::length () at iostream:77), iostream:77 ma niewiele wspólnego z std::string::length ().
hey guys!
i also tried to compile vcmi on linux and after initial fail i tried to search for others who strive for this goal.
so after skimming through a google translate of the thread there seems to be some achievements in this regard.
could you in short summarize the steps i have to take to make it initially compile for now? it seems the issues mentioned here are not yet in svn?
after a successful compile i can do some gdb debugging.
and sorry for intruding into your polish section - i thought that maybe this issue gets more attention when it is discussed in english
no… iostream…
wygląda że serializacja poprzez klasę iostream pada (string ma operatory << i >> dla iostream)
jeśli mówiliście o stringu to fakt moja pomyłka std::string i (char *) to zupełnie co innego, ale oba nazywa się stringiem
@nawiasy, niezgodność typów
nawiasy przy typie wskaźnikowym i przy const, określają czy wskaźnik jest const, czy to na co wskazuje, co do niezgodności typów, chodziło mi głównie o rzutowanie consta na nie-consta a potem edycję
@windows nie sypie, błędy pamięci
windows jest niechlujny, pozwala nawet na injekcję kodu do innego procesu na niskim poziomie przy swojej minimalnej ochronie pamięci i nawet ostrzeżenia nie daje
linux ma zaawansowany menedżer pamięci w jądrze, każdy proces ma pewien stopień wirtualizacji i linux nie tylko stricte chroni pamięć, ale nawet adresy mogą być nieprzenośne między procesami. wykonywanie kodu też jest zwirtualizowane - np. nie powala wykonać instrukcji niskopoziomowego i/o na portach poza modułami jądra
***jest jescze trzecia opcja: ktoś zaimplementował jakąś niechlujną sztuczkę w zarządzaniu pamięcią, która jest dozwolona (jak wszystko) w windowsie, a w linuksie nawet nie wymyślono na nią obsługi błędów, jednak jest niedozwolona
@biblioteki std
kolega mógł mieć przestarzałą wersję (1997 rok ? ) lub miał wersję beta/alfa i niedziała mu dobrze, ew. zamiaststable ściągnął starą betę, więc każdą z tych opcji trzeba wykluczyć
poza tym dość często (za często) biblioteki standardowe nie są zgodne z dodatkowymi, niektórzy zakomentowywują sprawiające problem linie w nagłówkach (np. jakąś dziwną deklarację) na czas kompilacji, co może mieć nieprzewidziane skutki (np. błędy runtime), lepiej jest więc jest zmienić wersję na choćby starszą lecz zgodną
***to najbardziej wygląda na problem z pamięcią, a C i C++ jest tak zrobiony (tak pomyślany), że praktycznie się nie robi obsługi sytuacji wyjątkowych bez dokładnej obsługi przez programistę, co ma skutkować (i skutkuje) dużo lepszą wydajnością
najbardziej znany problem to niebadanie rozmiarów tablicy
At least some of issues mentioned here have been uploaded into svn. I think you should download latest sources and try to overcome problems alone or wait until we upload files necessary for automatic build. The only advice I can give you is that runtime libraries should be set to dynamic (DLL).
Przyglądnij się temu a nie wypisuj głupoty, string jest serializowany przez c_str a to nigdy nie korzysta z iostream (bo i po co?).
Skąd ty wziąłeś takie odróżnianie wskaźników do stałych od stałych wskaźników? Wszystkie źródła które widziałem podają, że używa się const char * w pierwszym przypadku i char * const w drugim. Twoje też wygląda mi na możliwe, ale mimo wszystko jestem ciekaw.
W przypadku funkcji w pamięci dzielonej między procesorami nie widzę z tym problemu. A mógłbyś mi napisać jak zrobić program piszący do pamieci innego programu, bo jakoś nie spotkałem się z taką możliwością? Najchętniej zobaczyłbym kod.
A teraz mi wyjaśnij co to ma wspólnego z naszym błędem.
Mógłbyś podać przykład takiej biblioteki dodatkowej? Nie słyszałem o takich. Kolejny strzał na ślepo?
Testowałem to na 4 rożnych wersjach mingw, tej dołączonej do C:B, osobnej z oficjalnej strony, mingw-tdm wersja beta 4.3.3/4.3.2, oraz samego 4.3.2 z tej paczki. Na każdym jest ten sam błąd.
nie chciałem łamać cytatu więc dodałem odpowiedzi w znacznikach code
mam na myśli wysyłanie na strumień, jeśli to nie zwykły (iostream << string) to może być (fstream << string) bo fstream dziedziczy po iostream (ifstream i ofstream jeśli się nie mylę dziedziczą po fstream lub na odwrót), prawie każda strumieniowa klasa dziedziczy po iostream (wykorzystanie składanych operatorów strumieniowych << i >>)
Czemu tu nie widzę “tak, masz rację, nie spojrzałem w kod VCMI”?
@dll injection
Jak widzę, nie potrafisz mi podać interesującej mnie informacji - jak to przebiega technicznie, konkretny kod. Jestem zbyt leniwy żeby się przebijać przez to do czego dałeś mi linki. Ciężko mi uwierzyć, że Windows jest taki be a Linux taki super. Poszukałem jednak pewnych materiałów sam i odkryłem, że istotnie można pisać do pamięci innego procesu jeśli nasz proces ma pewne przywileje (PROCESS_VM_OPERATION i PROCESS_VM_WRITE). Oczywiście jest pewien wyjątek, Vista oferuje wsparcie dla chronionych procesów dla których dostęp do ich pamieci z zewnątrz jest niemożliwy (nawiasem mówiąc, zostało to zaimplementowane z myślą o DRM, ale zdaje się być stosowalne do innych aplikacji). Możesz o tym poczytać np. tu: msdn.microsoft.com/en-us/library/ms684880(VS.85.aspx . A dostałbym linka do podobnego artykułu w kontekście Linuxa?
jeśli program robi coś podejrzanego linux może przeszkodzić, a windowsa to nieobchodzi
Jaki program ma robić coś podejrzanego?
could you in short summarize the steps i have to take to make it initially compile for now? it seems the issues mentioned here are not yet in svn?
Latest code from trunk should compile without problems.
The problem may be in the lack of up-to-date makefiles (codeblocks projects are AFAIK good, you may also (if possible) import project files from MSVC).
Maybe skoruppa will share his makefiles if he has finally successfully compiled all parts of AI.
VCMI should be basically working, the only remaining issue is problem with save/load options.
Btw it would be probably best if you create a separate thread on English forums.
majaczek, pytałem o pomysły, co może powodować tamten błąd, Ty zaś chyba postanowiłeś wypisać wszystko co wiesz o programowaniu, nie przeczytawszy nawet o co właściwie chodziło (std::string był ewidentnie wskazany). Część to truizmy nie na temat, część to już jakieś ich pomieszanie. Nie mam czasu tego rozplątywać.
Jedna tylko uwaga odnośnie dyskusji Linux a Windows - jest ona kompletnie niedotycząca tematu, ponieważ błąd zachodzi zarówno pod Windowsem jak i Linuksem. To nie kwestia systemu!
nie chciałem łamać cytatu więc dodałem odpowiedzi w znacznikach code
Obok przycisku “quote” na lewo masz taki mniejszy - on Ci cytuje zaznaczony fragment posta (wrzuca do okienka szybkiej odpowiedzi). Nie potrzeba się mordować z półśrodkami.
Skąd ty wziąłeś takie odróżnianie wskaźników do stałych od stałych wskaźników? Wszystkie źródła które widziałem podają, że używa się const char * w pierwszym przypadku i char * const w drugim.
Nie wiem czy on jest poprawny… mocno wątpię. (Możesz pokazać działający kawałek kodu C++ z użyciem skłądni const (char*)?) Nawet gdyby działało, to nie wierzę, by ktokolwiek zdrowy na umyśle chciał go stosować (chyba, że w celu zaciemnienia kodu).
Hosting provided by DigitalOcean