Hvor mange sikkerhedshuller forsvinder med mere sikre programmeringssprog?

Programmører er ikke ufejlbarlige, men i dag er teknikker, der kan hjælpe programmørerne med at skrive sikker kode, efterhånden blevet gængs standard.

Moderne programmeringssprog bruger i høj grad teknikker, som forhindrer programmøren i at introducere nogle af de sikkerhedshuller, som har givet problemer i årtier. Men selvom sprogene hjælper programmørerne, så er det ikke alle sikkerhedshuller, der forsvinder ved at programmere mindre i C++ og mere i Rust.

En af de type fejl, som mange sprog efterhånden sørger for at minimere eller helt eliminere, er typefejl. Det vil sige, at et program eksempelvis forventer at skulle behandle et heltal, men får leveret en tekststreng.

Problemet med typefejl er, at de kræver analyse af, hvad programmet gør og dermed vil forvente af input. Syntaksen i programmet kan være korrekt, men ved kørsel vil det give en fejl. Derfor benytter man i dag sprog med statiske typer. Det vil sige, at når noget skal være et heltal, så vil det kun kunne være et heltal.

»Med statiske typer får man ingen typefejl ved kørsel. Det ligger alt sammen i semantikken,« siger professor Olivier Danvy fra Institut for Datalogi ved Aarhus Universitet til Version2.

»De fleste moderne sprog tillader ikke automatisk konvertering mellem typer,« påpeger lektor Torben Mogensen fra Datalogisk Institut ved Københavns Universitet til Version2.

Læs også: Funktionelle sprog er tilbage efter års automatisk brug af objektorientet programmering

Tanken bag er, at man skal komme så tæt på at kunne forudsige programmets opførsel, når det afvikles.

Visse simple programmer kan man bevise, hvordan de vil opføre sig, men for den software, man i praksis udvikler, vil det være en uoverkommelig opgave. Derfor har man siden datalogiens barndom arbejdet med forskellige tiltag for at forhindre kritiske fejl.

Eksempelvis arbejdede de første udgaver af Lisp med en anden tilgang til problemet med typer, nemlig dynamiske typecheck, som først sker under kørslen af programmet, men hvor programmøren bør tage højde for, hvad der sker, hvis der opstår en typefejl. Fortran, som blev skabt i samme periode i slutningen af 1950'erne og begyndelsen af 1960'erne var derimod med statiske typer.

Garbage collection rydder op i hukommelsen

Senere kom et sprog som ML til og introducerede en funktion, som i dag er udbredt i nyere sprog, nemlig garbage collection. Det er en funktion, der hjælper med at rydde op i hukommelsen for henvisninger og data, der ikke længere bruges af applikationen.

»ML-skaberen Robin Milners store bedrift var at skabe et sprog med garbage collection, som aldrig kunne lave en typefejl,« siger Olivier Danvy.

Typesikkerheden i ML kom fra en særlig algoritme, der kunne udlede den korrekte type for en variabel. Dermed endte ML med at blive et sikkert sprog, der også er blevet anvendt i datalogiundervisningen i mange år.

Garbage collection ramte for alvor mainstream-programmering med Java, hvor det var én af de ting, som i begyndelsen fik især udviklere fra C og C++ til at kritisere Java-programmer for at køre for langsomt.

Erfaringen med garbage collection har imidlertid været, at den eliminerer et problem, man ellers kunne løbe ind i med netop de på daværende tidspunkt populære sprog.

»Det kan være et problem i C, når man frigiver noget lager. Hvis man ikke bruger garbage collection, skal man sikre, at man ikke peger på noget lager, der er frigivet,« siger Torben Mogensen.

Hvis man har fortalt systemet, at et område i hukommelsen ikke skal bruges længere, men stadig har noget, der peger på området, og senere prøver at læse fra det, så kan man ende data, der ikke hører til i applikationen. Omvendt kan man fjerne en henvisning til et område i hukommelsen, men ikke slette den. I så fald kan man ende med, at de ikke-slettede data ender et forkert sted.

Sproget Rust holder styr på henvisninger

Nyere sprog som Rust forsøger at løse problemet uden garbage collection ved i stedet at holde nøje styr på alle henvisninger til hukommelsen.

De fleste af de sikkerhedsproblemer, der kan opstå under kørslen af et program hænger sammen med, at programmet får nogle input, det ikke er beregnet til at håndtere. Det gælder eksempelvis for webapplikationer, hvor SQL-injektion længe har været et problem.

