Zero Day Initiative zveřejnila informace o 6 bezpečnostních chybách (1, 2, 3, 4, 5, 6) v MTA Exim. Nejvážnější z nich CVE-2023-42115 má CVSS 9.8. Na opravě chyb se pracuje.
Knihovna libvpx byla vydána ve verzi 1.13.1. Řešena je kritická bezpečnostní chyba CVE-2023-5217 (heap buffer overflow in vp8 encoding). Chyba je již opravena také v Chrome / Chromium 117.0.5938.132 a Firefoxu 118.0.1.
Balíček kmod s nástroji pro práci s linuxovými moduly byl vydán ve verzi 31. Nově umí modprobe zavést modul nacházející se v libovolném adresáři (# modprobe ./drivers/gpu/drm/i915/i915.ko).
Adventura Trüberbrook je na portále GOG.com zdarma, akce trvá do 2. října.
Sound Open Firmware, projekt Linux Foundation, open source audio DSP firmware a SDK, byl vydán ve verzi 2.7.0. Z novinek lze vypíchnout podporu platformy AMD Van Gogh.
Richard Stallman v den oslav 40. výročí GNU oznámil, že má rakovinu (YouTube).
DIY trackball Ploopy má novou variantu Adept, na rozdíl od předchozích používá 44mm kouli, má symetrický tvar a šest tlačítek, snímač zůstává PMW-3360, novinkou je použití Raspberry Pi Pico, na kterém běží firmware QMK s podporou grafické konfigurační aplikace VIA. Předobjednávky jsou otevřeny za ceny 80-105 CAD.
Probíhá Meta Connect 2023. Společnost Meta představuje své novinky v oblasti AI a virtuální, smíšené a rozšířené reality. Představeny byly nové chytré brýle Ray-Ban | Meta a headset Meta Quest 3.
Eben Upton oficiálně představil (YouTube) nové Raspberry Pi 5 (YouTube). Je více než 2x výkonnější než jeho předchůdce, model 4B.
Byl vydán (YouTube) Counter-Strike 2. Nativně také pro Linux. Jedná se o největší technologický skok v historii této populární herní série.
if(!ob_start("ob_gzhandler")) ob_start();mám to brát jako že to autor myslel takto?
if(!ob_start("ob_gzhandler")) { ob_start(); }else{ ob_start("ob_gzhandler"); }Že již při testováni ob_start("ob_gzhandler") se ta funkce zavolá proto nepoužil else? Díky
Řešení dotazu:
else
tam máš navíc. Ten druhý příklad by nefungoval správně.
ob_start() je funkce, která jako výsledek obsahuje hodnotu, zda se povedla či ne. Tuto hodnotu můžeš testovat.
ob_start("ob_gzhandler") || ob_start();
if(!ob_start("ob_gzhandler")) ob_start();
Člověku, který je ve svém kódu zvyklý takové obraty rutinně používat, to tak možná nepřijde, ale pro ostatní to výrazně snižuje čitelnost a srozumitelnost kódu.
Jinak většina přísnějších coding styles by nepovolila ani tu alternativu, kterou jste uvedl (a muselo by se to rozdělit na dva řádky).
ale když už, tak z těchto dvou možností mi přijde hezčí ta s ||.+1
do_somethig() or do_something_else()nebo
try do_something() except do_something_else()kdyz uz podminku tak
if is_supported_feature() do_something() else do_something_else()v podminenem vyrazu proste cekam predikat
udělejNěco() || udělejNěcoJiného()
krásně čitelné a na první pohled srozumitelné. Ještě lepší jsou ty výjimky, ale když už nejsou k dispozici, tak bych si alespoň výsledek první akce přiřadil do proměnné (s rozumným názvem) a tu vyhodnotil v podmínce na samostatném řádku.
OMG, to je zase flame Už na začátku jsem psal, že se mi moc nelíbí ani jedno. Moje pořadí:
V případě nějakých skriptů nebo jazyků, kde je zvykem tak psát, bych 3 posunul na druhé – možná i první, pokud nejsou podporované výjimky – místo. Možnost 4 mi přijde ze všech nejošklivější a nejméně čitelná.
Snad jen že jsem moc rád, že většina projektů, do kterých přispívám a s jejichž kódem musím pracovat, na to má opačný názor než vy dva.Ve Frantově případě už opravdu jen trolluješ, vzhledem k tomu, že opačný názor k jeho je v podstatě použít libovolnou z možností, které se mu nelíbí.
||
neospravedlnitelná prasárna, pro něj je to naprosto přirozená konstrukce. Pro mne je naprosto v pořádku použít funkci s vedlejším efektem v podmínce, pro něj je to neospravedlnitelná prasárna. Takže v tom se prostě shodnout nemůžeme.
pro něj je to naprosto přirozená konstrukceVětšinou píšu v Javě a tam to nepoužívám. Občas v Perlu nebo Bashi ano a tam mi to přijde jako lepší varianta.
…použít funkci s vedlejším efektem v podmínce, pro něj je to neospravedlnitelná prasárna.Abych to trochu zmírnil: nepovažuji to za úplné tabu, ale přijde mi to horší než použití ||. Když kouknu letmo na zdroják, tak vidím posloupnost příkazů a bloky, které se provádějí jen někdy, za určitých okolností – ale že se v závorce za IFem bude ukrývat i nějaký výkonný kód a ne jen vyhodnocení těch okolností, považuji za trochu zákeřné – je potřeba číst pozorněji a není to takové rychlé „kouknu a vidím“ – což zrovna u toho || funguje (pokud někdo nepíše kilometr dlouhé řádky, ale to je zase jiná kapitola). Chápu, jak to myslíš, a i že je to trochu zneužití téhle konstrukce… Ale když se podívám na výsledek, je to pro mne čitelnější než if + negace + pár závorek (a to jsem jinak docela fanda do závorek a píšu je rád). Že se výsledná hodnota nikam nepřiřadí nebo nepoužije taky není takový hřích – celkem často se volají nějaké metody/funkce, které něco vrací a výsledek nepotřebuješ, tak s ním dál nepracuješ.
P.S. dávat do podmínky výraz, který něco dělá/mění (místo aby jen zjišťoval) mi přijde fakt prasárna
if not decrypt(file, candidate): do_some_cracking()
if not kytička = tsql.fetchone(): log("Strange, gardener solved job I did not submit!", LOG_ERR) return zasaď(kytička)Přesvědčuj, ještě to můžu změnit! :)
if
), vždyť to už hraničí i s klasickým
if((fw=fopen("xy", "wb") != NULL){ if((fwrite( buff, sizeof(char), n, fw)) != n){ //write error } if(fclose(fw) != 0){ //write/close error } }else{ //open error }ten kód je, tedy podle mě, čitelný a hezký.
Také si myslím, že umělé ukládání návratové hodnoty do proměnné, pokud se pak k ničemu jinému nepoužije, přehlednosti nijak neprospívá, spíš naopak. Něco jiného už je samozřejmě situace, kdy hodnotu tak jako tak musím uložit, např.
if ((buffer = malloc(n * sizeof(int))) == NULL) { ... } ...
Tam bych se naopak přiklonil k rozdělení.
if((fw=fopen("xy", "wb") != NULL){tak i
if((buffer = malloc(n * sizeof(int))) != NULL){mi přijde dobré v případě, že v bloku na základě té podmínky pracuji s danou návratovou hodnotou. Proto jsem to vyhodnocení úspěšnosti alokace otočil. Ale i následující mi přijde jako OK:
if((buffer = malloc(n * sizeof(int))) == NULL){ //error & exit }A naopak u všech to cítím tak, že když se to vyhodí z podmínky tak to zhoršuje čitelnost, ale hlavně zvyšuje riziko vložení kódu „mezi“.
lock()
jsem se v příkladu vykašlal…):
while(!allDataProcessed()){ if(((buffer = getBuffer()) != NULL) //get a free buffer &&(readData(&buffer))){ //read data into the buffer //process buffer… releaseBuffer(&buffer); }else{ pthread_cond_wait(&cond, &mut); //wait for release a buffer or reading thread } }Ale věřím, že spoustě lidí se to nelíbí…
lze v jedné podmínce provést dva příkazy, přičemž druhý se neprovádí v případě…Takže k tomu IFu přidáš ještě konstrukci typu:
ob_start("ob_gzhandler") || ob_start();
aaa() || bbb();čitelné, ale když se to začne ztrácet v IFu a negacích, už je to horší – je těžší tam na první pohled vidět ty metody, které něco dělají/mění…
OR
a takovéhoto použití mi přijde zbytečně brainfuck-ové.try fw = fopen() fwrite(fw) fclose(fw) except print errornebo toto
( fw = fopen() and fwrite(fw) and fclose(fw) ) or ( die() )samozrejme se nebavime o C, ktery tyto konstrukce neumi.
die()
je die, tak jen nedokonalý.fwrite()
, a „print error“ naznačuje že soubor zůstane otevřený kdoví do kdy.
Myslel jsem, že svůj názor na použití logických operátorů coby maskovaných podmíněných příkazů jsem už sdělil dostatečně zřetelně… Co se výjimek týká, tak pokud je jazyk má, je to fajn, ale ani v tom případě se nehodí vždy. Třeba když budu chtít pomocí výjimek přepsat kód typu
int __init ip6_route_init(void) { int ret; ret = -ENOMEM; ip6_dst_ops_template.kmem_cachep = kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0, SLAB_HWCACHE_ALIGN, NULL); if (!ip6_dst_ops_template.kmem_cachep) goto out; ret = dst_entries_init(&ip6_dst_blackhole_ops); if (ret) goto out_kmem_cache; ret = register_pernet_subsys(&ipv6_inetpeer_ops); if (ret) goto out_dst_entries; ret = register_pernet_subsys(&ip6_route_net_ops); if (ret) goto out_register_inetpeer; ... ret = fib6_init(); if (ret) goto out_register_subsys; ret = xfrm6_init(); if (ret) goto out_fib6_init; ret = fib6_rules_init(); if (ret) goto xfrm6_init; ret = register_pernet_subsys(&ip6_route_net_late_ops); if (ret) goto fib6_rules_init; ret = -ENOBUFS; if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, NULL) || __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, NULL) || __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL, NULL)) goto out_register_late_subsys; ret = register_netdevice_notifier(&ip6_route_dev_notifier); if (ret) goto out_register_late_subsys; ...
tak mi výjimky kód spíš znepřehlední.
ret
mi přijde lepší, než nacpat výkonný kód do závorek za IF. A to GOTO je vlastně taková emulace výjimek Použití proměnné ret mi přijde lepší, než nacpat výkonný kód do závorek za IF.
Kdybych tu funkci zkopíroval celou, bylo by vidět, že ukládání návratové hodnoty do proměnné ret
není samoúčelné, protože uložená hodnota se v případě chyby použije jako návratová hodnota ip6_route_init()
. Což se promítá i do téhle části:
ret = -ENOBUFS; if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, NULL) || __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, NULL) || __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL, NULL)) goto out_register_late_subsys;
která mimochodem dělá přesně to, co se vám nelíbí.
A to GOTO je vlastně taková emulace výjimek
Jenže v tomto případě by právě výjimky z hlediska přehlednosti nadělaly víc škody než užitku.
Což se promítá i do téhle části:÷Zrovna tady by se proměnná hodila – smyslem proměnné totiž není jen to, že v IFu nebude výkonný kód, ale i to, že si nějakým výstižným názvem pojmenuji výsledek logické operace složené z několika AND/OR – aby to člověk nemusel luštit vždy znovu a znovu a zkoumat, proč tam jsou zrovna takový ORy a ANDy a co tím chtěl původní autor říct.
Jenže v tomto případě by právě výjimky z hlediska přehlednosti nadělaly víc škody než užitku.Neznám kontext, může být.
aby to člověk nemusel luštit vždy znovu a znovu a zkoumat, proč tam jsou zrovna takový ORy a ANDy a co tím chtěl původní autor říct.Hlavně se obsah proměnné hezky zkoumá v debuggeru, takže pokud se nejedná o něco, o čem se předpokládá, že to nebudu nikdy potřebovat debugovat, tak to není špatný nápad. Optimalizovaná verze se stejně bez místa v paměti pro nepotřebnou lokální proměnnou obejde.
-O0
, tak ano.
Neznám kontext, může být.
Kontext je jednoduchý. Je třeba provést sérii asi tak deseti inicializací ve správném pořadí s tím, že pokud některá selže, všechno, co se dosud povedlo, se zase musí (v opačném pořadí) vrátit zpět. V C++ by se to nejspíš řešilo přes nějakou umělou třídu a pomocné třídy pro jednotlivé kroky inicializace, ale to zase zanáší nežádoucí overhead.
public void nějakáMetoda() { try { vytvořitSpojení(); připravitSQLDotaz(); vykonatSQLDotaz(); } catch (Exception e) { zavřít(spojení, dotaz, výsledkováSada); } } public static void zavřít(Connection spojení, Statement dotaz, ResultSet výsledkováSada) { if (výsledkováSada != null) { try { výsledkováSada.close(); } catch (Exception e) { // nedá se už nic dělat, jen zalogujeme } } if (dotaz != null) { try { dotaz.close(); } catch (Exception e) { // nedá se už nic dělat, jen zalogujeme } } if (spojení != null) { try { spojení.close(); } catch (Exception e) { // nedá se už nic dělat, jen zalogujeme } } }
A hlavně se ta byznys logika neztrácí mezi haldami pomocného, uklízecího a výjimky ošetřujícího kódu.Ztrácení užitečného kódu způsobují někdy i „korporátní“ konvence pro logování a jednotkové testování…
----------------------------------------------------------------- STATE | ACTION | OK | ERROR - 1 | ERROR - 2 | ...... ----------------------------------------------------------------- init | do_init() | inited | init | final inited| do_someting() | next | init | init final | exit() | null | null
while state != 'final' retval = execute(table[state][action]) state = table[state][retval]
definice tabulky: obycejne pole, list, dict, map ... - pametova narocnost pro desitky stavu je nulova
predavani parametru: trivialni - list, dict, map ...
wrappery nemusi bejt potreba, pripadne se muzou generovat automaticky.
Ihned utnu namitku, ze v C a v kernelu si nemuzeme dovolit nejake listy a mapy. Na par radku se da napsat generator, ktery tento automat prevede do C-kovyho kodu, i se vsema vyhodama, ktere nasleduji.
Co je ale obrovskej prinos? Verifikace a validace. Ten kod kernelu, co jste poslal, je vicimene nemozne poradne otestovat (ale co uz, mame tisice testeru, tak je nam to fuk :) ).
Definici stavoveho automatu muzeme krasne validovat oproti zadani. Jenoduchy provadeci kod automautu se poradne otestuje jednou a pak uz to mame zadarmo. Jednotlive akce pujdou krasne unit testovat.
definice tabulky: obycejne pole, list, dict, map ... - pametova narocnost pro desitky stavu je nulova
predavani parametru: trivialni - list, dict, map ...
wrappery nemusi bejt potreba, pripadne se muzou generovat automaticky
Zkuste si to pro ten konkrétní příklad. Uvidíte, že náročnost není ani zdaleka "nulová", že kódu bude ve výsledku podstatně víc než je ho teď a že se v něm bude podstatně hůř orientovat.
Na par radku se da napsat generator, ktery tento automat prevede do C-kovyho kodu, i se vsema vyhodama, ktere nasleduji.S tím souhlasím a myslím, že by to pomohlo mnoha programům – efektivita programu tím netrpí (generuje se ještě před kompilací), chybovost (překlepy atd.) je omezena, jsou lépe oddělena data od logiky, snáze se přidají nová data…
To tak trochu zavání 10. pravidlem, resp. zde nastává problém nutné znalosti generátoru k pochopení zdrojového kódu.Ihned utnu namitku, ze v C a v kernelu si nemuzeme dovolit nejake listy a mapy. Na par radku se da napsat generator, ktery tento automat prevede do C-kovyho kodu, i se vsema vyhodama, ktere nasleduji.
zacatecnikum kteri se prave dozvedeli o zkracenym vyhodnocovani to muze pripadat "Fujtajbl"...
Jsou takovéhle urážky nutné, zvlášť když dobře víte, jak moc jsou mimo mísu?
ob_start("ob_gzhandler") returns FALSE if browser doesn't support gzip, so then is called normal ob_start();Tzn. browser podporuje gzip, nastartuje se output buffering s callbackem ob_gzhandler. Pokud nepodporuje, spusti se standardni output buffering.
if (foo()) bar();je zkraceny zapis tohoto:
if (foo()) { bar(); }vhodny pokud v podminenem bloku je jen jeden prikaz; Jinak taky preferuju zapis, ktery ukazal mike
Že již při testovániob_start("ob_gzhandler")
se ta funkce zavolá proto nepoužilelse
?
Samozřejmě. Jak byste chtěl zjistit návratovou hodnotu funkce, aniž byste ji zavolal?
ok = ob_start("ob_gzhandler"); if (!ok) { ob_start(); }
Tiskni
Sdílej: