Portál AbcLinuxu, 30. dubna 2025 21:23
UPDATE: Vyřešeno
Tři hodiny po odeslání bug reportu do gcc bugzilly problém vyřešen jedním z vývojářů. Jelikož tomu nerozumím až tak dobře, tak v zájmu nešíření FUDu napíšu pouze odkaz s řešením.
Pojďte se mnou na lov. Co nás čeká? Spousta nebezpečí, temná zákoutí kódu a hmyzáci všude okolo.
Pomozte mi najít chybu v kombinaci GCC 4.x a Verse.
Q: O co jde?
A: Scháním někoho, kdo by mi pomohl otestovat zda bug #8959 je bugem GCC nebo verse a případně i s popisem problému. Update: Už jsem to reportoval do gcc bugzilly, mrkněte na bug #36026.
Q: Potřebný software?
A: GCC, ideálně více verzí, chyba se projevuje přinejmenším v 4.3.0 a 4.1.2 , verse a případně verse-tests (pokud chcete vyzkoušet i nějakého klienta), které jsou ke stažení přes subversion:
svn co https://svn.blender.org/svnroot/verse/trunk/verse
svn co https://svn.blender.org/svnroot/verse/trunk/verse-tests
Q: Co je třeba udělat atd.?
A: Problém je v tom, že když verse zkompiluji s gcc 4.x (v gcc 3.4.6 se chyba neprojeví) s flagem -O2 nebo vyšším tak generování klíče skončí v nekonečné smyčce. U klientů se to projevuje vždy (klíč se generuje při každém přihlášení), u serveru jen pokud v adresáři ze kterého je spouštěn není vygenerovaný host_id.rsa (např. z testu bez optimalizací).
Podle všeho za to nejspíš může nějaká kombinace flagů, protože když jsem zkoušel verse zkompilovat nejprve s jednou polovinou flagů, které -O2 zapíná a potom s druhou, ani jednou se problém neprojevil.
Q: Kde hledat chybu?
A: Hlavně díky Ketlingově pomoci byla jako původce chyby odhalena funkce miller_rabin()
v souboru v_prime.c
, která nerozpozná prvočíslo a tedy vrací vždy 0 což způsobí zacyklení smyčky v v_prime_set_random()
v témže souboru.
Tady se naše výsledky rozchází – podle mých testů problém nastává při druhém průchodu smyčkou v miller_rabin()
, kde v_bignum_square_half(d)
vrací jiné výsledky v optimalizované verzi a v neoptimalizované verzi. Podle Ketlinga problém nastává také při druhém průchodu, ale ve funkci v_bignum_mul()
.
Q: Jak testovat?
A: Styl testování nechám na Vás. Pokud ale v adresáři, ze kterého spouštíte verse máte vygenerovaný host_id.rsa
, vždy ho před dalším spuštěním vymažte, protože jinak se nespustí generovaní klíče.
Q: Co je to verse?
A: Verse je jednoduchý a nenáročný síťový protokol určený pro komunikaci grafických aplikací licencovaný pod GNU FDL. Linuxáky bude nejvíce zajímat jeho implementace ve verse gimp pluginu a Blenderu. Díky tomu je například možné propojit Blender a Gimp díky čemuž je možné kreslit v Gimpu texturu, která se v (takřka) reálném čase zobrazuje v Blenderu. Více viz domovská stránka verse.
Q: verse-tests nejdou zkompilovat!
A: V Makefile schází u arx flag -lalut
Tiskni
Sdílej:
miller_rabin. Môj odhad je, že
k = v_bignum_bit_msb(nmo);vráti záporné číslo a potom sa to v nasledujúcom fore cyklí. Navrhujem podávať na každý riadok printf a potom sa uvidí.
v_randgen.c
ve funkci VRandGen * v_randgen_new(void)
. Měl by se tam otevřít /dev/urandom, ale nic to nedělá. Když dám za gen->fd = open(SOURCE, O_RDONLY);
nějaký printf, tak ho to ani nevypíše ale až po delší době to přeskočí do fce v_randgen_get()
v témže souboru.
VRandGen * v_randgen_new(void)
otevře deskriptor na /dev/urandom a ten vrátí – to ještě funguje tak jak má.
Pak v souboru v_bignum.c funkce void v_bignum_set_random(VBigDig *x, VRandGen *gen
) zavolá fci void v_randgen_get(VRandGen *gen, void *bytes, size_t num)
z v_randgen.c.
Tahle funkce vezme deskriptor na /dev/urandom a ten se pokusí přečíst. Pomocí ukazatale by se měly přečtená data vrátit volané funkci. A tady je průser: /dev/urandom se začne číst, ale už neskončí.
void v_prime_set_random(VBigDig *x) { int bits = v_bignum_bit_size(x); VRandGen *gen; gen = v_randgen_new(); do { /* Create candidate, making sure it's both odd and non-zero. */ v_bignum_set_random(x, gen); /* Set topmost two bits, makes sure products are big. */ v_bignum_bit_set(x, bits - 1); v_bignum_bit_set(x, bits - 2); /* Set lowermost bit, makes sure it is odd (better prime candidate that way). */ v_bignum_bit_set(x, 0); } while(!v_prime_test(x, gen)); /* printf("Prime found after %d iterations: ", count); v_bignum_print_hex_lf(x); */ v_randgen_destroy(gen); }
dd if=/dev/urandom of=../verse-tests/rand count=1000 bs=32
. Potom som prepísal 64. riadok v_randgen.c na #define SOURCE "rand"
. Touto úpravou mi začal program po každom spustení generovať tú istú sekvenciu čísel, takže sa dá pekne porovnať dobrý a zlý výstup.
Dobrý program označil 0xC4FD1FB7720D4DF2C15DBD9A0FF4C9454399401720757DAB7DDBD68F909D3BC1 ako prvočíslo.
Zlý si myslí, že 0xC4FD1FB7720D4DF2C15DBD9A0FF4C9454399401720757DAB7DDBD68F909D3BC1 nie je prvočíslo a pokračuje drzo ďalej.
v_bignum_set_string_hex()
, popř. pomocí v_bignum_set_string()
x
nastavil na nějaké zaručené prvočíslo (některá jsou v v_prime_set_table()
, ale zkoušel jsem i jiná).
v_bignum_reduce(d, n, mu);
pri druhom prechode for cyklom vracia nesprávny výsledok.
v_bignum_bit_shift_right()
volanej z v_bignum_reduce()
v_bignum_bit_shift_right()
ale v_bignum_mul()
, nejak som to splietolv_bignum_square_half(d);
Prvá kompilácia:
./a.out > out1
Druhá kompilácia:
./a.out > out2
diff -u out1 out2 > priloha.diff
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.