SQL-injektion opstår, når applikationen kan modtage en tekststreng, hvor det er muligt at inkludere SQL-kommandoer, som bliver fortolket og udført af applikationen. Det løser udviklerne typisk ved hjælp af forskellige former for inputvalidering, men der findes også tiltag i sprogene til at mindske risikoen.

»I Java bliver det kodet som en streng, der indeholder både data og nøgleord. Men i for eksempel C# har man Linq, der bruger en særlig syntaks til at sørge for at adskille data fra nøgleord,« forklarer Torben Mogensen.

Flere sprog kan også i et vist omfang begrænse risikoen for forskellige typer bufferoverløb ved eksempelvis automatisk at udvide en buffer. Et bufferoverløb opstår typisk, når man forsøger at kopiere en stump data, der er større end det område, der er afsat til at kopiere dataene til.

Derfor er de særligt problematiske i sikkerhedssammenhænge, fordi de ofte kan fremprovokeres ved at få en funktion til at kopiere en inputdatamængde, der er for stor til bufferen.

Nyere compilere som eksempelvis dem baseret på LLVM benytter forskellige metoder til at undgå, at bufferoverløb kan udnyttes til at kompromittere et system.

Tips og korrekturforslag til denne historie sendes til tip@version2.dk

Kommentarer (31)

Baldur Norddahl

Glemmer du ikke at svare på spørgsmålet? Hvor mange sikkerhedshuller...

En anden ting er at det ikke var Java der gjorde garbage collection (spildopsamling på dansk) populært. Faktisk har næsten alle sprog en form for spildopsamling og det er C og C++, der som de to eneste populære sprog, der er undtagelsen. Og mange C++ programmer bruger biblioteker til at styre lageret, så det meste er automatisk.

Rust har ikke spildopsamling men benytter statisk analyse og en nyskabelse kaldet pointer udlån til at styre allokering og frigivelse af hukommelse.

Det efterlader C som det eneste mainstream sprog hvor det er almindeligt med helt manuel styring af lageret.

Ivan Skytte Jørgensen

Jeg tvivler på at Torben Mogensen præcist sagde:

I Java bliver det kodet som en streng, der indeholder både data og nøgleord

Alle fornuftige libraries (inkl. dem tilJava) understøtter prepared statements, og hvis folk ikke bruger dem, så bør de piskes med brændenælder.

Mads Buch

Jeg lavede for noget tid siden et blog indlæg om bevisførelse for programmer. Helt konkret har jeg bevist at 2 implementationer af Fibonacci altid opfører sig ens.

Hvis nogle er interesseret i at se hvordan sådan noget bevist software ser ud, skal i være meget velkommende:

buchi.dk/blog/100-days-of-fibonacci-day-7-coq

Det er iøvrigt også materiale der indgår (indgik?) i Olivier Danvy's kursus om funktionelle programmeringssprog på AU.

Kim Nielsen

Tænk, jeg kan huske Cobol og Working Storage Division. Og ANSI-Fortran med fast in- og uddata validering (datatype fejl kunne ikke opstå) - men det er vist længe siden..

Johnnie Hougaard Nielsen

Tænk, jeg kan huske Cobol og Working Storage Division.

Du mener vist Working-Storage Section :-)

Men med Cobol kan det give grusomme fejl at være sjusket med at bruge (og skrive) til det forkerte record layout i File Section. Store muligheder for datatype-fejl. For slet ikke at tale om index til occurs-strukturer, eller kald af underprogrammer med forkerte parametre. Også uden selv at rode med pointere (som efterhånden blev mere udbredt, især under CICS), kan der gå mange ting galt.

Jan Rasmussen

Jeg startede mit hoppy projekt i C+SDL få at være cool og fandt hurtigt ud af det var crap med maclloc/free/const char */ no classes/no template/no overloading/no virtual functions o.s.v.

Jeg opgraderede til C++ og SFML og udskiftede til new/delete men efter at have set Bjarne Stroustrup på slap line er alle naked pointers+new/deletes fjernet og jeg bruger nu kun std::vector/std::map/std::unique_ptr + scope termination og har derfor ikke brug for Garbage Collection, og som nybegynder kan jeg ikke lave nogle fejl i memory management afdelingen.

Takket være C++ exceptions er debugging blevet elimineret til småfejl i filnavne på ressourcer, noget jeg måtte bruge en del tid på i C der bare hang fast.

