2010-06-08:

Losowe przemyślenia (3)

random thoughts:easy
Kilka dni nic nie pisałem, a kilka losowych przemyśleń mi się uzbierało. Skorzystam więc z okazji i je zanotuje.

Komunikaty GCC, Yield() w winbase.h


To, że niektóre komunikaty gcc/g++ są nieprzejrzyste, nie jest dla nikogo zaskoczeniem. Niemniej jednak poruszę ten temat i na swoim blogu. Konkretnie, chodzi mi o ten oto komunikat:
error: invalid conversion from 'void (*)()' to 'void (*)()'
Co wiemy z powyższego komunikatu? Wiemy że chodzi o pointer na funkcje, i wiemy że zachodzi nieprawidłowa konwersja z typu 'void (*)()' na typ 'void (*)()'. Chwila... Że co? Przecież te typy są identyczne! Po lewej mamy 'void (*)()' i po prawej również mamy ten sam 'void (*)()'. Więc gdzie tu błąd?
Ano, oczywiście błąd jest w tym, czego kompilator już nie raczył napisać - czyli, że jest to pointer na funkcje typu __cdecl (patrz: konwencje wywołania (EN)), a sama funkcja była typu __stdcall, tak jak na poniższym listingu:
void __stdcall func(void) {}
void (*func_ptr)(void) = func;

Oczywiście rozwiązaniem tego problemu jest albo zmienienie typu pointera na __stdcall (będzie to wyglądać tak: "void (__stdcall *func_ptr)(void)"), albo zmienienie typu funkcji na __cdecl.
W żadnym wypadku natomiast nie jest rozwiązaniem przerzutowanie funkcji na typ __cdecl podczas przypisania. W przypadku funkcji bez argumentów co prawda nie spowoduje to nic groźnego, natomiast gdybyśmy mieli do czynienia z funkcją z przynajmniej jednym argumentem, doszłoby do "rozwalenia" struktury stosu - albo parametry byłyby usunięte dwa razy, albo ani razu, co oczywiście doprowadziłoby prędzej czy później do ślicznego segfaulta (food for thought: ciekawe czy można by z takiego błędu wyciągnąć code execution, w sprzyjających warunkach oczywiście).

Druga sprawa, którą chciałbym tutaj poruszyć, związana jest z pewnym frameworkiem którzy tworzę (napiszę o nim przy okazji ;>) - stworzyłem w nim pewną klasę, która miała metodą Yield():
9: class XYZ {
10:  bool Yield();
11: };

