Áno, to se Vám nepochybně podaří, ale problém není ani tak v tom, že by C++ bylo špatné, ale v tom, že je to jazyk historický postavený na jiných programátorských paradigmatech dané doby. Před 20 lety byl považován za dobrého programátora ten, který uměl problémy s pamětí správně ošetřit. Dnes se řekne: „to není špatný programátor, že si nepohlídal všechny pointery“ … „to je tím, že jazyk je špatný“. Je to z toho důvodu, že jiné jazyky to hlídají za programátora, a tím se eliminovalo jedno z rizik programování (jeden z potřebných skillů programátora).
Navíc C++ při je ho postupné modernizaci se procházelo od konceptu C ke knihovně C++ s několika málo změnami po moderní jazyk (rok 2011+). Avšak s ohledem na zpětnou kompatibilitu se zachovaly možnosti psát „po staru“, a programátor má mnoho volnosti prasit dohromady konstrukty ze starého C, starého C++ a moderního C++.
To všechno dělá z C++ nebezpečný jazyk, a pokud chcete programátory donutit psát bezpečně, což se v praxi jaksi hodí, tak jim musíte C++ v současné formě zakázat. Je to smutné, ale je to tak, C/C++ umožňuje mnoho volnosti, ale bohužel ta volnost vede programátory ke špatnému používání jazyka a výsledkem jsou chyby.
Řešením je jedině omezit se (to lze vymáhat v analýzou kódu a v budoucnu lze předpokládat, že pokud C++ neumře, tak bude možné bezpečné standardy kódování vymáhat v lintu nebo i přímo kompileru) na moderní konstrukty (např. dle C++ Core Guidelines), které byly vymyšleny (a doplněny do C++) za tím účelem, aby se právě tyto chyby eliminovaly, z C++ se tak může stát jazyk podobný jiným moderním jazykům (ostatně nemálo těch konstruktů (C++11 až C++20) bylo převzato z jiných jazyků ve kterých se osvědčily).
Ano, C++ patří k těm jazykům, pro které platí „jaké si to uděláš, takové to máš“. Dalo by se říct, že to není programovací jazyk, ale nástroj, kterým si každý může vyrobit svůj vlastní programovací jazyk. Podle toho pak také vypadají diskuse, kde to vypadá, jako by každý psal o jiném jazyku – jenže ono to tak vlastně je. Problém je to právě u těch komplexních projektů, kde se potká spousta takových jazyků, všechny se syntaxí C++. Pak hodně záleží na tom, zda se těm schopnějším podaří vnutit ten svůj jazyk celému projektu.
Jenomže ono to není jenom o tom, že se musí používat moderní konstrukty (nemluvně o tom, že řada existujících knihoven včetně současného iostream prostě jako parametry bere char*). Je to o tom, že v C++ neexistuje lifetime analýza. Když například pořebuji v nějaké třídě mít referenci na jiný objekt, jsou v podstatě jenom dvě možnosti:
- buďto pracuji s nějakým unique_ptr nebo shared_ptr, což znamená, že tím vynucuji, jaký typ pointeru mi má volací kód předat, což hlavně u knihoven je problém;
- nebo přijmu referenci& (nebo pointer *) a v tu chvíli je po všem, protože v C++ není možné zajistit, že taková reference nepřežije objekt, na který ukazuje, že nemůže být nulová, nebo že nebude docházet k nekontrolovaným mutacím atd.
C++ je prostě děravé a je to jednak proto, že vzniklo v době, kdy pokročilejší metody statické analýzy prakticky neexistovaly, a jednak proto, že jeho filozofie vždycky byla implementovat všechny myslitelné featury a s problémy se potýkat "potom". V důsledku to vede i k takovým věcem, že najednou (pokud si pamatuju, tak v C++11) museli zavést novou alternativní syntaxi deklarace funkcí, protože s tou starou se jazyk stal neparsovatelný.
Jistě, že za pomocí analyzátorů a rigidní disciplíny je možné řadě problémů předejít, ale to není omluva a neznamená to, že C++ je vlastně dobré. Jestliže staré C++ bylo minové pole, tak moderní C++ je pořád minové pole, akorát je tam cedule "pozor miny". Rozhodně nevidím důvod, proč by měl někdo záměrně chtít jít zrovna tudy, pokud má jinou možnost.
26. 5. 2020, 09:20 editováno autorem komentáře
ad reference, teď vycházím z jednoho konkrétního projektu (v C), který je vystavený do internetu, takže to není jen o tom "na doma to stačí".
- nebo na daný objekt je omezený relativně malý počet referencí (nižší jednotky) v místech kde to dává smysl z pohledu performance, zaniká přesně v jediném místě (konkrétně potvrzená deautentikace klienta) kde jsou tyhle reference ošetřené a hlavne ošetřitelné, a v celém zbytku kódu se používá pouze v lokálních proměnných nebo jako parametr funkcí. Všude jinde, kde je jinde to potřeba uložit se použije unikátní serial, přes který se pak referencuje (reálně je pod tím btree ale to je fuk).
... a deauth je asynchronní evet v hlavním event loopu, takže race condition tam nemá vzniknout jak (bohužel, až do teď je to single thread, ale díky tomu výše nebude takový problém tam rozjet další, ale to už je jiná pohádka).
Ono se to dá, jen se člověk nesmí nechat unést.
Jistě že záleží na řadě okolností, mezi kterými jsou subjektivní (céčko mě osobně víc sedne než Java) i objektivní důvody (pointery jsou zlo, ale existuje spousta toolů a spousta návyků, které činí život s nimi snesitelný, a jde o zvážení jestli míru jistého nepohodlí z nich vyváží něco jiného, třeba ladění GC.)
Konkrétně u téhle věci je mnohem větší problém to, že se celý průběh hlavní smyčkou musí vejít do pár milisekund. Tady si troufám tvrdit že v tomhle konkrétním případě je céčko velmi vhodný jazyk, rozhodně bych ho nevnucoval jinde, zvlášť kde jsou jiné priority.
Před 20 lety byl považován za dobrého programátora ten, který uměl problémy s pamětí správně ošetřit.
Problém spatřuju v tom, že spoustu známých bezpečnostních chyb způsobili dobří programátoři. Možná ne tak dobří, aby splnili tuhle definici, ale dost dobří na to, aby se nedali snadno nahradit. A dost dobří na to, aby je drtivá většina zdejších čtenářů, ne-li všichni, respektovala. Protože chyby se stávají a nedají se eliminovat dodržením jednoduchých pravidel typu strcpy/strncpy/strlcpy.
On je tu jeste dalsi dulezity aspekt.
Dejme tomu ze jsem buh, co chyby v pointerech nedela, ani pri refaktoricazo apod, protoze mam hlavu jak patraci balon.
Otazka zni, jestli je stejny buh i ten Ind, co psal knihovnu pro odesilani SNMP trapu, kterou linkuju. Nebo libovoilnou jinou knihovnu, treba OpenSSL s jeho Heartbleed.
Ale ty přece také používáš C++ kód, který wrappuje C, který není bezpečný na všech platformách a vždy, např. používáš std::string tmpfile, který má problémy se staršími systémy, viz https://cwe.mitre.org/data/definitions/377.html.
U C++/C vůbec nejde o to, že umíš dobře psát, ale o to, že to dobře se nedá snadno ověřit a prokázat, vznikají chyby kombinací různých nepředvídatelných situací a máš tam jednu past vedle pasti.