gsl::owner(T) er vel mere i samme retning, hvis man har brug for 'nøgne ejerskabs pegepinde'
https://www.youtube.com/watch?v=1OEu9C51K2A&t=29m38s

Bjarne bliver spurgt om han vil tage noget af æren for 'Heartbleed' da buffer overflow er med i hvad folk tro C++ er...
https://www.youtube.com/watch?v=86xWVb4XIyE&t=77m38s

Bjarne bebrejder (som jeg opfatter det) Linus Torvalds der har får en hel hær af newbies til at tro at det er cool at programmere som i 70's

Jeg vil personlig hellere bruge mere tid på C++14/17 ind at begynde på et nyt sprog, specielt taget i betragtning hvor meget C++ litteratur/web-sites/video/mennesker/biblioteker/kompilere/IDE's der findes til C++ vs Rust, m.fl.

Jeg føler ikke jeg har brug for flere støttehjul på cyklen.
Der er selvfølgelig måske noget andet når der er mange penge/præstige på spil.

Baldur Norddahl

Jeg vil personlig hellere bruge mere tid på C++14/17 ind at begynde på et nyt sprog, specielt taget i betragtning hvor meget C++ litteratur/web-sites/video/mennesker/biblioteker/kompilere/IDE's der findes til C++ vs Rust, m.fl.

C++ og Rust er ikke direkte konkurrenter. Rust sigter på at erstatte C, men ikke så meget C++ eller andre højniveau sprog.

Der er situationer hvor du kan bruge C og Rust men hvor C++ kommer til kort. Det er systemprogrammering, kerne programmering og meget små embedded systemer. Du kan ikke bruge C++ i Linux kernen fordi C++ kræver en runtime, som ikke findes i kernemiljøet.

Bemærk i øvrigt at reference counting ikke nødvendigvis er hurtigere end spildopsamling (garbage collection). Det er en fejl at hænge sig i metoden da der ikke er nogen metode uden ulemper i forhold til de andre. Den vigtige parameter i forhold til sikkerhed i sproget er at det er automatisk styring af hukommelse vs manuel styring.

Troels Henriksen

Du kan ikke bruge C++ i Linux kernen fordi C++ kræver en runtime, som ikke findes i kernemiljøet.

C kræver også en runtime som ikke fandtes i kernemiljøet før den blev skrevet. På samme måde kan man fint skrive en kerne i C++ (jeg mener OS X IOKit-programmer er i en delmængde af C++), omend der er visse features (undtagelser, måske RTTI) man muligvis vælger at slå fra - i hvert fald i dele af kernen.

Man kan skrive kerner i ethvert sprog hvis først man definerer den underliggende runtime, og definitionen af denne runtime må nødvendigvis foregå i assemblykode. Som jeg har nævnt i en anden tråd, så læser jeg på min ferie Per Brinch Hansens The Architecture of Concurrent Programs fra 1977. Heri præsenteres adskillige styresystemer der alle er skrevet i højniveausproget Concurrent Pascal. Tricket er at flytte meget af hvad vi kalder typiske "kerne-opgaver" ind i oversætteren for et højniveausprog, og derefter kræve at både styresystemet og alle brugerprogrammer er skrevet i højniveausproget (i dette tilfælde, Concurrent eller Sequential Pascal). Oversætteren genererer så instruktioner til en enkel virtuel maskine, der er implementeret via et lille maskinkode-program på 4 kilo-ord.

Eftersom alle brugerprogrammer er skrevet i et sikkert sprog (Concurrent Pascal) behøver man slet ikke beskyttelsesmekanismer, som hukommelsesbeskyttelse, på maskin-niveau - et program kan umuligt tilgå maskinen på anden vis end via de funktioner der er defineret af styresystemet, og disse kan udføre deres egen adgangskontrol. Hukommelse kan som følge af Pascal's design ikke tilgås direkte.

Denne fremgangsmåde kræver at oversætteren er en pålidelig del af systemet, da den reelt er ansvarlig for at generere den derudover ukontrollerede maskinkode. Fremgangsmåden har naturligvis den oplagte svaghed, at alle programmer skal skrives i et højniveausprog, men det er sjovt og interessant at læse om alternative styresystems-designs, der ikke har de problemer vi kæmper med nutildags. Verden er andet og mere end C versus C++.

Michael Eriksen

ADA er fint, men ikke en garanti. Den første Ariane 5 gik som bekendt tabt med ADA software:

Ariane 5's first test flight (Ariane 5 Flight 501) on 4 June 1996 failed, with the rocket self-destructing 37 seconds after launch because of a malfunction in the control software.[28] A data conversion from 64-bit floating point value to 16-bit signed integer value...

