Skip to content

Instantly share code, notes, and snippets.

@geneotech
Last active December 8, 2018 16:33
Show Gist options
  • Save geneotech/fa5998de35c0d8b5b234cba8eb8b2659 to your computer and use it in GitHub Desktop.
Save geneotech/fa5998de35c0d8b5b234cba8eb8b2659 to your computer and use it in GitHub Desktop.
To pokazuje jak se można odstrzelić całą nogę w tym języku.
Miałem takiego buga, że jak do jednego pliku,
nazwijmy go crash.cpp - nie wrzuciłem jednego includa - to miałem crasha w serializacja.cpp.
Co ciekawe, funkcje z crash.cpp w ogóle nie były wykorzystywane podczas testowania.
Więc mam se w kodzie takie generalne templatki do serializacji, write_bytes oraz read_bytes,
które z dowolnego obiektu robią ci wektor bajtów i vice versa,
ale możesz dla swojego złożonego typu zdefiniować w global scopie własne funkcje 
zwane write_object_bytes/read_object_bytes.
Jeśli moja templatka wykryje je tam gdzie jest wywołana,
to te funkcje będą wywołane zamiast np. domyślnego memcpy dla PODów.
Mam sobie zwykły obiekt.h.
Obok jest obiekt.hpp,
a w środku moje własne implementacje write_object_bytes/read_object_bytes dla klasy obiekt.
obiekt.hpp z założenia includuję tylko w serializacja.cpp,
żeby nie wrzucać wszędzie indziej niepotrzebnego kodu.
Wróćmy do crash.cpp.
Wywołuję tam write_bytes na obiekt z pewnego trywialnego powodu.
Nie ma tam jednak wywołania do read_bytes.
I kurwa zapomniałem do crash.cpp wrzucić obiekt.hpp żeby się poprawnie zapisał do bajtów
moimi customowymi funkcjami.
Kod się jednak zbudował, bo domyślny behaviour mojego serializatora też będzie działać,
a już na pewno powinien działać bez crasha, w przeciwnym wypadku jest wywalany static_assert.
Rezultat?
W serializacja.cpp, poprawnie includuję obiekt.hpp i wywołuję write_bytes oraz read_bytes
z widocznymi w global scopie write_object_bytes/read_object_bytes.
ALE, wcześniejsza kompilacja pliku crash.cpp striggerowała instantiację write_bytes
BEZ customowego write_object_bytes w obiekt.hpp (bo zapomniałem go wrzucić).
Rezultat?
W serializacja.cpp, read_bytes dla obiekt skompilował się z customowym read_object_bytes,
podczas gdy write_bytes dla obiekt skompilował się z domyślnym zachowaniem,
mimo że w scopie był widoczny customowy writer,
tylko dlatego że wcześniej w crash.cpp został już zinstantiatyzowany bez niego.
To poskutkowało w asymetrycznym cyklu read/write w serializacja.cpp - i mamy crasha.
Rozwiązanie jest proste, trzeba po prostu wrzucić po ludzku do obiekt.h forward-deklaracje
dla write_object_bytes/read_object_bytes,
żeby każdy compilation unit który używa obiekt widział zawsze że ma on customowe i/o.
No ale zajebałem i tego nie zrobiłem.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment