Amikor az optimalizáló teszi futtathatóvá a hibás kódot

Fórumok

Valami ehhez hasonlót írtam:

*(uint16_t *) (buff + 241) = get_crc(buff, 241);

buff 4-re align-olt uint8_t buffer, illetve get_crc() uint16_t-vel tér vissza. -O1-gyel fordítva a kód hibátlanul fut, míg -O0-val lefordul, de futásidőben exception-t dob. Ami persze érthető. Nyilván -O0 esetén a fordító bután lefordította a páratlan címre történő egy gépi ciklussal történő 16 bites írást. Csak ugye itt meglehet, hogy két gépi ciklus kell, először egy 32 bites duplaszónak a felső byte-jába kell írni a 16 bites számunk alsó byte-ját, majd utána a következő 32 bites duplaszó alsó byte-jába írjuk a 16 bites számunk felső byte-ját. Little endian MIPS architektúra. Az optimalizáló érti, mire gondoltam, de ha csak bután lefordítjuk, akkor bizony ez nyilván exception. A programozónak látnia kell a hardware-t, annak működését is, nem elég az, hogy amit leírtunk, az elméletileg jó. Azt valódi hardware hajtja végre.

Hozzászólások

Szerintem ebben nincs igazad, a forditonak a -O0 esetben is kellene mukodnie, ha -O1 esetben mukodo kodra is kepes. Forditoirok persze ilyenkor elokapjak valami 1000 oldalas doksi 800. oldalanak valamelyik sorat, ami epp az "undefined behaviour"-oket sorolja, es ramutatnak. Amugy ott a -S, ami megmutatja ASM-ben mit alkotott. Te jol ertesz hozza.

When you tear out a man's tongue, you are not proving him a liar, you're only telling the world that you fear what he might say. -George R.R. Martin

Egyértelműen unaligned access -t csinálsz, ekkor pedig implementation defined mi történik. A baj azzal van, hogy a kódon nem látszik mi imp.def. és mi nem, így könnyű elrontani. Esetleg egy -m strict-align jellegű kapcsoló vagy egy static analyzer segíthet.

Amúgy az optimizer nem érti mit akarsz, hanem véletlenül megjavította. Gondolom a transzformációk során van valahol egy unaligned access ellenőrzés amit aktiválódott. Nem fogadnék rá nagy tételben, hogy a következő compiler verzió is így fog működni erre az esetre.

De gondolom ezekkel tisztában vagy te is.

Hallod, ennél sokkal rosszabb, hogy a nem általam írt, hanem készen felhasznált USB CDC device driver régi fordítóval -O1-gyel fut, új fordítóval -O0-val fut, -O1-gyel meg mintha nem is létezne az USB interface. :( Maradtam a régi fordítónál.

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Jó lenne látni az Assembly kódot mindkét esetben; ennek talán az objdump -dS module.o a legegyszerűbb módja.

Mgen, ez sajnos ilyen, en is belefutottam mar hasonloba. Ott egyebkent az lett a megoldas hogy az ntohs(), htons() stb. "mintajara" csinaltam ilyesmiket hogy setns(), seths(), getns() meg geths() meg hasonlo. Es akkor az altalad most felhozott pelda ez lenne:

seths(buff+241, get_crc(buff, 241));

Es akkor egy alignment-biztos architekturan lehet akar ez is:

#define  seths(addr,value)    (*(uint16_t *)(addr))=(value)

Egyebkent meg megfelelo trukkokkel hordozhatora osszerakhato (akar memcpy, akar struct ideglenes hasznalataval egy fuggvennyel, akar bitshiftelessel). Barhogyis, akkor csak 1x kell ezt az egeszet megfelelo optimalizacioval vegigszopkodni, es akkor jo lesz :)

Ez is ilyen volt https://hup.hu/node/178120

ott is más paraméterrel buildelték a csomagot mint régen és elromlott. Mert ott is undefined viselkedésű kódok vannak benne.

Az UBSan-nak kene dobnia ra egy szep runtime misaligned address hibat.

GCC 5-tol mar biztosan van -fsanitize=undefined (bar erre -fsanitize=alignment is eleg lenne). Afaik MIPSel-en is megy az UBSan.