https://en.wikipedia.org/wiki/Ariane_5

Mogens Hansen

Uden at sige at alle sprog er lige nemme/svære at lave fejl i, så findes der formodentlig ikke noget programmeringssprog, der er nyttigt til virkelige produkter, som kan forhindre programmeringsfejl.
Der kræves meget andet end at vælge et programmeringssprog for at lave sikre produkter - f.eks. processer til kvalitetssikring af såvel produktkrav som den producerede software.
Nogle af disse processer er helt sikkert påvirket af hvilket sprog der programmes i.

Softwaren i Ariane 5 var skrevet i Ada. Det er veldokumenteret at den eksploderede, helt forudsigeligt, ved første opsendelse pga. en softwarefejl .
Software i Lockheed Martin F-35 (Joint Strike Fighter) jagerflyet er skrevet i C++, angiveligt under meget strikse processer til validering.

Ada har eksisteret i 30+ år (ANSI/ISO standardiseret), et sprog, der ret ihærdigt forsøger at hjælpe udviklerne til at undgå at lave dumme fejl

Christian Lynbech

Det var altså Lisp der introducerede garbage collection. Dynamisk type check fandtes ikke kun i de første udgaver, men findes også i eksempelvis Common Lisp der stadigvæk lever og har det godt. Iøvrigt har Common Lisp også statisk type erklæringer som en option, det er bare ikke krævet.

Iøvrigt så er reference counting, som det ser ud som om Rust benytter (men som man også finder i Objective-C ), altså også en form for garbage collection. Garbage collection er egentligt bare et andet ord for automatisk lager-håndtering som er det der er det vigtige her. Om man benytter den ene eller anden strategi (stop and copy, reference counting, generational scavenging) er ikke vigtigt i den diskussion.

Netop lager håndtering er iøvrigt et glimrende eksempel på hvor lidt gavn man har af (ihverfald de simple) statiske type systemer. Jeg er helt sikker på at der spildt langt flere timer (som i størrelsesordner flere) på at finde og rette lager-håndterings fejl i C programmer end nogen programmør nogensinde har fået igen gennem fejl opdaget og forhindret af compileren.

Programmering er bare en hård disciplin, hvor selv den mindste lille fejl kan få det hele til at kuldsejle på det allermest uheldige tidspunkt. Der er ihvertfald ikke noget af det der findes i moderne eller populære sprog der har forhindret folk i at komme galt afsted (polsag, EFI, Amanda, tinglysning).

Torben Mogensen Blogger

En generalisering af standsningsproblemet blev lavet af Henry Gordon Rice, og siger, at i et turingkomplet programmeringssprog er ethvert ikke-trivielt spørgsmål om et programs opførsel uafgørligt. De eneste trivielle spørgsmål er dem, hvor svaret er ens for alle programmer, så man kan svare uden at se på programmet.

Uafgørligt betyder ikke, at man aldrig kan afgøre det, men at der eksisterer programmer, hvor man ikke kan svare ja eller nej til, om programmet har den givne opførsel. Spørgsmålet kan f.eks. være: "Findes der data, hvor dette program laver bufferoverløb?". For nogle programmer kan du svare "Ja, dette data vil medføre bufferoverløb", og for andre kan du svare "Nej, bufferoverløb kan ikke forekomme". Men der vil være programmer, hvor du ikke kan svare præcist. Du kan så vælge at afvise alle programmer, hvor en analyse ikke kan garantere, at bufferoverløb ikke kan forekomme, men så vil du afvise mange programmer, der alligevel ikke laver bufferoverløb.

I praksis vil komplekse egenskaber såsom mangel på bufferoverløb være umulige eller ekstremt tidskrævende (læs: årevis) at garantere ved hjælp af analyse for alt andet end meget små eller simple programmer. Så man kan forledes til at give op og nøjes med test, som Dijkstra så rigtigt påpegede ikke kan garantere fravær af fejl men kun påvise eksistens af fejl.

Men der er en anden mulighed: Rices sætning tillader trivielle egenskaber at være afgørlige, og definitionen af "triviel" (at det er en egenskab, alle eller ingen programmer har) hindrer ikke, at man gør komplicerede egenskaber trivielle ved gennem design at sikre, at enten har alle programmer egenskaben, eller ingen har den.

