[Játék] Találd meg a bug-ot!

Címkék
  1. Próbáld megfejteni a feladványt, most mutasd meg mit tudsz!
  2. Szándékosan van képként
  3. Próbálj meg tisztán játszani (Google Image Search stb. lúzerek pls.)!
  4. A feladvány a Google P0 egyik csapattagjától származik
  5. Pár nap múlva publikálásra kerül a forrás (URL)

🍿

Hozzászólások

Szerkesztve: 2025. 03. 06., cs – 11:11

printf("Element: %x\n", *element);
 

Így lenne jó: 
if (element != nullptr) {
    printf("Element: %x\n", *element);
} else {
    printf("Congratulations, you've found the borked index!\n");
}

A get_element_safe függvény az arr tömb egy elemére mutató pointert ad vissza, ha az index érvényes. Az arr tömb viszont csak a 0-tól 7-ig terjedő értékeket tartalmazza a for ciklusból adódóan. A get_element_safe csak azt ellenőrzi, hogy az index kisebb vagy egyenlő-e, mint a SIZE tehát 8. A >= miatt 8 is átmegy itt. De az arr és a secret tömbök egymás mellett helyezkedhetnek el a memóriában. Ha egy érvényes 0–7 közötti indexet adsz meg, akkor minden rendben van. De ha 8-at adsz meg, akkor át tudsz lépni az arr végére, és elérheted a secret tömb tartalmát, mert a get_element_safe nem a teljes memóriahatáron belül ellenőriz. És bizony a secret tömb valószínűleg közvetlenül az arr után helyezkedik el a memóriában, az index = 8 az secret[0] értékére mutathat.

Igen, de hiába ad vissza nullptr-t ha ezt nem ellenőrzik, akkor egy nullptr dereferálása történik, ami szegmenshibát (segmentation fault) okoz.

(*kisebbet elírtam mert nagyobb, de utána már jól írom jelekkel. Lényeg, hogy a 8 átmegy és az pont a secret elejére mutat) 

Lényeg, hogy a 8 átmegy és az pont a secret elejére mutat

De nem megy át :) (a 8-ból is nillptr lesz). Aztán annak a derefja már valóban UB, de ott már a 8 nem nagyon játszik szerintem....

 

Szerk: ah, "megfelelő" optimalizálás esetén simán kidobja a check-et (az UB miatt) és "átmegy" a 7 fölötti is :)

Most nincs kedvem bepotyogni hogy kiprobaljam hogy tenyleg bekovetkezik-e, de a pointer dereferalas printf parametereben az UB ha nullptr, vagyis az optimizer felteheti hogy nem kovetkezik be es kioptimalizalhatja az index checket a get_element_safe fv-bol. Lasd: https://blog.llvm.org/2011/05/what-every-c-programmer-should-know_14.ht…

Tehat szerintem 8-ra siman ki fogja adni a secret tomb 0. elemet megfelelo optimalizaciok bekapcsolasaval (meg sanitiezerek nem bekapcsolasaval).

I hate myself, because I'm not open-source.

de a pointer dereferalas printf parametereben az UB ha nullptr, vagyis az optimizer felteheti hogy nem kovetkezik be es kioptimalizalhatja az index checket

Ajjajjajj, ez tényleg? Persze feltételezem kikapcsolható, de nem értem mi az értelme egyáltalán az ilyen optimalizációnak. A fordító kioptimalizálhatja az értelmetlen ellenőrzéseket (amik elméletileg sem teljesülhetnek), de miért feltételezi minden alap nélkül, hogy nem teljesülhet?

Mert onnan kezdve hogy UB van, a compiler barmit is megtehet, mert a C/C++ szabvany nem mond semmit arrol hogy minek kene tortennie. Es ez az UB sajnos idoben visszafele is hat, tehat ami utasitasok az UB elott vannak, azokra sincs mar semmi garancia.

I hate myself, because I'm not open-source.

Ez tele van bugokkal, de a legnagyobb rohadt nagy bug, hogy mi a francért keveri a C++ kódot a C-vel??

C++-ban FILE típus? C++-ban C típusú tömb, std::vector helyett? printf meg stream-ek keverése...

Pont az ilyen gyökér keveredések miatt annyira népszerűtlen a C++.

Ezen kívül:

* nincs ellenőrizve a fájl megnyitása,

* nincs ellenőrizve a fread által olvasott elemek száma. Meg amúgy is szebb is lenne sizeof(uint32) és count=SIZE2-vel meghívni.

* nullptr-t nem kellene átadni a printf-nek. Amúgy is mi a tököm miatt ad át címként egy uint32-t (már ha nem akar beleírni).

félig laikusként a sizeof jól kezeli ezt unsigned int32 -t?

#include <stdio.h>
#include <iostream>

Ennél tovább nem szükséges olvasni, a kód úgy, ahogy van, a kukába való.

Szerkesztve: 2025. 03. 06., cs – 14:29

if (index >= (SIZE + SIZE2))...

8,9... től jön a secret

...ja, hogy nem a secret a goal, hanem a bug :) 

akkor if (index >= SIZE || index < 0) bár unsigned miatt mind1... passz

Szerkesztve: 2025. 03. 06., cs – 14:23

A kiírás hibás.

A main függvény lokális vermébe kerül X címre az arr, majd X - 32 címre a secret, így nyilván arról van szó, hogy a get_element_safe() függvényben kell túlcsordulást előidézni a "return arr + index" sorban, méghozzá az is biztos, hogy egy fordítóbug kihasználásával (a hiba nem szemantikai, hanem fordítóbeli).

Csakhogy, ennek megválaszolásához tudni kéne, hogy mennyi a sizeof(uintptr_t), azaz hogy 16, 32 vagy 64 bitesre fordítunk-e. Ennek ismerete nélkül nem is adható helyes válasz, tehát hibás - konrétan hiányos - a feladat kiírása.
ps: Ezen kívül a printf valóban UD-t eredményez bármilyen index >= 8 bemeneti értékre, és valóban eleve balfasz, aki így keveri a C-t és C++-t, de pláne a FILE-t a streamekkel. Gyanítom, ez triggereli a fordítóbugot az inlineolás kódgeneráló részében; és stream helyett fgets+atoi és sima C fordítóval valószínűleg eleve nem is jönne elő.

De mégegyszer, ez nem szemantikai, hanem fordítóbeli bug, tehát ismerni kéne a pontos fordítót, a célarchitektúrát, a címbusz méretét, de mivel inline-ról van szó, még a fordítónak átadott optimalizációs kapcsolók sem mindegyek!

clang és az inlineolt boundscheck esete

Szerkesztve: 2025. 03. 06., cs – 16:06

Ha jól látom csak a számsorral feltöltött arr-ból olvas a megadott indexnél nem pedig a secret-ből amit ki kéne "csorgasson". A printf feletti sor.

(A SIZE2-vel kéne ellenőrizni az indexet, de mivel ugyanannyi mindkettő, most mindegy.

Szerencsétlen, hogy ugyanaz a neve a függvényparaméternek meg az egyik tömbnek.

nullptr nekem új, de c++-os dolog szóval nem kéne, meg nem kéne keverni a dolgokat. )