Hlavní navigace

Bezpečné programování v C++ I

9. 3. 2009 23:54 (aktualizováno) inkvizitor

Nedávno jsem měl debatu s Laelem Ophrirem, který tvrdil, že linuxové prostředí, kde se používají zejména jazyky C a C++, je z principu náchylnější k chybám v kódu, než prostředí Windows, kde se čím dál tím více prosazují „managed“ jazyky typu C#. Tenkrát jsem slíbil, že napíšu do blogu, proč to není pravda. V principu každý alespoň trochu rozumně napsaný program je možné pomocí statické analýzy vyšetřit a zjistit, zda je napsán korektně. V praxi to tak jednoduché není a netýká se to pouze jazyků typu C a C++, ale obecně jakéhokoliv programovacího jazyka. Při zachování určité disciplíny se lze ale kýženému stavu docela dobře přiblížit. V tomto miniseriálku se chci zaměřit na jazyk C++, který podle mého názoru umožňuje psát stejně bezpečné programy jako C# nebo Java.

Naše debata se týkala ověřitelnosti správnosti kódu napsaného v jednotlivých jazycích a Lael vyzdvihoval zejména nebezpečnost používání ukazatelů. Je třeba zdůraznit, že žádný program, který běží na současných mainstreamových počítačích, se neobejde bez použití ukazatelů. Na úrovni strojového kódu vždy dochází k explicitní alokaci a dealokaci paměti a k přístupu do této paměti pomocí ukazatelů. Na opačném konci stojí kód aplikačního programu, který může být napsaný v libovolném programovacím jazyce. Mezi těmito dvěma krajními póly stojí izolační vrstva, kterou může představovat interpret jazyka, překladač nebo knihovna. V zásadě nezáleží na tom, jaká izolační vrstva je v daném případě použita. Důležité je, že programátora odstíní od nízkoúrovňového kódu.

Když se omezíme na problematiku ukazatelů, lze jazyky rozdělit do tří kategorií: 1. Jazyky, které se bez použití ukazatelů dost dobře neobejdou – sem patří například C. 2. Jazyky, které ukazatele používají, ale z hlediska aplikačního programátora se bez nich lze docela dobře obejít – to je případ C++. 3. Jazyky, které ukazatele nepotřebují a ani v nich nejsou programátorovi ukazatele k dispozici. Sem patří široká škála jazyků funkcionálních, logických, jazyky typu C# a Java a spousta vyšších objektově orientovaných a hybridních programovacích jazyků. Zatímco u jazyků 3. kategorie je izolační vrstvou interpreter, kompilátor nebo jejich kombinace (např. překlad do interpretovaného bytecode), u C++ se musíme spokojit s knihovnami. To nám ale úplně stačí! U JVM, CLR apod. se rovněž musíme spokojit s tím, že důvěřujeme implementátorům prostředí, v němž programy běží.

Nezbedné ukazatele jsou ale jenom jedním z rizik, které v programovém kódu číhají. Jiné riziko představuje kód, který je plný funkcí (procedur) s vedlejšími efekty, které pořád dokola modifikují obsah proměnných nebo objektů. Kód, který omezuje takové praktiky na minimum a striktně odděluje „destruktivní“ akce od „nedestruktivních“, je z hlediska analýzy zcela jistě nejpřístupnější. Každou funkci, která pouze přijme na vstupu nějakou sadu hodnot a z nich vypočítá výsledek, lze zkoumat zcela odděleně. Místa, kde dochází k přepisování paměti, byť ne třeba pomocí ukazatelů, lze jasně označit a věnovat jim zvýšenou pozornost.

V C++ existuje spousta mechanismů, které umožňují vyhnout se použití ukazatelů a zvýšit bezpečnost kódu – reference na konstantní objekty, silná typová kontrola, mechanismus šablon a bohaté knihovny s kontejnerovými třídami – např. STL. Zároveň ale C++ umožňuje posílat ukazatele na funkce, takže v něm můžeme poměrně snadno implementovat principy známé z čistě funkcionálních jazyků.

V tomto dílu bych chtěl ukázat, jak je možné v C++ implementovat funkci filter() známou například z Pythonu.Tato funkce má dva argumenty – vstupní seznam a funkci, která rozhoduje, zda se hodnota ze vstupního seznamu objeví ve výstupním seznamu, který funkce filter() vrací. Funkce je velmi užitečná a pomáhá psát velmi elegantní a čitelné konstrukce. V Pythonu lze její použití demonstrovat následujícím prográmkem, který filtruje seznam celých čísel, tak, že v něm ponechá pouze sudá čísla:

#!/usr/bin/env python

l = [1, 2, 3]
print "Original list:", l
print "Filtered list:", filter(lambda x: ((x % 2) == 0), l)

Funkce filter() z jazyka Python ve verzi 3 chybí, ale lze ji snadno nahradit pomocí tzv. list comprehension:

#!/usr/bin/env python

l = [1, 2, 3]
print "Original list:", l
print "Filtered list:", [i for i in l if ((i % 2) == 0)]

Tato funkce má obdobu v různých jiných jazycích, byť se může jmenovat jinak nebo je nahrazena metodou dané třídy, která vrátí jiný objekt. Pro zajímavost přikládám prográmek v jazyce Scala:

#!/bin/sh
exec scala "$0" "$@"
!#

val l = List(1, 2, 3)

print("Original list: ")
println(l)

print("Filtered list: ")
println(l.filter(_ % 2 == 0))

Jak na to v C++? Třeba tak, že využijeme knihovny STL, která nabízí třídní šablonu s názvem list a definujeme si šablonu funkce, která umožní psát programy v podobném stylu, jaký nabízejí funkcionální jazyky. Náš prográmek bude vypadat následovně:

#include <list>
#include "safecode.hpp"
using namespace std;

bool isEven(const int &i)
{
    return ((i % 2) == 0);
}

int main(void)
{
    list<int> l;
    l.push_back(1);
    l.push_back(2);
    l.push_back(3);

    printList(l, "Original list");
    printList(filter(l, isEven), "Filtered list");

    return 0;
}

Program používá dvě šablony s názvem filter a printList. Jejich definice se nachází v souboru safecode.hpp, jehož obsah je následující:

#include <list>
#include <string>
#include <iostream>
using namespace std;

template<typename T>
void printList(const list<T> &l, const string &desc = "List contents")
{
    typename list<T>::const_iterator it;
    typename list<T>::size_type i = 0;

    cout << desc << ": [";

    for (it = l.begin(); it != l.end(); it++)
    {
        cout << *it;
        if (i < l.size() - 1)
            cout << ", ";

        i++;
    }

    cout << "]" << endl;
}

template<typename T>
list<T> filter(const list<T> &originalList, bool (* func)(const T &))
{
    list<T> newList;
    typename list<T>::const_iterator it;

    for (it = originalList.begin(); it != originalList.end(); it++)
    {
        if (func(*it))
            newList.push_back(*it);
    }

    return newList;
}

Všichni příznivci funkce filter() se mohou radovat – v C++ ji lze implementovat velmi snadno a používat ještě snadněji. Udělali jsme krůček k psaní snadno čitelného a srozumitelného kódu v C++. Příště bych chtěl uvést další příklady. Doufám, že si tento úvodní článek najde svoje příznivce nebo alespoň vyvolá zajímavou diskusi. Budu se těšit.