F.eks. kan egenskaben "Findes der data, hvor dette program laver bufferoverløb?" gøres triviel ved at sikre, at ingen programmer kan lave bufferoverløb. Men i det øjeblik, at bare et enkelt program kan lave bufferoverløb, har du tabt. Så kan du i praksis ikke lave en effektiv og tilstrækkelig præcis analyse, der sikrer mod bufferoverløb.

Et andet alternativ er at tage fat i forudsætningen for Rices sætning: At sproget er turingkomplet. Når et sprog ikke er turingkomplet, kan du i teorien godt lave præcise og effektive analyser over ikke-trivielle egenskaber. For eksempel kan ækvivalens af programmer være afgørligt for visse ikke-turingkomplette sprog (f.eks. endelige automater). Men turingkomplethed er meget praktisk, så denne løsning er for det meste kun interessant for meget specialiserede sprog såsom Datalog (som udtales, så det rimer med "loch" og ikke med "lo", ellers er den en person med datalogiuddannelse).

Statiske typer kan ses som værende en del af sproget, sådan at kan kommer udenom Rices sætning ved at gøre typesikkerhed til en egenskab, alle programmer har. De kan også ses som en analyse: Typecheck eller -inferens er analyser, der afgør om et program er typesikkert. Grunden til, at det ikke falder i den grøft, hvor kun simple programmer kan analyseres effektivt, er, at typechecket kan give feedback om, hvor i programmet, der er potentielle problemer, så programmøren kan rette sit program til, og i stedet få en typefejl i næste linje osv. Så selv om langt den overvejende del af programmer, der ikke er skrevet med bevidsthed om typer, vil fejle et typecheck, så fungerer det alligevel, fordi der er en feedback loop, hvor programmøren og typesystemet arbejder sammen om at lave et typesikkert program. Det er naivt at tro, at man kan udskyde analysen til programmet er helt færdigt, men den iterative proces fungerer fortrinligt. Det er dog ikke alle analyser, der kan give den form for feedback, så det er ikke alle egenskaber, hvor denne model er brugbar.

Baldur Norddahl

Iøvrigt så er reference counting, som det ser ud som om Rust benytter

Det er kun som sekundær mekanisme at Rust benytter reference counting. Den primære mekanisme er pointer borrowing, hvor man via type systemet sikrer at hukommelse altid frigives og at man ikke kan tilgå uinitialiseret hukommelse. Da det er et tjek på oversættelsestidspunktet, så har det ingen omkostning runtime.

Rust er et eksempel på hvordan man kan benytte statiske type systemer til også at sikre imod allokeringsfejl. C har bare ikke den feature. Nu er der heldigvis også sket en del siden at C blev opfundet.

Med en vis ret kan man også sige at de fleste C++ programmer udnytter type systemet til at håndtere automatisk hukommelsesstyring. Det specielle ved C++ i den sammenhæng er blot at det er valgfrit at kode på den måde.

Christian Lynbech

Min pointe er at det handler om automatisk lager håndtering, ikke hvilken præcis mekanisme der benyttes.

Om C++ kan siges at have det er nok noget man kan skændes om. Uden at være den store ekspert på C++ så er min forståelse at det foregår ved at man som programmør udstyrer sine klasser med standiserede allokering og deallokerings metoder. I så fald er det klart en forbedring over noget som C men stadigvæk ikke rigtig automatiseret lagerhåndtering, som jeg ser det. Det er dels frivilligt og hvis programmøren laver fejl i (de)allokerings metoderne, så får man stadigvæk lagerstyrings problemer. I sprog som Lisp og ML er man garanteret at der ikke går noget galt, ihvertfald ikke med den del.

Klavs Klavsen

Og blev til en snak om Garbage Collection.. hvilket jeg desværre har fået mange java udviklere til ikke at bekymre sig eller overhovedet overveje hvor meget ram de bruger.. de fortsætter bare med at hælde mere ind i ram - selvom de er ved at løbe tør.. (selvom man jo netop i java preallokerer hvor meget ram den må bruge - så den har jo alle forudsætninger for at have styr på det) - hvorefter java GC halt'er java processen for at "smide noget ud".. og når java koden så kører igen, fortsætter den med at hælde ind, hvilket ender med en nedagående spiral.. :)

Nu er det en grov generalisering.. men elasticsearch og anden java kode jeg ser, bærer ofte præg af ingen hensyntagen til fysiske omstændigheder :) - så at GC er et plus.. skal vist tages med det gran salt :)

Christian Lynbech

