Hlavní navigace

Vlákno názorů ke zprávičce Kolem 70 % vážných bezpečnostních chyb v Chromiu jsou chyby používání paměti od oss - Skvele, takze chrome bude teraz 5-krat pomalsi a...

  • Aktualita je stará, nové názory již nelze přidávat.
  • 26. 5. 2020 17:47

    Petr M

    Zaplatí prostě daň za bezpečnost.

    Pokud se na objekt odkazuje několik objektů a chyba je v to, že jeden jim ho mění pod rukama, tak se to fixne vytvořením kopie (asi jako přiřazení proměnné v Erlangu). Vytvoření kopie chce paměť a čas.

    Pokud odkaz přežije objekt, tak je dvojí obrana - neukazovat na objekt, ale při předání odkazu si ho naklonovat. Klon potřebuje paměť a kopírování (jedno, jestli se motá v cyklu, nebo čeká na DMA). Nebo počítat reference, občas se zastavit a projet to garbage collectorem (GC, který nezaměstná CPU, jsem ještě neviděl). GC je zátěž navíc, kolikrát projede všechny objekty v paměti bez toho, že by něco mazal...

    No a pokud chci mít jistotu, že se někde něco nedomrví, tak nas..ru aserce úplně na všechno a ve všech funkcích. Už ti někdo řekl, že podmíněný skok je nejdražší instrukce kvůli zahazování pipeline? A že pokud budeš odskakovat jenom při chybě, otrávíš si branch prediktor?

    Kde vidíš zachování nebo snížení spotřeby paměti/CPU?
    A - tadá - takzvaně "bezpečnější jazyk" to řeší úplně stejně, akorát se to nemusí psát explicitně, takže ubude překlepů nebo opomenutí. Výkon pude tak jako tak do kopru.

  • 26. 5. 2020 18:57

    bez přezdívky

    V Rustu můžete mít víc odkazů na jeden objekt a kompilátor zajistí bezpečnost s nulovou režií v čase běhu.

  • 26. 5. 2020 23:14

    J ouda (neregistrovaný)

    Můžu se zeptat jak to dělá? (resp bavíme se doufám o dlouhodobé heap alokaci, a ne o triviálních či méně triviálních případech kdy zafunguje lifetime a dokáže to ošetřit kompiler)

    Pokud mluvíte o std::rc::Rc tak tam si dost dobře nedovedu tu nulovou režii představit (ostatně ani v těch článcích, co jsem, rust neznaje, narychlo vygooglil, se v takovém případě nemluví o nulové režii, ale o režii srovnatelné s dobrou implementací v C/C++ - což mi připadá velmi uvěřitelné i logické)

  • 26. 5. 2020 23:38

    klokan

    Pokud je tím myšleno odkazy jako reference, tak na to není potřeba Rc, stačí &, což je úplně normální pointer nebo fat pointer. Těch je možné klidně mít několik současně, ale kompiler provede důkaz životnosti každého z nich.

  • 27. 5. 2020 0:58

    J ouda (neregistrovaný)

    Možná si nerozumíme (a možná nerozím já Vám co píšete v rámci rustu, který neznám).
    Jde mi o zhruba následující, zcela hloupý, zjednodušený a neoptimalizovaný příklad. Mám server, přijme tcp connection, tomu naalokuje (na heapu) nějakou strukturu kterou strčím do nějakého seznamu, která obsahuje dejme tomu nějaké síťové detaily (socket, rcv a send buffer + head a tail na ně, nějakou stavovou proměnnou, případně nějakou vyšší abstrakci nad tím) plus string nickname. Celá ta veselost umí jen poslat někomu jinému zprávu, takže fajn, v rámci obsluhy vyparsuju co přišlo, udělám iteraci přes všechny connections a když sedí nick, tak tomu předám zprávu do send bufferu, zavolám write() a hotovo. (neřešme teď chyby, blocking etc., jde mi jen o datové struktury)

    No a pak si vymyslím featuru, že když se někdo odloguje, tak to má napsat všem, s kým si povídali. Takže mě napadne ke každému connection přihodit nějaký seznam, který _nějak_ (v céčku to budou pointery, v rustu nevím a tam směřuje onen dotaz) ukazuje na connections účastníků, které je třeba notifikovat.

    Tady kompiler nemá jak během compile time poznat živost (prostě objekt zmizí ve chvíli, kdy mu spadne tcp connection), a za běhu si nedovedu představit, jak by to (ať už automaticky nebo manuálně) mohl udělat bez přídavné režie, jak tu tvrdil předřečník. Kompiler můžu vygenerovat při zrušení reference automaticky decrementovat ref_count a při nule zavolat nějaký free()/dealloc() nebo jak se to jmenuje, ale jak psal předpředřečník zadarmo to není, nebo může jen dekrementovat referenci ale samotnou práci nechat na GC, celé to samozřejmě může co do taktů velmi zlevnit optimalizace překladu (proč inkrementovat ref_count když vím že ho hned zase dekrementuju, teda pokud to není multithread, ale to je jen detail a měli bysme podobnou diskusi kolem Arc), ale cena na paměť tam bude pořád (minimálně je to o sizeof(refcount) interně víc - to že v 99% RL aplikací na tom nesejde je věc druhá)

    Nebo jsem jen pochopil špatně, a reálně se v rustu podobné konstrukce dělají úplně jinak?

  • 27. 5. 2020 9:13

    Ink

    Zázraky se nedějí a inherentní výpočetní složitost se obejít nedá. Rust člověka nepustí tam, kde to není bezpečné, ale to neznamená, že to program zpomalí nebo zvýší paměťové nároky. Synchronizace mezi vlákny má samozřejmě vždycky režii a ta by byla i v dobře/bezchybně napsaném programu v C. Vtip je v tom, že v Rustu by neměla být větší a pokud člověk nepoužívá kanon na vrabce, nedojde k jevu, kterým hrozí Petr M. Akorát jako bonus dostaneme tu větší jistotu a případně tedy stabilitu.

  • 27. 5. 2020 11:02

    JSH

    Přemýšlíte o tom způsobem vhodným pro jazyky s GC. V C++/Rustu tak jde přemýšlet taky, ale není to úplně šikovné. Nebudu se soustředit na implementační detaily, ale vezmu to obecně.

    Objekty v jazycích s GC existují naprosto nezávisle. Prostě žijí minimálně tak dlouho, dokud o nich někdo ví. A až na ně všichni zapomenou tak možná někdy umřou. Objekty v jazycích s GC nemají vlastně dobře ohraničený konec života. GC svým způsobem emuluje nekonečnou paměť, kdy objekty jen vytvářím a až doslouží tak je prostě ignoruju.

    Naproti tomu v C++/Rustu se vychází z toho, že většina objektů má nějakého logického vlastníka. Jen minimum objektů má cenu vlastnit sdíleně třeba přes reference counting. Například ten váš seznam lidí k notifikaci nemá důvod existovat samostatně bez toho primárního spojení. Takže bude mít jediného vlastníka a i jeho život bude s tím vlastníkem provázaný.

    A život záznamu v tabulce těch notifikací je zase svázaný s životem toho spojení s protistranou. Ve chvíli, kdy nějaké spojení umře, tak umřou i všechny vlastněné objekty.
    Ten příklad je hodně vágní, takže je těžké mluvit o nějakých konkrétních datových strukturách. Ale nevidím tam vlastně nic, co by vůbec vyžadovalo sdílení vlastnictví a tím i reference counting.

    Hlavní rozdíl v uvažování je ten, že pokud v jazyce s GC někam předáváte ukazatel, tak si ho ten volaný může bez omezení uložit a prodloužit tomu objektu život.
    V C++ to není dobrý nápad, takže to dělá (v novém c++) málokdo. Když předávám ukazatel, tak předpokládám že si ho volaný nebude nikam ukládat a po návratu z funkce už ten ukazatel neexistuje. Pokud chci volanému předat vlastnictví, tak dostane smart pointer. Jinak to dělá akorát historický kód, případně nějaké zprasenosti.
    Rozdíl mezi C++ a Rustem je v tomhle jen ten, že mi borrow checker vynutí abych ten půjčený ukazatel zase vrátil a nenechal si ho. V C++ je to jen dobrý zvyk, který ale překladač nemá jak vynutit.

  • 27. 5. 2020 13:20

    Filip Jirsák

    Jak moc je ten koncept vlastnictví „přirozený“? Vždycky, když o tom čtu, je to velmi logické – a zároveň vím, že kdybych to měl začít používat, budu nad tím muset strašně uvažovat, není to něco, co bych udělal intuitivně a většinou správně. Je možné, že je to jen nezvyk – ale trochu se bojím, že ne, že to prostě v něčem nesedí do světa, jak ho jako lidé normálně vnímáme. Ale chybí mi ta zkušenost, takže by mne zajímal názor někoho,kdo tu zkušenost má.

    Zkusím to připodobnit ještě k něčemu jinému. Třeba relační databáze jsou podle mne tak úspěšné proto, že používají model, který je lidem nějak blízký, je pro ně přirozený – model relačních databází existoval už dávno před počítači v podobě kartotéčních lístků nebo podvojného účetnictví. Podobně je to třeba s některými částmi objektového paradigmatu – a některé části, které nemají pořádný předobraz v reálném světě (třeba dědičnost), jsou i v OOP problematické a buď se nepoužívají, nebo se používají divně.

    Ten koncept vlastnictví je z hlediska OOP paradigmatu vlastně správně, uzavírá určitou díru, která je v běžných OOP jazycích a týká se zapouzdření. Normálně by měl objekt sám rozhodovat, co se s ním dá dělat, k tomu vystaví potřebné metody (nebo reaguje na události). To, že ten objekt může vlastnit kdokoli, ale to zapouzdření porušuje – protože pak platí, že o tom, co se s objektem dá dělat,rozhoduje objekt sám, s výjimkou vlastnictví, protože vlastnit ho může kdokoli.

    Rust tuhle díru v designu zalepil – ale odpovídá tenhle model tomu, jak vnímáme reálný svět? Já se bojím, že spíš ne, protože mu neodpovídá ani zapouzdření. Ano, objekt pes obvykle běhá, štěká, kouše a žere, ale pak přijdete s Bóbikem do restaurace a ukáže se, že se psem lze dělat i jiné věci, které Bobík určitě nechtěl. Nebo vám po přivyknutí připadá koncept vlastníka přirozený, rovnou vás napadá, kdo má být vlastník a co zpřístupníte ostatním – a jakmile se vrátíte do jazyka se sdíleným vlastnictvím, připadá vám to najednou jako hrozná anarchie, že objekt může vlastnit každý, kdo chce?

  • 27. 5. 2020 13:37

    KarelI

    Koncept vlastnictví samozřejmě v obecném pojetí přirozený není a troufám si tvrdit, že většina algoritmů ho nevyžaduje. Je to tedy nutné řešit v jazycích, které nemají GC, což má pak nezanedbatelný vliv na algoritmus, kód, čas programátora atd. V podstatě programátor musí zas a znovu ten GC v nějaké formě zapracovat do řešeného problému.

  • 27. 5. 2020 14:00

    JSH

    Jestli je "přirozený" nevím. Mám pocit, že v našem oboru není přirozené vůbec nic. Všechno je jen o naučení se, zvyku a hromadě tréninku. A jestli můžu vzít za slovo Daniela Kahnemana a jeho Rychlé a Pomalé myšlení, tak je to stejně i jinde. Veškerá naše intuice stojí na tom, že si natrénujeme mozek na podobných situacích. Něco úplně nového intuitivně a správně dělat prostě neumíme.

    Jinak já často ani neuvažuju o objektech jako samostatných entitách. Proměnné jsou obvykle spíš chlívky na hodnoty. Hodnotovou sémantiku v C++ bych nejlíp popsal stylem "Když můžeš, tak se chovej jako int". Proč by třeba string měl být nějaký objekt na haldě, na který se může vést hromada odkazů? Proměnná typu string je prostě chlívek na string a nějakou alokaci paměti ať si řeší uvnitř. Když nemám odkaz na string, ale přímo string, tak to vlastnictví vyplyne už z toho, kde ta proměnná je.

    OOP paradigma a reálný svět jsou dost vzdálené. Podobnosti jsou IMO spíš na škodu a slouží hlavně k tomu, aby začátečníky vodily stále do stejných pastí. V reálném světě děláme něco my s objekty, v OOP světě dělají něco ty objekty samotné. Drtivá většina reálných objektů umí akorát tak "zůstaň". Kdesi jsem četl vyjádření samotného Alana Kaye, že se mu ten název moc nepovedl.

    Nevím, jestli si pamatujete svoje OOP faily, já ty svoje jenom částečně. Určitě jich bylo mračno, než jsem si natrénoval hlavu.

  • 26. 5. 2020 8:54

    bez přezdívky

    Bezpečný jazyk ulehčuje agresivní optimalizace, C/C++ vede k defenzivnímu přístupu.