Update 9.3.2009: Na radu čtenáře s přezdívkou Sten jsem ve funkci printList() změnil typ proměnné i z int na list<T>::size_type. Děkuji.

Sdílet

  • 8. 3. 2009 3:39

    Šimon Tóth (neregistrovaný)

    Vazat obecny algoritmus primo na datovy kontejner je dost ujete. Co takhle pres iteratory, nebo jeste lepe zcela obecne a osetrit pomoci boost concept?

    Nemluve o tom, ze ukazovat nejakou vlastnost jazyka duplikovanim funkcnosti jine casti je vzdy hodne spatny napad. Pokud uz je nutne neco podobneho udelat je absolutne nezbytne na tento fakt durazne upozornit a zduraznit, ze uvedeny kod slouzi pouze pro demonstraci a ze implementace dane funkcnosti je uz v jazyce dostupna.

  • 8. 3. 2009 12:09

    Jirka P (neregistrovaný)

    No nevím - ten ukazatel na funkci bude asi dost na překážku použití takového filtru. Kdyžtak bych to udělal tak, aby to mělo hlavičku

    template
    list filter(list originalList, boost::function func)

    nebo bych to nechal rovnou brát obecný funktor a použil iterátory, z čehož by nakonec vzniklo to, co se v c++0x bude jmenovat std::copy_if. Ze stejného soudku je i filer_iterator z boost.iterators.

    Ale ten prográmek ve Scale mě nadchl - jednak jsem nečekal, že by to někdo znal, druhak mě doslova odbourala ta hlavička...

  • 8. 3. 2009 12:12

    Jirka P (neregistrovaný)

    Tak ještě jednou, s lepšíma zobákama.

    No nevím - ten ukazatel na funkci bude asi dost na překážku použití takového filtru. Kdyžtak bych to udělal tak, aby to mělo hlavičku

    template<class T>
    list<T> filter(list<T> originalList, boost::functi­on<bool(T)> func)

    nebo bych to nechal rovnou brát obecný funktor a použil iterátory, z čehož by nakonec vzniklo to, co se v c++0x bude jmenovat std::copy_if. Ze stejného soudku je i filer_iterator z boost.iterators.

    Ale ten prográmek ve Scale mě nadchl - jednak jsem nečekal, že by to někdo znal, druhak mě doslova odbourala ta hlavička...

  • 8. 3. 2009 13:00

    lobo (neregistrovaný)

    hm, s uvodom nesuhlasim
    je to podobna argumentacia, ze snura na pradlo je rovnako dobra ako horolezecke lano: ved ked predsa pojdes na hory, tak si tych snur na pradlo zapleties 6 dokopy a hlavne sa na to nebudes vesat celou svojou vahou
    .

  • 8. 3. 2009 13:05

    BoneFlute (neregistrovaný)

    Koukám, že jako inspirace je Lael Ophrir dobrej. Žel pravdu má výjimečně.
    Děkuji za dosti zajímavé porovnání.

  • 8. 3. 2009 14:37

    Pichi (neregistrovaný)

    Už to hledám hodinu a nemůžu to najít. Kde je ten citát asi v tomhle smyslu: Každý komplexní netriviální program v C (nebo C++) obsahuje polovinu neefektivní, neudržovatelné a chybové implementace LISPu.

  • 8. 3. 2009 17:54

    bořek (neregistrovaný)

    Jazyky C a C++ kladou subjektivně vyšší nároky na vývojáře než např. Java nebo C#, aby se dosáhlo stejně bezpečného kódu. Vzhledem k mizerné úrovni některých programátorů v praxi (tipnul bych si, že je jich většina) je to celkem podstatné. Podle mě jsou největším nedodostatkem C++ je nekonzistence standartní knihovny. Nejlépe je to vidět např. na vyjímkách. Vyjímky jsou v Javě kontrolované kompilátorem a navíc vím, jaké vyjímky může funkce vyvolat. Naopak do C++ jsou vyjímky "naroubované". Takže některé části standartní knihovny používají bitové příznaky nebo návratové hodnoty hlásící chybu(jako v C) a jiné už podporují vyjímky. Bez kvalitní dokumentace nebo zdrojových kódů se nemůžu spolehnout na nic. Tím, ale nechci shazovat C/C++. Jsou to jazyky, které určitě mají své uplatnění, ale v poslední době mi připadá, že na tvorbu běžných programů s grafickým rozhraním jsou vhodnější alternativy. Názory, že nějaký jazyk je nejlepší, a proto v něm musíme psát všechny aplikace jsou naprosto nesmyslné.

  • 8. 3. 2009 20:34

    alef0 (neregistrovaný)

    Vyhoda manazovanych jazykov vidim v tom, ze vyzaduju mensie vstupne znalosti programatora a znizuju pravdepodobnost nahanania pointerov, teda chyb, ktore sa ladia nesmierne tazko. Kym v Jave/C# ani nemusim uvazovat o pointeroch, v C sa bez nich nezaobidem a v C++ minimalne musim mysliet na to, ze tam su.

    Pozitivom ale bude, ked mi niekto ukaze, ze C++ nie je az take pointerovo zamorene, ako sa mi podla mojich znalosti zda (mam totiz z C++ neracionalny strach) a ze to nahananie pointerov je vlastne mytus.

  • 8. 3. 2009 21:51

    m (neregistrovaný)

    Je jasne, ze bez kvalitnich knihoven v C++ dnes snad nikdo nepise. Vysvetleni, vcetne porovnani s Pythonem, bylo nazorne a davam mu "+1" :-).

  • 9. 3. 2009 0:17

    Miloslav Ponkrác (neregistrovaný)

    C++ je nebezpečný jazyk. Je to formule 1 a má přesně tytéž vlasnosti, chce cvičeného řidiče.

    Mimochodem, řekl bych, že není v C++ nic nebezpečnějšího, než je STL. Knihovna, která nekontroluje skoro nic a základní, s trochou nadsázky lze říci normou předepsanou, reakcí na nečekané hodnoty patrametrů je u STL zhroucení programu.

    Jako člověk, který mnoho let intenzívně programuje v C++ mohu říci, že velmi zvýšíte bezpečnost svých programů, když nahradíte STL jeho kontrolovanou implementací, nebo ještě lépe, její používání omezíte na nezbytné minimum, co nejblíže k nule.

    To co dokáže udělat STL za velmi fikané chyby, které můžete dlouho hledat, proti tomu je jakákoli chyba s ukazatelem jenom slabý čajíček.

  • 9. 3. 2009 0:35

    Yossarian (neregistrovaný)

    Par otazek.
    1) Co je na tomto pouziti funkce filter() safe, nebo spis co to ma vubec demonstrovat?
    2) bylo by lehce inteligentnejsi , umet filter() nad 2 iteratory, a mnohem blizsi filosofii STL
    3) to ze C++ neumi noname funkce je dalsi 'bezpecny' prvek, takle si psat jednoradkove funkce bokem, a pak si dohledavat, co delaji .. navic sila funkcionalnich jazyku spociva PRAVE v tom, ze umi lambda kalkul, tendle pripad dokazuje akorat to, ze v C++ funkcko emulovat je maximalne opruz, a ne to, ze 'to jde, a navic i bezpecne'.

  • 9. 3. 2009 0:59

    mol (neregistrovaný)

    Ve skutečnosti samozřejmě filter už ve standardní knihovně dávno je. Jmenuje se remove_copy_if, pozor na to, že má obráceně podmínku (kopíruje tedy ty, pro které isEven vrátí false):

    list res;
    remove_copy_if(l­.begin(), l.end(), back_inserter(res), isEven);
    printList(res, "Filtered list");

    Bohužel, omylem ze standardu vypadlo copy_if, které by neobracelo podmínku, ale to snad není velký problém.

  • 9. 3. 2009 1:07

    Po par pivach (neregistrovaný)

    C# pouzite ukazatelov umoznuje, nie vsak pre vsetky typy premennych. Inak clanok dobry, uvital by som vsak keby bol ukazany priklad, ktory by ukazoval aj nie "bezpecnu" implementaciu spominanej funkcie(a jej dosledky).

  • 9. 3. 2009 2:28

    javista (neregistrovaný)

    O tomhle dlouho přemýšlím.

    Začínal jsem Assemblerem a C, dostal jsem se přes C++, WIN32 API, Visual C++ s ATL na Javu, kde jsem už docela dlouho a jsem velice spokojený.
    Opravdu si myslím, že je Java skvělý programovací jazyk s věeobecnou využitelností, skriptovací jazyky jsou úspornější v kódu, ale bez možnosti detailní syntaktické kontroly, když si vzpomenu na příklady úloh s pointerovou aritmetikou v C, tak jsem rád, že s tím dnes již nemám co společného.

    Je to podobné jako s možností psaní "úžasných a geniálních" konstrukcí na jednu řádku typu
    use integer;@A=split­//,;sub R{for$i(0..80){next if$A[$i];my%t­=map{$_/9
    ==$i/9||$_%9=­=$i%9||$_/27==$i/27&&$_%­9/3==$i%9/3?$A[$_]:0=>1}­0..80;R($A[
    $i]=$_)for grep{!$t{$_}}­1..9;return$A[$i]=0}di­e@A}R

    Příklad daného sudoku solver v perlu, je sice "cool", ale pro někoho dalšího, kdo by se dostal k projektu například jako support je ten kód prakticky nespravovatelný.

    Dneska je obrovské množství softwarové údržby předáváno do Indie lidem, kteří mi někdy příjdou že ještě před měsícem prodávali zeleninu, ale proto že jim to nešlo, tak šli programovat (znám ale i plno chytrých a snaživých indických programátorů). Ti dovedou dělat divoké věci i v Javě, jejich práce v C/C++ by byla podle mne nemožná.

    Někdy si hraju s myšlenkou OS, kterýby byl implementován celýv Jave a kernel by jen zaváděl JRE pro danou platformu :-).

  • 9. 3. 2009 2:54

    Sten (neregistrovaný)

    Tak jako správný C++kař se hned pozastavuji nad implementací printList a používáním int i v něm. Takže pokud bys už chtěl požít nějaké počítadlo, tak použij list::size_type (u něhož zjistíš, že není typu int, ale size_t, což může být i unsigned long, tedy ten int by ti přetekl) nebo ještě lépe si udělat objekt pro psaní čárky, který se volá před každým výstupem, např. takto (bohužel musím psát na jeden řádek): class Comma_t { public: Comma_t() : doWrite(false) {} std::ostream& operator ()(std::ostream &out) { if (this->doWrite) { return out <doWrite = true; return out; } protected: bool doWrite; };, potom udělat funkci pro vložení Comma_t do proudu a nakonec printList upravit na Comma_t comma; for (it ...) { cout << comma << *it; }

  • 9. 3. 2009 3:38

    Sten (neregistrovaný)

    Ještě jeden komentář: správně C++kovsky by funkce filter měla vypadat takto: template OutputIterator filter(InputI­terator first, InputIterator last, OutputIterator result, bool (&func)(typename InputIterator::va­lue_type item)) { while (first != last) { if (func(*first)) { *result++ = *first; } first++; } return result; } a funkce isEven takto: template bool isEven(Numeric i) { return (i % 2) == 0; } a funkci filter voláme takto: filter(l.begin(), l.end(), std::back_inser­ter(l2), isEven);

  • 9. 3. 2009 8:46

    dum8d0g (neregistrovaný)

    "Všichni příznivci funkce filter() se mohou radovat - v C++ ji lze implementovat velmi snadno a používat ještě snadněji. Udělali jsme krůček k psaní snadno čitelného a srozumitelného kódu v C++." -- Jak pro koho. Ja si tohle budu muset precist tak desetkrat nez pochopim o co tady bezi. Ale jinak to vypada hodne zajimave, doufam ze tomu brzo porozumim.

  • 9. 3. 2009 8:53

    vlk (neregistrovaný)

    > V principu každý alespoň trochu rozumně napsaný
    > program je možné pomocí statické analýzy vyšetřit
    > a zjistit, zda je napsán korektně.
    Toto by som nikdy netvrdil.
    Najma ak nevieme rozhodnut problém zastavenia Turingovho stroja.
    vid. kap. 6.9.2 http://people.ksp.sk/~ppershing/mutella/skola/foja/foja_misof.pdf

    > Naše debata se týkala ověřitelnosti správnosti
    > kódu napsaného v jednotlivých jazycích a Lael
    > vyzdvihoval zejména nebezpečnost používání ukazatelů.
    A co ostatne zdroje v aplikacii ( napr. subory, sietove spojenia, databazove pripojenia ) ? Tam uz automaticke uvolnovanie zdrojov nefunguje, a programator na to musi pamatat. Ked je vsak zhyckany neuvolnovanim pamate, tak velmi casto zabuda upratovat tieto zdroje.

    Kvalita kodu je vzdy zavisla od programatora a jeho navykov. A v tomto pripade je kvalita na strane Linux-u, vdaka jeho otvorenosti a reviziam kodu.

  • 9. 3. 2009 9:13

    alblaho (neregistrovaný)

    Docela pěkný článek.

    Docela hezky ukazuje, proč raději než v C++ programuji v Pythonu. C++ je ohromná síla, ale její zvládání vyžaduje úsilí, které je dost často neúměrné.

  • 9. 3. 2009 12:53

    Raoul.Duke (neregistrovaný)

    Niekolko pripomienok, podla mna std::list neni ekvivalent python list, skor std::vector sa k nemu blizi kedze podporuje aj pristup k nahodnemu prvku (random access), dalej filter sa da spravit aj cez remove_copy_if() (s invertovanou podmienkou v isEven) a printList by som parametrizoval ako kontajner a nie ako polozku list-u...

    template
    void printList(T const &List, std::string const &desc = "List contents")
    {
    std::cout << desc << ": [";

    for(typename T::const_iterator it = List.begin(), end = List.end(); it != end; ++it)
    std::cout << *it << (it < end - 1 ? "," : "");

    std::cout << "]" << std::endl;
    }

    bool isEven(const int &i)
    {
    return !((i % 2) == 0);
    }

    int main(int argc, char* argv[])
    {
    std::vector l;
    l.push_back(1);
    l.push_back(2);
    l.push_back(3);

    printList(l, "Original list");

    std::vector out;
    std::remove_co­py_if(l.begin(), l.end(), std::back_inser­ter(out), std::ptr_fun(­isEven));
    printList(out);

    return 0;

    }

  • 9. 3. 2009 12:58

    Raoul.Duke (neregistrovaný)

    v printList() este jedna zmena aby fungoval aj na list a jemu podobne:

    ...
    for(typename T::const_iterator it = List.begin(), end = List.end(); it != end; ++it)
    std::cout << *it < 1 ? "," : "");
    ...

  • 9. 3. 2009 13:00

    Raoul.Duke (neregistrovaný)

    Nejak to zle poslal tak este raz:

    for(typename T::const_iterator it = List.begin(), end = List.end(); it != end; ++it)
    std::cout << *it < 1 ? "," : "");

  • 9. 3. 2009 15:52

    ivan (neregistrovaný)

    Bravo, takhle ma vypadat C++. Zadny Ccko s tridama. Bohuzel se toho porad spousta lidi boji a neveri kompilatorum. Zkuste treba porovnat zdrojaky maildropu a CUPSu. C++ je bohuzel prilis volny jazyk a ano da se v nem psat "bezpecne" a jedine co vas k tomu nuti je vase vlastni svedomi. V statnich jazycich tohle dostanene zadarmo, protoze proste jinak psat nemuzete a jako programator mate mnohem vice svazane ruce.
    Jinak bych mel jeste jedno doporuceni, vase sablona bere jako parametr pointer na fci - proto ji nemuzete predat poiter na metodu. Mozna by nebylo od veci udelat sablonu, ktera by misto pointru na fci dostavala jmeno tridy. Ta trida by implementovala jedinou metodu Run a byla by vnitrni trida toho kdo by vasi sablonu pouzival.

  • 9. 3. 2009 16:57

    Petr Pospíchal (neregistrovaný)

    Inspirující přístup :) Nicméně v praxi je podle mého názoru vhodnější mít něco "nad" uživatelem, co zajistí, že potenciálně děravý kód ani nemůže napsat (tj. například interpret nebo překladač do bytecode). Samozřejmě těžko si lze představit, že všechny programy budou psány v C#/Java/intepre­tovaných jazycích, stejně tak těžko si ale lze představit, že existující aplikace někdo přepíše do podobného stylu. Čili ano, sice se dá psát bez pointerů a jiných potenciálně nebezpečných konstrukcí, ale v praxi je to podle mě úplně nereálné a bezpečnější zůstává používat interpretované jazyky.

  • 9. 3. 2009 20:57

    inkvizitor (neregistrovaný)

    Moc se všem omlouvám, netušil jsem, že komentáře je nutné schvalovat. V předchozím blogovacím systému to nebylo. Ještě jednou omluva. :(

  • 9. 3. 2009 21:10

    inkvizitor (neregistrovaný)

    Všem děkuji za odpovědi a pokusím se teď odpovědět na otázky a námitky. Předem bych chtěl říci, že už asi 6 let neprogramuji v C++ a v době, kdy jsem programoval, se jednalo zejména o prostředí Visual C++ a MFC a proprietární prostředí se specifickými knihovnami. Knihovnu Boost neznám prakticky vůbec a STL poměrně málo. Pokud se někdo domnívá, že píšu z pozice supermachra přes C++, není tomu tak. Chtěl jsem se zaměřit na obecné koncepty a jsem si vědom toho, že možná trochu znovu vynalézám kolo. Zasvěcených připomínek znalců C++, STL a Boost si vážím a jsem za ně rád.

  • 9. 3. 2009 21:28

    inkvizitor (neregistrovaný)

    [1] Jak jsem napsal výše, Boost moc neznám. Šlo mi hlavně o ten obecný princip, takže doufám, že to nevadí. Možná je chyba, že jsem neuvedl, že se nejedná o ukázku ideálního řešení v C++, myslel jsem, že můj záměr je jasnější.

    [3,4] Jazyk Scala se mi velice líbí, protože podle mě daleko lépe řeší některé věci, které jsou v Javě kontroverzní (klíčové slovo protected), přidává lepší typovou kontrolu (variance), aktorový model známý např. z Erlangu atd. Je toho opravdu hodně. Ve Scale jsem se jal řešit problémy z projektu Euler. Ta hlavička je dost obskurní, ale jednodušší možnost neznám.

    [5] Já jsem získal dojem, že z prádelní šňůry je možné udělat velice pevné horolezecké lano. Chce to ale trochu úsilí navíc.

    [7] Ano, inspiraci funkcionálními jazyky nepopírám. Nadšený příznivec Lispu ale nejsem. Původně jsem chtěl dát příklad i v Common Lispu, ale když jsem zjistil, jakým způsobem navrhovali někteří programátoři implementaci funkce filter v CL, radši jsem to neudělal.

  • 9. 3. 2009 21:50

    inkvizitor (neregistrovaný)

    [8] Původně jsem chtěl tento seriálek zaměřit i na C, ale řekl bych, že tam jsou možnosti kontroly velmi ztížené oproti C++. Můj příkládek vlastně pojal C++ jako metajazyk, který umožňuje vybudovat bezpečnější základy pro "koncové uživatele". Myslím, že v týmu je možné si vynutit, aby méně bezpečné konstrukce používali pouze ti zkušení budovatelé "základu". Já sám nejsem zastánce konceptu "jeden jazyk vládne všem".

    [9] Ano, to je pravda, děkuji za opravu.

    [10] Rád bych k tomu překonání "iracionálního strachu" přispěl. Moje teze zní, že je možné analýzou kódu (zhruba ala lint) vytipovat problematická a potenciálně nebezpečná místa. K výsledku analýzy je možné se nějak postavit.

    [12] Já raději "šmrdám" třeba v tom Pythonu. Z ukazatelů mám respekt. ;)

    [13] Rád věřím, že používání STL může navodit neočekávané chování. Moje šablona funkce filter() ale podle mě pomáhá k tomu, aby řešení některých úloh bylo snadnější a aby těch potenciálních překvapení bylo co nejméně.

    [14] Já bych se spíš zeptal, co je na té funkci "unsafe". Podle mě je to stavební blok, který pomáhá lépe zhodnotit bezpečnost celého programu. Je jasné, že např. ta funkce add() by v principu mohla dělat cokoliv. Podle mě se to ale dá ohlídat. Co se týče podpory lambdy, někdo tady odkazoval na Boost, takže na to chci mrknout.

    [18] Pokud vím, tak myšlenka JavaOS (a Lisp machine atd.) tady už byla. Zatím se to moc neprosadilo, takže uvidíme.

    [20] A není ta moje implementace srozumitelnější a snadnější k používání? Možná není úplně obvyklá z hlediska programátora v C++, ale stejně mi obecně přijde lepší.

  • 9. 3. 2009 22:05

    inkvizitor (neregistrovaný)

    [23] Jasně, problematiku NP těžkých úloh jsme ve škole brali. Každý syntaktický analyzátor samozřejmě má svoje meze. Ale podle mého názoru mu lze pomoci a dojít tak k velmi dobrým výsledkům. V první fázi to může například zkusit a napsat "tohle psalo nějaké prase, já se v tom nevyznám".

    Co se týče C++, tak tam vidím problém v tom, že neobsahuje (pokud se to nezměnilo) konstrukci try-finally. Ta to řeší docela elegantně, ale kód je třeba samozřejmě psát rozumně. A když ne try-finally, tak automatické volání destruktoru by mohlo pomoci.

    [27] List v Pythonu je podle mě dost specifická záležitost. Lisp, ML, Scala apod. mají Array a List zvlášť a v mnoha případech ten "klasický" list úplně stačí a je snad i vhodnější. Napadlo mě, že by bylo namísto listu nějakým způsobem použít jeho předka.

    [31]Ano, to je otázka, zda použít třídu nebo funkci; já bych byl spíš pro funkci, ikdyž javisti mě za to asi proklejí. C++ každopádně umožňuje využít mechanismus přetěžování, takže myslím, že by bylo možné napsat dvě šablony pro oba případy.

  • 9. 3. 2009 22:07

    inkvizitor (neregistrovaný)

    Všem ještě jednou děkuji, pokud jsem někomu neodpověděl, znamená to, že s ním souhlasím nebo že si připomínku ještě nastuduju. Děkuju zejména Stenovi za obsáhlý příklad implementace a všem ostatním, kteří přispěli ukázkou nebo radou.

    To schvalování od nynějška budu brát poctivěji.

  • 9. 3. 2009 22:42

    JmJ (neregistrovaný)

    Inu zacal sem u basicu, pres pascal, assembler, C, C++ sem dosel k C#. V jazycich jako je C# se mohu soustredit na samotny algoritmus, muzu resit pomerne primo podstatu problemu a nemusi ztracet cas s blbostma jako je alokovani pameti, uvolnovani pameti, predavani ukazatelu na pole ukazatelu atd. Kod v C# je myslim docela jasny a citelny i pro dalsi lidi (jak tu jiz nekdo zminoval), kazde volani funkce nebo metody neni obaleni tunou maker a definice teto funkce neni obalena dvema tunami maker. Ja ty jazyky nezatracuju, ale proste kdyz sem shodou okolnosti minuly tyden dostal za ukol upravit uplne cizi kod aplikace vyvijene ve Visual C++, tak sem si pripadal tak trochu jako bedrich hrozny kdyz lustil egyptske pismo :-). Vlastni algoritmy se schovaly pod tunami kodu pro kod. Nemluve o mnozstvi knihoven, ktere jsou standardne v CLR k dispozici. Ano, vhodne knihovny si clovek sezene k leccemus, ale tady proste jsou a jsou snadno pouzitelne, coz opet umoznuje soustredit se na problem a ne na blbosti kolem.

    Nechci tvrdit, ze C# je to jedine prave.

  • 9. 3. 2009 23:28

    Sten (neregistrovaný)

    [33] Práce bez přehazováním pointerů a jiných nebezpečných konstrukcí je v C++ docela dobře možná. Musí se ale vědět jak. V případě C# to za programátora řeší překladač a virtuální stroj, čili programátor nepotřebuje znát detaily. Na druhou stranu pak má daleko víc svázané ruce, co může jeho kód dělat.

    [37] To je právě ten problém C++, na který asi i poukazoval Lael Ophir (a Yenya a další). Spousta programátorů totiž v C++ programuje tak, jak je zvyklá z jiných jazyků (C, Python, Java ap.), což pak má za následek, že odjištěná zbraň ukazatelů, přetékajících hodnot (jako ten int i v printList - prosím nahradit za std::list<T>::si­ze_type) a minimálních kontrol v STL (v tomhle je „oblíbený“ operator[]) přinášejí těžko odhalitelné chyby, které se projeví, až když aplikace dostane opravdu zabrat. Což bývá až u zákazníka. (Mimochodem ani ta moje ukázka není z hlediska C++ programátora ideální - šlo by použít Boost, upravit funkci filter, aby nebral jen funkci, ale cokoliv volatelného, třeba funktor a ten operator << pro std::list by šlo implementovat obecně pro všechny kontejnety.)

    [40] Přesně argument který jsem tu už jednou vyvracel: špatní programátoři nedělají špatný jazyk, jen špatný kód (to je narážka na to obalování funkcí marky a schovávání kódu pod kódem pro kód). Podle postupu v jazycích, který jste provedl, to vypadá, že vám C++ nesedlo. Zřejmě jste na něj oproti C nabalil jen třídy. To je ale věc, ve které C++ moc nevyniká (ačkoliv se to často tvrdí). A co se týče alokování paměti a předávání ukazatelů - vám to C++ opravdu nesedlo :) No nevadí, hlavně že jste našel jiný jazyk, který vám vyhovuje.

  • 11. 3. 2009 0:07

    Miloslav Ponkrác (neregistrovaný)

    Jaký má vlastně smysl zakázat komentáře bez schvalování a několik dní se vykašlat na schvalování?

  • 11. 3. 2009 0:17

    inkvizitor (neregistrovaný)

    [45] Smysl to samozřejmě nemá žádný. Myslel jsem, že jsem to (i s omluvou) vysvětlil v komentáři č. 34 - nutnost schvalování komentářů považuji za nesmysl a nikdy bych to tak nenastavil; že tak byl účet přednastaven, je věc jiná. Problém je, že pokud nejdete do administrace blogu ani do mailu, nezjistíte, že pod článkem komentáře jsou. Zkrátka mi to uniklo, což neznamená, že jsem se na to vykašlal. Celou neděli jsem byl pryč a v pondělí v práci.

  • 11. 3. 2009 0:19

    inkvizitor (neregistrovaný)

    [45] podruhé: blog.root.cz přešel před časem na systém Wordpress a předtím se mi ty komentáře pod článkem zcela určitě přidávaly bez moderace.

  • 1. 4. 2009 17:48

    D.A.Tiger (neregistrovaný)

    Nevím, jak vy, ale já si dávno všiml, že pan Ophir strašně rád předhazuje mýty (nebo věci které nejsou již roky aktuální) jako fakta, vaše protiargumenty překroutí k nepoznání. Nakonec nechápu co se řeší - stačí se podívat na správy o bezpečnosti ve Windows, Linuxu / Unixu a je jasno.

    Naprosto souhlasím se Stenem, že špatný/dobrý program nedělá zvolený programovací jazyk, ale programátor. Bez ohledu na tom, zda používáte BASIC, Perl, C++, nebo C#.

    Omlouvám se všem koho teď naštvu, ale argumenty typu "C# je lepší, protože se nmusím soustředit, na takové věci jako je správa paměti, atp..." jsou prostě k smíchu. Ano v C++ si o paměť musíte říct, a co? Zavoláním operátoru new a delete, které vše potřebné vyřeší za Vás? To je opravdu tak složité? Nemluvě o tom, že oba operátory lze přetížit a tím i přizpůsobit ke svým potřebám a takovou situaci řeší např. knihovna loki (alokaci malých oběktů).

    A to se ani nezmiňuji o tom, že existuji takové věci jako šablony, inteligentní ukazatele, továrny na oběkty, typové seznamy ... atd. s jejichž pomocí lze spoustu funkcionalit z jiných jazyků do C++. Stačí se pouze rozhlédnout (např. loki, boost, STL).

    C++ je typový jazyk a to je jeho největší síla a výhoda... Někdo to může vidět jinak. Nic proti, ale řeči o tom, že něco je napsáno v C/C++ a proto je to míň bezpečné nebo použitelné než například to co je napsáno v C# jsou nehorázné žvásty a nechápu jak je může někdo brát vážně (Pomalu zní jak středověké obvinění z čarodějnictví). Zvlášť pokud jdou z klávesnice pana LO.

  • 2. 4. 2009 14:58

    Lael Ophir (neregistrovaný)

    [48] Nepřijde vám divné, že máme dnes v celém IT průmyslu děravé kernely, toolkity, browsery, emailové klienty, DNS servery, DB servery, přehrávače multimédií, komprimační programy, knihovny pro práci s obrázky, prohlížečky rlzných formátů atd? Proč se to asi stalo? Já vám to řeknu. Programátoři prostě dělali, dělají a budou dělat chyby, to se nedá změnit. Někdy kvůli tomu selže raketa Ariane, jindy to zaplatí životem omylem ozáření pacienty.

    Příčinu odstranit nelze. Jediným řešením je tedy omezit NÁSLEDKY. Například tak, že budeme používat jazyky, které nemají nebezpečné konstrukce specifické pro C/C++. A pokud to do budoucna otevře možnost zaručovat parametry kódu, bude to opravdová revoluce v bezpečnosti a spolehlivosti SW.

    Když jsme u správy prostředků v C/C++. Kdyby taková spousta programů neměla resource leaks, tak bych vám věřil, že je to není problém. Jenže on je to velký problém.

    Celkem mě překvapuje, že se místo hledání cesty jak psát bezpečnější SW omezíte na konstatování "je to o programátorech". Jistě, je. Jsou tam venku, a dělají chyby. Vaše tipy na řešení? No nic...

  • 2. 4. 2009 16:49

    D.A.Tiger (neregistrovaný)

    [49]
    " Nepřijde vám divné, že máme dnes..."
    Nepřijde. souhlasím v tomto bodě s vámi. Je to smutné, ale až lidé přestanou dělat chyby, tak už nebudou lidmi. To už potom bude fakt stát za ...

    "Jediným řešením je tedy omezit NÁSLEDKY."
    A není rovnou lepší než investovat do drahého omezování a odstraňování následků, vedení svatých válek za "jedinou pravdu" (správný compiler, systém, web server, dosate si co je vám libo) poučit se z chyb které nastaly a v tom co umím nejlépe se jich vyvarovat? Není rovnou lepší než toto všechno dělat to co umím nejlépe, než vést svatou válku proti těm kteří to umí nejlépe něco jiného? Není rovnou lepší NĚCO DĚLAT, NEŽ ŽVANIT NESMYSLY A VYVOLÁVAT HÁDKY O DEBILATÁCH, KTERÉ JSOU NA ÚROVNI TAK 3-LETÉHO ŠIMPANZE, a ne dospělého člověka v 21. stol.?

    kolik je lidí (programátoru) tolik bude vždycky pohledu na toto. Neexistuje žádné oběktivní měřítko, které by stoprocentně určilo který jazyk je lepší a který ne. Vždy to bude zas konkrétní člověk / lidé u konkrétního projektu, kteří to rozhodnou. Žádná oběktevní pravda neexistuje a vše je relativní - nemá ji ani váš bůh Gates.

    "Celkem mě překvapuje, že se místo hledání cesty jak psát bezpečnější SW omezíte na konstatování "je to o programátorech". Jistě, je. Jsou tam venku, a dělají chyby. Vaše tipy na řešení? No nic..."
    Mě zas nepřekvapila tato vaše - poněkud standardní - reakce. Kompletně překroutit argumenty oponenta. Ano je to o programátorech. A moje řešení? Velice jednoduché - Programátoři chyby dělají, ale měli by se z nich poučit a už je neopakovat. Jenže ono je vlastně jednoduší svést to na jazyk... IMHO a jsme u toho. Zavedl bych ještě pojemy IT-Alibizmus a IT-Rasizmus...

  • 3. 4. 2009 6:06

    Lael Ophir (neregistrovaný)

    [50]
    OK, shodneme se, že programátoři dělají chyby. Šimpanze a váš další folklór s dovolením přeskočím. Jen si dovolím krátké konstatování, že abyste neměl pocit, že jde o další útok na vaši skvělou osobu (a nežvanil o šimpanzích), tak bych zřejmě musel bych skandovat něco pozitivního o C/C++, poplácávat se s vámi po rameni, a bezvýhradně s vámi souhlasit.

    Jaký jazyk je lepší, to nebylo předmětem diskuze. V diskutované věci je hlediska bezpečnosti a bezchybnosti aplikace je poměrně jedno, jestli použijete C#, VB.NET, Javu, nebo něco s podobnými parametry. Mě se osobně líbí C#. Jestli se někomu líbí F#, neleze mu z toho mozek ušima, nevadí mu nedostatek dokumentace (.NET Framework je dokumentovaný pro C#, VB.NET a občas J#), příkladů a tutorialů, tak mu to přejme.

    Programátoři měli desítky let, aby se poučili z minulých chyb. Nepovedlo se, a SW je pořád děravý a nebezpečný (podobně se z minulých chyb nepoučili třeba řidiči). Takže asi fakt nezbývá, než minimalizovat následky chyb programátorů. A pokud mluvíme o minimalizaci následků, tak nelze než se shodnout, že managed prostředí (.NET, Java) je krokem správným směrem od C/C++.

  • 3. 4. 2009 9:04

    D.A.Tiger (neregistrovaný)

    Och pane Ophire, asi máte jako obvykle problémů s chápáním elementárních logických principů a se čtením. Narážka na šimpaze měla pouze konstatovat co si myslím o obdobných diskuzích ;) Takže i velmi nechápavému jako jste vy : Bude mnohem užitečnější, když budete něco v tom vašem C# dělat, než vyvolávat diskuze na výše zmiňované úrovni. Bohužel za dobu vašeho působení na Rootu pochybuji, že na něco takového máte a vůbec to pochopíte.

    "Jaký jazyk je lepší, to nebylo předmětem diskuze..." Nepovídejte. Nikdo si neumí tak hezky protiřečit v jednom odstavci jako vy. Takže tvrzení že v C# napíšete explicitně bezpečnější program než v C++ není defakto řečeno, že C# je lepší?

    "Programátoři měli desítky let, aby se poučili z minulých chyb..." A zjišťoval jste někdy v čem ty chyby jsou? Udělal je preprocesor/kom­pilátor/linker (tedy aniž by je tam zas nezanesl člověk)? Aha... Takže když programátoři mohou být nepozorní, dělat chyby (jako konec konců každý člověk) a hlavně jsou to pořád lidé - takže nebudou nikdy schopni předvídat všechny problémy ke kterým může potencionálně dojít. A Murphyho zákony schválnosti snad znáte, ne?

    Takže vaše řešení zní: Abychom minimalizovaly pravděpodobnost chyb donutíme programátory používat takové jazyky, které budou většinu podstatných věcí (správa zdrojů, atp...) řešit automaticky. Sice je tím omezíme, sebereme jim tím možnost pružně reagovat na neočekávané události - nebo pokud se najde lepší řešení, v daném případě použit to. Nehledě na to, že pokud se týče neočekávaných událostí je každý automat v podstatě v řiti. Ale to nevadí - já a MS jsme přesvědčeni o tom že je to tak správně, takže to bude správně pro všechny... Bravo! To je ta správná cesta do binárních pekel. A nebo se můžeme vrátit ke starému dobrému Basicu... To je skoro stejný přístup ;) A vlastně když už to tak vezmu, C# se nejvíce - pokud je mi známo - uchytil právě ve Windows. Tak by mě zajímalo proč je v něm tolik chybného software (včetně samostatného systému) :P

    Moje řešení zase zní - co nejlépe se naučit jeden, dva programovací jazyky (jeden který danému člověku vyhovuje a jeden který se používá řekněme nejčastěji), pracovat na jejich zdokonalování prostředky které nabízí, dělat chyby a pak se z nich učit a zveřejňovat je. Pracovat na stírání platformních nekontabilit a podobných problému, Nahlašovat Bugy v aplikacích a pokud to jde a je trochu v mých možnostech a silách snažit se spolupracovat na jejich odstranění.

    Jak Windows, tak Linux/Unix mají plno jiných problému které je nutno řešit a na nich pracovat, než vést kilometry dlouhou svatou válku o hovadinách. A ty by se měly řešit.

    Poslední věta je buď absolutně holý propagandistický nesmysl, nebo pouze vyjádřením vašeho názoru, který je z globálního hlediska prostě irelevantní (proč to jsem už vysvětloval v minulé reakci, ovšem to by se někdo musel naučit číst. )

  • 3. 4. 2009 13:56

    Lael Ophir (neregistrovaný)

    [52]
    C# je jednoznačně bezpečnější, než C/C++. Jazyk bez pointerů je typicky bezpečnější, než jazyk s nimi. Jaký jazyk je lepší, to záleží na kontextu. Pro každou platformu to typicky bývá jazyk, který na ní má nejlepší podporu (C# na Windows, Objective C na MacOS, C/C++ na unixech). To ovšem vůbec nevylučuje, že pro danou aplikaci na Windows bude nejlepší C++, nebo cokoliv jiného. Například kernelové drivery v C# ve Windows psát nejdou.
    C# se pochopitelně uchytilo nejvíc ve Windows, protože je to primární jazyk pro .NET Framework. S chybným SW to nemá souvislost.

    Několikrát jsem psal, že nejsem programátor. Přesto jsem za posledních pár měsíců musel něco napsat. Diskuze na zmíněné téma jsou (pravda ne na rootu) důležité pro budoucnost IT jako oboru. SW je čím dál složitější, je ho čím dál více, a nebezpečnost a nespolehlivost SW má potenciál ohrozit celý obor. Ojedinělé případy s velikými materiálními škodami i ztrátami více životů už máme také.

    Nemusím dohledávat analýzy, abych vám řekl, že buffer overflow chyby dodnes způsobují velké procento bezpečnostních problémů. Přitom jejich mechanismus byl pochopen někdy v roce 1972. 37 let poté, a problém je to pořád. Nepoučili se, a nepoučí se. Řidiči se také nepoučili, a pořád havarují. Programátoři i řidiči totiž budou VŽDY dělat chyby.

    Nemyslím si, že by použití managed prostředí ubíralo možnost reagovat na neočekávané události. V C/C++ je často praxe taková, že se nepoužívají výjimky, a musíte po volání vždy ověřovat návratovou hodnotu (viz typicky libc). Faktem je, že to většina programátorů nedělá důsledně, takže programy na neočekávané věci (třeba neočekávané vstupy) reagují v lepším případě core dumpem s chybou "nelze zapsat adresu 0x0c" apod. V horším (ale přesto častém) případě reagují tichým přepsáním nějaké části vlastní paměti, následným zcela záhadným chováním, nebo dokonce spuštěním nežádoucího kódu.

    To, co nabízíte jako řešení vy, je jen pokračování současných problémů. Jak jsem psal výše, programátoři ani řidiči se nepoučili a nepoučí, chybovat budou dál. Hlásit bugy je jistě třeba, ale bohužel to není řešení *příčiny* problému. Když řidiči často havarují, asi nebudete jen zlepšovat lékařské a pohřební služby, ale budete to také řešit úpravami vyráběných vozů (volant nemusí pravidelně končit v žaludku řidiče), airbagy, ABS, VSC atd. Jinými slovy budete minimalizovat následky chyb, kterých se řidiči budou vždy dopouštět. Samozřejmě to neznamená, že díky tomu přestane být potřeba opatrnost a odpovědnost řidiče. Ale při troše štěstí to umožní udržet či snížit počty těžce zraněných a mrtvých ve stále houstoucím provozu.

  • 3. 4. 2009 15:57

    D.A.Tiger (neregistrovaný)

    --"C# je jednoznačně bezpečnější, než C/C++. Jazyk bez pointerů je typicky bezpečnější, než jazyk s nimi."
    Typicky žádný jazyk bez pointerů neexistuje. Pointery (ukazatele - v podstatě nic jiného než adresa hodnoty/oběktu v paměti) jsou minimálně používané skrytě programovacím jazykem, popřípadně přímo v binárním kódu po kompilaci - jak už tady někdo upozornil.

    Pokud bych potřeboval z nějakého důvodu skrýt adresu nějaké proměné, či zacházet s takovýmto pointerem "bezpečně" v kontextu kódu C++, existuje hned několik možností jak to provést, včetně tzv. inteligentních ukazatelů (díky nímž se mimochodem dá velice jednoduše implementovat podobná správa paměti, jakou zajišťuje např. tzv. garbage collector), které všechny potencionálně nebezpečné operace schovají ve své implementaci a navíc se zhlediska kódu chovají jako klasické ukazatele (popř. i reference). Většinou jsou implementovány jako tzv generické třídy, takže je lze typově bezpečně a plně přispůsobit dané situaci, a žádným způsobem se neprojevý (či jen velmi minimálně) na výsledném výkonu či oběmu projektu. Nemusím je ani implementovat, protože to už udělala spousta lidí předemnou (už jsem tu zmiňoval loki, nebo boost - co mě momentálně napadá a které sám používám, avšak existují i jiné). Obdobně je to i s jinými features jiných jazyků a C++. (Mimochodem všichni takový flameři zapomínají ještě dodat, že nebýt C a obvzláště C++ - jeho možnosti tvorby velmi sofistikovaných abstrakcí, kde se bez vlastní zprávy prostředků a pointerů neobejdete, žádný C#, java, atpd. by asi ani neexistoval)

    --"Jaký jazyk je lepší, to záleží na kontextu."
    To je jen účelové překroucení, nemá ani smysl se k tomu nadále vyjadřovat.

    --"C# se pochopitelně uchytilo nejvíc ve Windows, protože je to primární jazyk pro .NET Framework. S chybným SW to nemá souvislost."
    Zase si protiřečíte. Psal jste (volně řečeno, takže si laskavě odpusťte vaše slovíčkaření), že většinové nasazení C# by mělo - díky jeho konstrukci - vést k potencionálně bezpečnému kódu aplikací a eliminovat důsledky chyb omylů programátorů. Pokud (díky platformě .NET ) byl tento jazyk tolik rozšířen převážně na Windows, pokládám otázku proč se toto neprojevilo a naopak se zdá, že chybovost aplikací (včetně vámi zmiňovaných zákeřných, nebo neidentifikova­telných chyb) je stále stejná? Máte samozřejmě pravdu - s použitým jazykem to nesouvisí, jen mi připadá, že jste ochoten to připustit jen tehdy, když se vám to hodí do krámu. Takže ano, ale pak kdo/co je na vině?

    Moje odpověď zní : Chyby programátorů, nerespektování pravidel a zásad platných v daném systému a jazyce, benevolentnost systému jako takového, hloupá a najivní představa, že se o něco postará systém/nebo někdo jiný (říká se tomu různě: nezodpovědnost, důvěřivost, nebo taky blbost - typická to lidská vlastnost).

    --"Nemusím dohledávat analýzy, abych vám řekl, že buffer overflow chyby..."
    IMHO za tuto chybu může vždy nepozornost či omyl programátora - ne jazyk. Viz výše. Mimochodem, od toho jsou v C++ STL konteinery (a nejen ty), které nabízejí bezpečnější a sofistikovanější způsob práce s datovými poly. Každý programátor, který přesto použije klasická pole moc dobře ví, že C++ nekontroluje jejich přetečení/pod­tečení. Tím pádem bere odpovědnost za ně na sebe (někde jsem slyšel, že neznalost zákona neomlouvá). Prostě je to stejné jako s těmi pointery, jen je jednoduší to svést na špatný jazyk - jak jsem říkal IT-Alibizmus.

    --"Nemyslím si, že by použití managed prostředí ubíralo možnost reagovat na neočekávané události...."
    Já ano - nepochopil jste to. Už jen proto, že v C++ nejsem omezen strojem, který rádoby myslí za mě a proto mohu reagovat na různé požadavky (z hlediska výkonu výsledného projektu, zprávy systémových prostředků, hardvarové platformy a specifik cílového stroje, atpd...) mnohem flexibelněji - aniž by mi do toho někdo kafral. Je zcela na mém výběru a uvážení zda využiji již existující řešení, nebo implementuji své vlastní a převezmu za něj plnou zodpovědnost. (A řek bych dal krk za to, že tohle je ten hlavní důvod proč se některým lidem C++ nelibí a radši se vzdají těchto možnosti, a mnohem výší míry flexibility při návrhu a implementace projektu... Že jsem se trefil? ;) ).

    --"Faktem je, že to většina programátorů nedělá důsledně, takže programy na neočekávané věci (třeba neočekávané vstupy) reagují v lepším případě core dumpem s chybou "nelze zapsat adresu 0x0c" apod. V horším (ale přesto častém) případě reagují tichým přepsáním nějaké části vlastní paměti, následným zcela záhadným chováním, nebo dokonce spuštěním nežádoucího kódu."
    Někde jste sám psal, že prý Linux nepoužíváte a nijak podrobně nesledujete. Můžete mi tedy říci, kde berete tu drzost tady šířit FUDY o tom, že Linuxové aplikace padají (a hlavně jak?). Krom svých projektů (kde jsem udělala chybu já sám) a testů windowsáckých aplikací pod Wine jsem už dlouho neviděl pád nějaké stable aplikace (Nepadají mi kupodivu ani moje vlastní odladěné aplikace). A to že já jim dávám někdy pěkně zabrat. Takže zase tvrdíte věci, které nemáte ověřeny?

    --"To, co nabízíte jako řešení vy, je jen pokračování současných problémů..."
    Do jisté míry ano. Jenže já bohužel jiné řešení nevidím. Všechno od polovodiče po OS (včetně programovacích jazyků a programů) dělají lidé. A dokud se nezmění lidé, nezmění se ani nynější situace a ani její řešení (pře sebe lépe navržený kompilátor). Já preferuji C++ a to se asi hned tak nezmění (přesto, že jazyků znám řadu - minimálně v základech, programováním si přividělávám opravdu jen příležitostně, ale programy a scripty píšu dost často) Za vnucováním jedné jediné pravdy (o tom jsem koneckonců už říkal) vidím pouze fanatickou zaslepenost, nebo prasácké finanční zájmy...

  • 3. 4. 2009 16:46

    Lael Ophir (neregistrovaný)

    [54]
    C# ani Java nemají konstrukci typu pointer, to je prostý fakt. Že kompilátorem vygenerovaný kód pointery interně používá (protože jde nakonec o strojový kód), to je v kontextu naprosto nepodstatné. Rozdíl je v tom, jestli vám jazyk dovolí jako pointer předat kdejaký nesmysl, nebo jestli vyžaduje zapouzdření typu .NET delegate, které chyby programátora při manipulaci s pointery vylučuje. Ve vhodně nastaveném prostředí tak můžete vyloučit nejběžnější chyby, podobně jako jsme úpravami automobilů zabránili těm volantům často zakousnutým do břicha.

    Samozřejmě můžete vymyslet konstrukce, které zvyšují bezpečnost kódu psaného v C/C++. Bohužel je to ale marná snaha, protože nemůžete VYNUTIT jejich používání. Když použijete smart pointers, přesto stačí jediné nesprávné použití klasického pointeru, nebo jediné nesprávné použití strcpy, a iluze bezpečnosti je v háji. A tomu aby autor kódu použil nebezpečnou konstrukci namísto bezpečné v C/C++ prostě nezabráníte.

    Ohledně bezpečnosti, spolehlivosti a C# si nijak neprotiřečím. To jen vy stavíte na chybných předpokladech. Veliké procento kódu pro Windows je napsané v C++, včetně samotných Windows. Pokud uvedete další aplikaci v C#, počet chyb v C++ aplikacích (a v systému psaném v C/C++) tím nijak nesnížíte.

    Nemá smysl objevně konstatovat, že buffer overflow je chyba programátora. Za chybu v kódu může programátor. Ovšem také víme, že ze své podstaty chybu nakonec vždy udělá, a že bude chybovat poměrně často. Můžeme buď alibisticky říkat "ale za to může programátor" a nic s tím nedělat, nebo mu dát takové nástroje, které buffer overflow vyloučí. Vy jste pro tu první možnost, já pro druhou. První možnost byla zkoušena desítky let, a problém zjevně neřeší. Druhá možnost problém prokazatelně řeší.

    V C++ jste samozřejmě také vždy omezen strojem. V ASM jste omezen méně, a v čistém strojáku nejméně. Otázkou je, jestli chceme co nejvíce možností, nebo funkční a spolehlivý SW. Jako zástupce zákazníků říkám, že možnosti pro autory kódu musí ustoupit funkčnosti a bezpečnosti. Ustoupili jsme jednou, když průmysl přešel od ASM v C/C++. A ustoupíme znovu, a bude to dobré pro IT.

    Je úplně jedno, jestli se bavíme o Linuxu nebo o Windows. Nespolehlivé a nebezpečné aplikace jsou dnes na všech platformách. A jestli myslíte, že aplikace je spolehlivá a bezpečná, když v ní budete opakovat svých pár naučených kroků, tak se šeredně mýlíte. No a ohledně bezpečnosti je to katastrofa už dlouhá léta. Webové browsery, které zpracovávají hloupých pár set tagů, jsou zjevně děravé jako řešeto. Emailoví klienti, kompresní a dekompresní utility, kodeky, knihovny pro imaging atd. - chyby jsou všude kolem. Jestli je nevidíte, máte klapky na očích.

    Já vám pravdu nevnucuji. Klidně piště dál v C/C++, a věřte tomu, že se uhlídáte, a žádnou chybu neuděláte. Jenom vám musí přijít divné, kde pořád vznikají ty chyby včetně buffer overflow v OS, frameworcích, DB enginech, desktopových aplikacích atd. Všichni ti profíci se přeci měli dávno poučit, stejně jako se měli poučit řidiči ;).
    Když někdo propaguje opatření ke zlepšení situace, které zjevně řeší některé chyby (včetně buffer overflow), umožňuje do budoucna dát záruky na kvalitu kódu, a jaksi mimochodem také zvyšuje produktivitu práce programátora, tak mu prostě řekněte, že je za tím jeho zaslepenost nebo finanční zájmy. Musíte nějak ukázat, že si nevidíte dál, než na špičku vlastního nosu.