Jeg mener personligt ikke der kan være tvivl om at GC er et gode, men det skal selvfølgelig bruges som en undskyldning for ikke at tænke sig om. Man kan så også spørge sig selv om dine erfaringer siger mest om GC eller Java programmører.

Hvorom alting er, så siger al visdom at først gør du programmet korrekt (og her hjælper GC gevaldigt), først derefter begynder du at optimere, og al optimering bør iøvrigt laves ud fra profiling og ikke gætværk.

Man skal ikke tro at programmer af sig selv bliver optimale bare fordi man sidder med et lav-niveau sprog som C og styrer alt sit lager selv. F.eks. husker jeg endnu det vantro udbrud fra en gammel kontorfælle der netop havde fundet ud af hvorfor garbage collectoren i den sprog-implementation han debuggede på, til tider var meget langsom; nogen havde (sikkert af tidnød og med alle intentioner om at fikse det senere) puttet en bubblesort ind i garbage collectoren! Det hjælper altså ikke stort at du er omhyggelig med at flytte ting rundt, hvis den algoritme du implementerer er kvadratisk.

Christian Lynbech

Lige endnu et lille aktuelt hip til folk med en overdreven tro på hvad statiske typer kan gøre, via twitter, denne gang i forhold til Java:

https://twitter.com/philip_schwarz/status/685830452079267840

Du kan jo selv prøve at læse forklaringen og prøv så at tænke igennem hvor godt den facilitet kommer til at hjælpe dig til at lave sikker robust kode :-)

Baldur Norddahl

Det er for sent for Java at ændre på den enorme kodebase som misbruger "null" til at betyde ingen værdi. Det går helt ind i de mest basale funktioner i standard biblioteket, f.eks. så returnerer HashMap.get null hvis den søgte nøgleværdi ikke findes.

Et nyt sprog som Rust har derimod helt afskaffet null. Så det er en kæmpe klasse af fejl som ikke findes i Rust programmer. Og det er tilmed super effektivt idet "None" bliver kodet som null i den genererede maskinkode. Så det er faktisk gratis ved kørselstidspunktet at kode værdier ind i en "Option" type i Rust.

Jesper Louis Andersen

Lige endnu et lille aktuelt hip til folk med en overdreven tro på hvad statiske typer kan gøre, via twitter, denne gang i forhold til Java

Du kan også kode alt som strings. Det er næppe smart, men det kan lade sig gøre.

Pointen med typesystemer er at de er letvægts-formelle-metoder. For at få dem til at fungere, sådan at de finder fejl, så skal dit program have en hvis beskaffenhed, så du udnytter at en typisk programfejl resulterer i en typefejl. Heraf problemet med at implementere alt som strings: du har fjernet enhver mulighed for at typesystemet kan sige noget intelligent om dit program. Så hvis du har et typesystem der er udtryksfuldt, så skal du også udnytte det som programmør, ellers hjælper det ikke.

En "option"-type (eller dens mere generaliserede form som sum-type) har kun en styrke når sproget har den form at der ikke findes "null" (eller 'nil). Dermed signaler typen at du har en form for beregning der kan fejle. Men dermed siger du også at alle beregning der ikke er en option-type ikke kan fejle. Det er virkeligt en stærk egenskab der kan udnyttes til at få korrekte programmer først, og dernæst til at fjerne null-checks fra koden der genereres af oversætteren.

Java fejler fordi du ikke kan ommøblere sproget på nuværende tidspunkt. Skaden er sket i 1996. Tough, men sådan er det. Men hvis du tager f.eks. Standard ML eller OCaml, så har du ikke det problem. På mange måder er de sprog "moderne" udgaver af Common Lisp, hvor man er kommet videre i forståelsen for hvad et programmeringssprog bør være.

Per Dalgas Jakobsen

ADA er fint, men ikke en garanti. Den første Ariane 5 gik som bekendt tabt med ADA software

Ja, Challenger og Discovery fløj også med Ada software, men hvad har det med sagen at gøre?

Denne hændelse en smule mere nuanceret, hvilket du burde have checket inden du bragte den op:
1) Ariane 5 Flight 501 Failure, Report by the Inquiry Board
2) I heard tell that Ada was to blame for the Ariane V disaster. Is this true?

Det interessante er at Ada fangede konverteringsfejlen og forhindrede programmet i at eksekvere mere kode (nu baseret på forkerte data). - Gad vide hvor mange vulnabilities, der ville være undgået hvis alle sprog gjorde det per default...