Ku mojemu zaskoczeniu, otrzymałem taką oto informacje od g++:
:10: error: declaration does not declare anything
Szczerze mówiąc, aż przetarłem oczy ze zdumienia i upewniłem się, że dobrze widzę (tj. jeszcze raz przeczytałem error message). Czyżbym nagle, w środku szału twórczego, zapomniał jak się deklaruje metody w klasie?
Na szczęście, przyczyna okazała się leżeć po stronie kodu (a raczej bibliotek), a nie mojej osoby - mianowicie w jednym z (pośrednio) includowanych przeze mnie plików nagłówkowych (a konkretniej w winbase.h) można znaleźć wpis (poniżej przedstawiony jest cały, kompletny, a zarazem pełny, wpis):
#define Yield()
Uh. Huh. Jak widać, ktoś z Microsoftu (bo taki oto wpis istnieje w ichnim Platform SDK) zadecydował, iż jeśli ktoś korzysta z WinAPI, to na pewno nie będzie chciał mieć nigdzie (w żadnym namespace, w żadnej klasie/strukturze/etc) funkcji/metody o nazwie Yield. Oczywiście przesadzam :)
Najwyraźniej kiedyś istniała (?) funkcja Yield(), która następnie została z jakiegoś powodu usunięta (ktoś się orientuje czemu? na MSDN nie mogę znaleźć wzmianki o tym), ale w celu zachowania wstecznej kompatybilności powstało powyższe makro (które każde wywołanie Yield() miało zamieniać na puste wyrażenie). Oczywiście, w C to rozwiązanie jest niezłe, ale w C++ (z uwagi na inne namespace'y/klasy/struktury w których można by zadeklarować takową funkcję) trochę komplikuje życie programistom (mi) którzy chcą nazwać funkcję/metodę Yield() (ponieważ preprocesor zamieni wpis w klasie z "bool Yield();" na "bool;", co oczywiście nic nie deklaruje, jak zresztą uruchamiany później kompilator słusznie zauważa).
Jak rozwiązać ten problem? Najprościej zmienić nazwę funkcji (np. YieldExecution). Można również napisać #undef Yield, ale z jakiegoś powodu to rozwiązanie mi się nie widzi (głównie dlatego że nie jestem w 100% pewien czy nic co będzie korzystać z mojego frameworku nigdy nie będzie musiało wywołać prawdziwego, nieistniejącego, Yield(); szczerze, to sądzę, że moje obawy są bezzasadne ;>).

StarCraft 2


Wczoraj wieczorem zakończyła się pierwsza część bety SC2, tak więc klepnę ze dwa zdania podsumowujące ową betę.
Więc tak, StarCraft 2 jest grą kapitalną i mogę z czystym sumieniem powiedzieć, że jest to lepsza gra od SC1 (a w SC1 grywałem prawie nieprzerwanie od wydania do wyjścia bety SC2). Z ciekawostek technicznych - GUI jest zrobione we "flashu" (a konkretniej pewna firma napisała implementacje VMki flasha pod DirectX'a, i to właśnie użyte jest w SC2), a sam SC2 jest bardzo znośnie zabezpieczony przed RE (łącznie z tym, że odpalone są dwa procesy, z którym jeden debuguje drugi, i jednocześnie implementuje pewne jego funkcje po swojej stronie, których wywołanie triggerowane jest exceptionami (pisałem coś o tego typu mechanizmach w Xploit nr. 3)).
Niemniej jednak po dwóch dniach od wypuszczenia bety (closed bety) osoby bez klucza mogły oglądać replay'e, a tydzień później grać na AI (stworzone przez scenę, sporo lepsze niż to które było użyte w samym niemodowanym SC2).
Potem w moje ręce wpadł klucz do bety, i mogłem w końcu nacieszyć się gierką, co skończyło się na top2 2v2 platinium (hi Nek ;>) i na diamentowej lidze 3v3, a wcześniej top1 3v3 platinium (z Nekiem i j00ru).
Jak pisałem, gra jest dobra, i jedyne co pozostaje robić, to czekać na drugą część bety i wydanie pełnej wersji :)

I tyle na dzisiaj :)

Poprzednie losowe przemyślenia:
Losowe przemyślenia (1)
Losowe przemyślenia (2)

Comments:

2010-06-09 10:37:56 = przemoc
{
Z tym GUI to ciekawa sprawa. Mnie np. uświadomił dopiero znajomy z branży growej gdzieś 3 miesiące temu. W rozmowie powiedział mi, że GUI we Flashu robią, co mnie mocno zdziwiło. Rozwiązanie zwie się Scaleform i większość współczesnych gier z tego korzysta. Przyspiesza to znacząco proces tworzenia graficznego interfejsu. Więcej info: http://en.wikipedia.org/wiki/Scaleform
}
2010-06-11 11:18:57 = Agares
{
Skoro to Yield() i tak jest zdefiniowane jako puste, to jakim cudem mógłbyś tego kiedyś w swoim projekcie używać?
}
2010-06-11 12:15:51 = Gynvael Coldwind
{
@przemoc
Thx za link, mi totalnie z głowy wypadła nazwa tego cuda :)

@Agares
A nuż kiedyś wróci do łask ? :))))
}
2010-06-15 09:17:51 = die
{
Widziales jak Twoj blog wyglada w IE 6? :D
}
2010-06-15 11:30:00 = Gynvael Coldwind
{
@die
Nope ;) Ale domyślam się ;>
}
2010-06-21 12:25:21 = Rolek
{
@Gyn
Drobne pytanie: Zamierzasz kontynuować ReverseCraft?
Jest to (była?) bardzo ciekawa seria :)
}
2010-06-21 19:26:45 = Gynvael Coldwind
{
@Rolek
Tak, zamierzam to na 100% kontynuować, ale prosiłbym jeszcze o chwilę cierpliwości :)
}
2010-06-22 08:55:46 = Rolek
{
@Gyn
No mam nadzieję :)
A mógłbyś mniej więcej określić kiedy spodziewać się następnego odcinka?
}

Add a comment:

Nick:
URL (optional):
Math captcha: 3 ∗ 6 + 3 =