PS: I øvrigt er Ada et navn, ikke en forkortelse.

Per Dalgas Jakobsen
Ivo Santos

Nu har jeg programmeret i C sproget på hobby niveau i et par år, og min forståelse af C sproget kontra C++ sproget er at man kan sammenligne et C modul, eks. modul.c og modul.h. med et C++ klasse.
Det der er det forskellige er at i C++ har man en constructor til at initialisere de dele der skal initialiseres, og så er der en destructor til brug når der skal rydes op.

I C sproget skal man for hver modul skrive sin egen init_modul() og term_modul() funktion, altså init for initialze og term for terminate, og kræver at man manuelt husker at eksekvere dem begge på det rigtige tidspunkt.
Da C sproget ikke understøtter klasser som er man nødt til at bruge alternative muligheder, og i windows er alternativet endt med at blive til de såkaldte handles hviken naturligvis stiller større krav til programmøren når det drejer sig om komplekse programmer, men det kan lade sig gøre.

Sikre programmering sprog?
Java og .net burde vel betegnes som sikre sprog. Jeg ved godt at der findes andre sprog Ada er blandt andet nævnt, men nu holder jeg mig i første omgang til java og .net.
java og .net burde vel være sikre sprog, og når man søger på 'how safe is .net and java' så får man en del interessante resultater, men nu er det jo sådan at en kæde ikke er stærkere end det svageste led.

Når jeg opdatere en windows pc efter en ren installation er der også en hel del rettelser til .net.
Selv til java bliver der med jævne mellemrum udgivet rettelser.
Så selvom java og .net er bedre end C sproget og C++ på en hel del områder så er det som sagt stadigvæk ikke muligt at programmerer hverken java eller .net i de respektive sprog, så selvom de pågældende platforme eller sprog er mere sikre end for eksempel C sproget så er nok stadigvæk svært at sige at det er muligt at lave ultra sikre programmerings sprog.

Christian Lynbech

For at få dem til at fungere, sådan at de finder fejl, så skal dit program have en hvis beskaffenhed, så du udnytter at en typisk programfejl resulterer i en typefejl.

Nu er udgangspunktet for diskussionen hvordan man sikrer et sprog. Hvis man siger at man er nødt til at kode på en bestemt måde for at opnå beskyttelse, så er man halvvejs henne til at sige at man roligt kan kode alt i strenge, man skal bare lade være med at lave fejl. Det er jo ikke fordi man ikke kan lave malloc baseret C kode der fungerer, det er kræver bare i praksis rigtigt meget krudt at få til at fungere. GC fjerner problemet ved at sikre korrekt lagerhåndtering, uanset hvad programmøren finder på at narrestreger.

På mange måder er de sprog "moderne" udgaver af Common Lisp, hvor man er kommet videre i forståelsen for hvad et programmeringssprog bør være.

Det må så stå for "man"s egen regning, jeg er ret uenig, selvom jeg indrømmet ikke kender ML eller Haskell godt nok til at kunne udtale mig om hvorvidt de stærkere type systemer gør en væsentlig forskel i forhold til statisk typing.

Klavs Klavsen

Jeg mener personligt ikke der kan være tvivl om at GC er et gode, men det skal selvfølgelig bruges som en undskyldning for ikke at tænke sig om. Man kan så også spørge sig selv om dine erfaringer siger mest om GC eller Java programmører.

GC er bestemt en smart feature.. men desværre er det min opfattelse at ALT der fortæller/lærer om java - går ind for at GC betyder at man overhovedet ikke skal "tænke på sit memory forbrug".. hvilket betyder at det gør programmørerne så ikke.. Det er blevet en undskyldning for "så behøver man ikke tænke sig om/vide hvad man gør".. og ærlig talt burde sproget have indbygget en slags exception eller lign. - så programmørerne SKULLE håndtere når java sagde "stop - jeg GC'er for lang tid af gangen/for ofte".. med en eller anden indstillige setting for definitionen af det.. istedet for den forventning jeg ser idag - hvor alle lærer alle at GC = "hukommelsesmagi"

Lars Tørnes Hansen

[quote]
Jeg mener personligt ikke der kan være tvivl om at GC er et gode, men det skal selvfølgelig bruges som en undskyldning for ikke at tænke sig om. Man kan så også spørge sig selv om dine erfaringer siger mest om GC eller Java programmører.

GC er bestemt en smart feature.. men desværre er det min opfattelse at ALT der fortæller/lærer om java - går ind for at GC betyder at man overhovedet ikke skal "tænke på sit memory forbrug".. hvilket betyder at det gør programmørerne så ikke.. Det er blevet en undskyldning for "så behøver man ikke tænke sig om/vide hvad man gør".. og ærlig talt burde sproget have indbygget en slags exception eller lign. - så programmørerne SKULLE håndtere når java sagde "stop - jeg GC'er for lang tid af gangen/for ofte".. med en eller anden indstillige setting for definitionen af det.. istedet for den forventning jeg ser idag - hvor alle lærer alle at GC = "hukommelsesmagi"
[/quote]
Hvis man bruger sprog der gør brug af en GC så skal man tænke over hvordan GCen frigiver hukommelse.

Brug af en memory buffer er meget nyttigt for typer man bruger og kasserer ofte/meget hurtigt.

Eksempel for Go programmeringssproget:
https://blog.cloudflare.com/recycling-memory-buffers-in-go/

Jan Rasmussen

C++ og Rust er ikke direkte konkurrenter. Rust sigter på at erstatte C, men ikke så meget C++ eller andre højniveau sprog.

Det gør det vel bare indnu værre for Rust, jeg kan godt forestille mig at en C programmør skifter til en C++ kompiler og bruger det som 'C with Classes' også stille og roligt gasser op for C++ features som vedkommende bliver fortroligt med dem, som undertegnet.

Men at gå fra C til Rust eller D, den tror jeg ikke på. Ikke at jeg på nogen måde er kvalificeret til andet ind gætværk, men min intuition ser ikke ud til at fejle noget hvis jeg læser denne her artikel: ( som er første hit på Google ved søgning på Rust vs. C++/C )

http://www.viva64.com/en/b/0324/
Criticizing the Rust/D/Xxx/ Language, and Why C/C++ Will Never Die.

Lige en side bemærkning jeg kunne ikke drømmer om at bebrejde Ada eller noget andet professionelt programmering sprog for programmørens mangle evne til at test deres software ordligt.

For hvis det er tilfældet, så er C++ vel også skyld i at denne bekostelige satellit gik tabt:
https://en.wikipedia.org/wiki/Mars_Climate_Orbiter

The Mars Climate Orbiter (formerly the Mars Surveyor '98 Orbiter) was a 338 kilogram (750 lb) robotic space probe launched by NASA on December 11, 1998 to study the Martian climate, Martian atmosphere, and surface changes and to act as the communications relay in the Mars Surveyor '98 program for Mars Polar Lander. However, on September 23, 1999, communication with the spacecraft was lost as the spacecraft went into orbital insertion, due to ground-based computer software which produced output in non-SI units of pound-seconds (lbf s) instead of the metric units of newton-seconds (N s) specified in the contract between NASA and Lockheed. The spacecraft encountered Mars on a trajectory that brought it too close to the planet, causing it to pass through the upper atmosphere and disintegrate.

For hulen hvor formatering på dette forum sutter, i forhold til hvad man ellers er vant til på diverse boards. Hverken * eller ** eller quote virkede til at fremhæve den tekst jeg ville fremhæve.

Men ok bare det at men kan kommentere artiklerne må vel siges at være et stort plus, og indikere fremsynethed og mod fra V2 side. På dr.dk skanner jeg blot overskrifter for at se hvad er det de vil fortæller pøbl-host befolkningen, af samme årsag, da én enkelt sarkastisk bemærkning eller spørgsmål jo kan ødelægge hele deres spin.

Jonas Høgh

Det må så stå for "man"s egen regning, jeg er ret uenig, selvom jeg indrømmet ikke kender ML eller Haskell godt nok til at kunne udtale mig om hvorvidt de stærkere type systemer gør en væsentlig forskel i forhold til statisk typing.


Så synes jeg du skulle prøve dem, inden du fortsætter dit korstog. Jeg er heller ikke ekspert, men du vil formentlig opdage, at du behøver ingen eller meget få type-annoteringer til de fleste typer opgaver. (Omend det i Haskell betragtes som god praksis at angive typerne på top-niveau-funktioner)

Det er langt ude at bruge et elendigt hack oven på Javas typesystem som bevis for at statiske typer er dårlige. Jeg kunne lige så godt påstå at dynamiske typer er dårlige, fordi det er lykkedes ca. 1 mio. dårlige PHP-programmører at skyde benene af sig selv i tidernes løb ved hjælp af byzantiske fejldesigns omkring implicitte konverteringer.

Log ind eller opret en konto for at skrive kommentarer