Microsoft: Rust kan løse hukommelsesproblemer i C og C++

Illustration: Pixabay.com-bruger terimakasih0
Måske er det på tide at putte gamle sprog i skraldespanden og benytte et mere moderne og sikkert system-sprog, lyder det fra software-giganten.

Microsoft Security Response Centre (MSRC) har undersøgt hver eneste sårbarhed i Microsofts programmer siden 2004.

Konklusionen er klar: Langt de fleste fejl handler, som man nok ville forvente, om usikker håndtering af hukommelse i programmerne.

Men hvad hvis man helt kunne slippe for denne type fejl?

Det spørgsmål stiller Gavin Thomas, som er ledende sikkerhedschef i MSRC, i et blogindlæg.

Størstedelen af ​​de sårbarheder, der rettes og får tildelt et CVE-sårbarhedsnummer, skyldes at programmørerne uforvarende kommer til at indsætte fejl i håndteringen af hukommelse i kode skrevet i C og C++.

Omkring 70 procent af de sårbarheder, Microsoft udstyrer med et CVE-nummer, skyldes problemer med usikker hukommelse. Tallet har ligget stabilt i de sidste 12 år. Illustration: Used with permission from Microsoft

Når Microsoft øger sin kodebase og benytter mere open source-software i sin kode, bliver dette problem ikke bedre, men værre. Andre producenter, der også arbejder med C og C++ oplever det samme.

Der findes hukommelsessikre sprog som C# og Java, men C og C++ kan nogle tricks, som de sikre sprog ikke kan tilbyde i helt samme omfang.

C++ har nemlig dyder, der gør det attraktivt og i visse tilfælde helt uomgåeligt.

Sproget er forrygende hurtigt, det kan køre med begrænset hukommelse og diskforbrug, det er et modent sprog, det har forudsigelig afvikling, og dets platform-uafhængighed er næsten uden sidestykke. Endelig kræver det ikke nødvendigvis installation af andre biblioteker eller komponenter.

En ideel løsning er efter Gavin Thomas' mening et sprog, der kombinerer de sikkerhedsgarantier, som et .Net-sprog som C# giver, med den effektivitet, som C++ kan byde på.

Og måske findes det sprog allerede, mener Microsoft-manden.

Et af de mest lovende nyere system-sprog, der opfylder disse krav, er Rust, et programmeringssprog oprindeligt opfundet af Mozilla, til at skabe en hurtigere og mere stabilt Firefox.

Sikker hukommelse med ejerskab på variable

Rust har en ambition om at være en slags sikker C ved hjælp af bestemte sprogkonstruktioner.

I Rust er der ejerskab på værdier. Man kan tænke på det, som om at man ejer eller udlåner værdier. Når man kalder en funktion med parametre, overfører man ejerskabet på en datastruktur. Efter funktionskaldet kan datastrukturen ikke længere bruges af kaldet, for ejerskabet er væk. Det er kompilerens såkaldte ‘borrow checker’ - 'låne-tjekker' - der holder øje med at reglerne overholdes.

En måde at tænke på det er, som at man rundsender ejerskabet til værdier, og det er meget anderledes end de fleste andre sprog, hvor man kan gøre, hvad man har lyst til, så længe variablen er i virkefeltet.

En anden operation i Rust er det at ‘låne’ en værdi. I stedet for at overføre ejerskab til en funktion kan programmøren overføre en reference, som kan være kun-læs eller læs-og-skriv (immutable og mutable). Hvis referencen kun kan læses, kan kaldet stadig få lov at læse. Og når funktionen er færdig med sit arbejde, har kaldet igen fuld kontrol over værdien.

Det hele betyder, at hukommelse kan frigives automatisk uden problemer, når en variabel falder ud af virkefeltet, altså når programudførslen rammer den sidste lokale tuborg-parentes i en kodeblok. Det betyder også, at samtidige tråde ikke uforvarende kommer til at ændre variablens værdi, med uforudsigelig opførsel til følge.

Og det er det, der gør koden mere sikker og stabil, samt nemmere at fejlsøge.

Læs også: Rust: Sådan vil Mozilla genstarte Firefox med sikker og hurtig kode

Moderne C++ har en facilitet der tilsvarer Rusts ejerskab, med navnet ‘smart pointers’, men til forskel fra Rust er det meget nemt at slippe for at anvende dem. I Rust skal der stå ‘unsafe’ i koden, før man kan slippe for de skrappe regler.

Det betyder dog også, at en simpel datastruktur som en 'linked list' ikke kan skabes i Rust uden 'unsafe', da cirkulære referencer er forbudt af låne-tjekkeren.

Masser af værktøjer - men problemet er et andet sted

Der findes masser af værktøjer, der kan hjælpe udviklere med at skrive sikker kode. Det drejer sig om statiske analyseværktøjer, som kan være komplekse og svære at lære at bruge, samt såkaldte 'fuzzing'-teknikker, der giver store stakke af program-crashes, der derefter skal analyseres.

Læs også: Sådan finder og retter Facebook kodefejl med kunstig intelligens

Der findes også bunker af vejledninger og retningslinjer, der skal holde programmørerne fra fedtefadet. Men der er måske en bedre måde at komme frem til mere sikre programmer på, mener Gavin Thomas.

Kernen i en udviklers arbejde er ikke at bekymre sig om sikkerhed, men at skrive kode, der fører til ny funktionalitet i et program. Her kan et sikkert sprog som Rust bruges til noget. Det er et af de mest lovende nye sprog til systemprogrammering, lyder vurderingen:

»Måske er det tid til at smide de usikre gamle sprog ud og gå over til et moderne og mere sikkert system-programmeringssprog?« slutter Gavin Thomas, og lover at sikkerhedsbloggen i fremtiden vil kigge mere på den rolle, Rust kan spille i Microsofts verden.

Tips og korrekturforslag til denne historie sendes til tip@version2.dk
Følg forløbet
Kommentarer (41)
sortSortér kommentarer
  • Ældste først
  • Nyeste først
  • Bedste først
Philip Munksgaard

Jeg har ikke selv erfaringer emd embedded Rust udover lidt hobby-projekter på en STM32F3DISCOVERY, men der er en hel embedded Rust bog, og det er et af Rust-projektets fokus-punkter at sproget skal være en gyldig erstatning til C også på det område.

For mere info:
https://rust-embedded.github.io/book/
https://www.rust-lang.org/what/embedded
https://github.com/rust-embedded/wg

  • 1
  • 0
Christian Nobel

Rust's ownership-model handler især om at gøre det rimeligt at skrive højtydende og korrekte flertrådede programmer. Der er mig bekendt ikke nogen lignende løsning i Delphi.

Det er muligt at lave flertrådede programmer i FreePascal - men jeg vil blankt indrømme at jeg aldrig har haft behov for det, da programafvikling som regel går så hurtigt at det ikke er nødvendigt med flere tråde (men ikke dermed sagt at andre ikke kan have behovet).

Til gengæld så har Pascal rigtig god strenghåndtering, og man behøver ikke rode sig ud i et pointerhelvede.

  • 0
  • 1
Kjeld Flarup Christensen

der er mange ting i TP/Delphi som jeg savner i C, incl. ShortString


Det kan man så let lave med C++.

Men når vi taler embedded, så er der mange som ikke ønsker C++. Forlaringen er den simple, at C++ i modsætning til C kan generere kode som laver ting bagom ryggen på udvikleren.

Inden jeg ville hoppe på en ting som Rust, vil jeg sætte mig ind i hvad jeg smider på mit target.
Hvordan holder sproget f.eks. styr på ejerskabet. Hvad er overhead ved det og hvilke dumheder kan man lave med det.

  • 1
  • 0
Helge Svendsen

Hvad er overhead ved det og hvilke dumheder kan man lave med det.

Jeg kan ikke se, at du ikke skulle kunne lave samme dumheder i Rust, som du kan i eks c/c++.

Siden alt fra udgangspunktet er immutable (write once / read many) så er det klart nemmere at holde styr på sikkerhed og samtidighed.

Til gengæld er tradeoff jo ganske givet et højere hukommelses forbrug og mere memory allokerings overhead.

  • 0
  • 1
Troels Henriksen

Jeg kan ikke se, at du ikke skulle kunne lave samme dumheder i Rust, som du kan i eks c/c++.

Det kan du godt hvis du aktivt tilvælger det (ved at bruge "unsafe"-blokke), men uden for disse garanterer Rust typesikkerhed og fraværet af udefineret opførsel. Det er altså ikke umuligt at kvaje sig i Rust, men det er mere vanskeligt, mens man samtidigt har mulighed for (bevidst) at slå sikkerhedsmekanismerne fra, hvis man har behov for at lave noget man er rimeligt sikker på er korrekt, men som bryder sprogets (konservative) regler. Man kan også bygge abstraktioner i C++ og C, men man er ikke på samme måde beskyttet mod at bryde reglerne.

Til gengæld så har Pascal rigtig god strenghåndtering, og man behøver ikke rode sig ud i et pointerhelvede.

Det er altså noget af en 70'er/80'er-problemstilling at gå op i strings. Ja, de er elendige i C. Ja, Pascal gør og gjorde det bedre. Men det har ikke noget at gøre med Rust, eller endda C++. Der er nye kampe at kæmpe! Hvis Delphi stadigvæk kæmper kampen mod C, og ikke de mange nyere sprog der har erstattet det meste C-programmering (uagtet at C stadigvæk er udbredt), så undrer det ikke at Delphi står med en fod i graven...

  • 6
  • 2
Christian Nobel

Det er altså noget af en 70'er/80'er-problemstilling at gå op i strings.

Det var en mærkelig hovski-snovski holdning at udvise.

Jeg er godt klar over at det er lidt OT i forhold til programmering af embeddede systemer, men hvis man laver forretningsorienterede programmer, og/eller webapplikationer, så er der tit en farlig masse stings man skal rode med, hvorfor string håndtering så afgjort er vigtig, og det kan korte udviklingstiden voldsomt meget ned, hvis man ikke skal bøvle med trivialproblemer.

  • 1
  • 3
Esben Nielsen

Det, som laver megen ekstra, ukontrolleret kode i C++, er templates. Dem har man så vidt jeg ved også i Rust.

Jeg har selv brændt nallerne med at lave pæn C++ kode, som miksede templates og virtuelle funktioner: det gav et hav af klasser med virtuelle tabeller og runtime type-information, som fyldte alt for meget på et 16 MB stort system.

Nu koder jeg på PC størrelse systemer, og har derfor ikke den slags problemer. Jeg har gennemtvunget, at vi kun lavet een-trådede programmer, men flere af dem på Linux og på den måde bruger MMU'en til at gennemtvinge data-adskillelse. På den måde er C++ mindst lige så nemt som Java - men det oversætter meget langsommere, og værktøjerne er dårligere.

Det samme gør man iøvrigt ofte i mere embeddede systemer uden MMU, her bruger man blot besked-køer frem for pipes eller TCP forbindelser, som vi gør.

Med Rust ville jeg nok turde begynde at parellelliserer noget af koden direkte inde i hvert program, men med C++, holder jeg mig til at parellisere ved at starte flere processor op og samle igen. Det kan også bedre spredes ud på mange maskiner.

Nede i kernen, hvor parellisering er uundgåelig, er Rust nok helt klart at foretrække - men man skal nok ikke drømme om mindre hukommelsesforbrug end C++, da Rust, så vidt jeg kan se, bygger på meget af det samme.

  • 0
  • 0
Troels Henriksen

Jeg er godt klar over at det er lidt OT i forhold til programmering af embeddede systemer, men hvis man laver forretningsorienterede programmer, og/eller webapplikationer, så er der tit en farlig masse stings man skal rode med, hvorfor string håndtering så afgjort er vigtig

Det var heller ikke min pointe - strings er skam vigtige, det tror jeg alle ved. Min pointe var snarere at de er et løst problem. C er det eneste sprog hvor de stadigvæk er elendige[1]. Man må finde en stærkere differentiator hvis man mener at Pascal/Delphi er værd at bruge ift. f.eks. Rust.

[1]: Afhængigt af hvor kræsen man er har de fleste sprog dårlige strings, men så er det fordi man går op i hvorvidt de repræsenterer bytes, Unicode code points, grafemklynger, eller hvad det nu måtte være. Tekst er i almindelighed svært. Men ingen andre udbredte sprog end C har problemer med at tekstbehandling giver hukommelseskorruption.

  • 4
  • 0
Christian Nobel

Man må finde en stærkere differentiator hvis man mener at Pascal/Delphi er værd at bruge ift. f.eks. Rust.

Du gøer op ad det forkerte træ!

Jeg har ikke sagt at Pascal skulle være bedre end Rust, men kommenteret at FreePascal godt kan køre flertrådet, og at Pascal generelt har en rigtig god string håndtering.

Og så er jeg i øvrigt ret så ligeglad med om man har en eller anden up-nose holdning til at Pascal skulle være 70'er agtig, hvis det kan løse den opgave jeg vil have det til at løse, på en brøkdel af tiden med et hurtigt og stabilt resultat til følge - og det er så stadig lysår foran f.eks. MUMPS som man i region Sjælland har inficeret sygehusvæsenet med.

  • 1
  • 4
Kjeld Flarup Christensen

Det kan du godt hvis du aktivt tilvælger det (ved at bruge "unsafe"-blokke), men uden for disse garanterer Rust typesikkerhed og fraværet af udefineret opførsel.


Udefineret opførsel er ikke problemet. Problemet er hvor mange ukendte operationer sproget benytter for at opnå den definerede opførsel.
Esben Nielsens oplevelse ovenfor et et godt eksempel. Jeg er sikker på at hans program gjorde som det skulle, hvis der var ressourcer til det.

I øvrigt er C blevet mere typesafe. Men man kan stadigt typecaste sig hele vejen til helvede.

  • 0
  • 1
Torben Rune

Jeg synes et eller andet sted, at der mangler et aspekt i diskussionen. Et er, at forbedre og modernisere programmeringssprog, så risikoen for fejl i koden minimeres. Noget helt andet er at se tingene fra en hackers synspunkt.

Vi taler her om complierede sprog, som generere masser af maskinkode, og det er klart, at der ikke må være oplagte uhensigtsmæssigheder i f.eks. memory allokering, frigivelse, gensidig beskyttelse, raeltidsparametre osv. men typisk er det ikke kun det en hacker går efter.

Han dekomponerer maskinkoden og kigger på hvordan han i givet fald kan udnytte sårbarheder. De opstår naturligvis som beskrevet hvis den logiske sammenhæng i programmeringssproget har huller, men så sandelig også hvis compileren generere dårlig maskinkode. Og der er ikke nødvendigvis en 100% garanti for, at selv om et programmeringssprog er sikret i forhold til sprogets logik og brug af memory, at maskinkoden ikke kan rumme (masser af) uhensigtsmæssigheder.

Så uanset hvor meget man holder af et givet sprog, og uanset hvor godt sproget er til at beskytte brugeren imod fejl, så ændrer det ikke på, at man fortsat har behov for at se på den konkrete implementering af selve compileren. Er (maskin)koden sikret. Hvad sker der ved evt. krydskompilering. Hvad sker der i forskellige hardware konstellationer osv. osv. Jeg har gennem årene set skrækkelige compilere, som generere den rene skod-kode, selv om alting ser helt vandtæt og smukt ud i kildeteksten.

Så skal sproget være sikkert, så omfatter det også at selve compileringsprocessen gøres til genstand for sikkerhedsanalyse.

  • 0
  • 2
Troels Henriksen

Og der er ikke nødvendigvis en 100% garanti for, at selv om et programmeringssprog er sikret i forhold til sprogets logik og brug af memory, at maskinkoden ikke kan rumme (masser af) uhensigtsmæssigheder.

Der er bestemt mulighed for at en oversætter kan generere forkert kode, og at denne kode kan udnyttes af en angriber. Uagtet gamle travere som Ken Thompson's Trusting Trust, er der så praktiske eksempler på at dette er sket? Hvor ofte sker det ift. så mange andre sikkerhedsbrister? Jeg tror ikke det i praksis er noget det er værd at bekymre sig om. Faktisk er jeg villig til at postulere en (empirisk u-underbygget) stærkere hypotese: Det er værd at lave sproget og oversætteren mere kompliceret (som Rust) for at undgå hukommelsesfejl i den programmørskrevne kode, selv hvis øger risikoen for fejl i oversætteren der potentielt kan udnyttes. Jeg mener at gevinsten er større end risikoen.

Der er massevis eksempler på at oversættere genererer forkert kode (især med mange optimeringer slået til), men det er sjældent de er blevet udnyttet af angribere, for som regel får de programmet til at crashe før det kommer i brug. Og der er blevet udviklet beviseligt korrekte oversættere (desværre til C) som garanterer at de slet ikke har sådanne fejl i den genererede kode (under en række antagelser; læs altid hvad der står med småt).

  • 3
  • 0
Baldur Norddahl

Inden jeg ville hoppe på en ting som Rust, vil jeg sætte mig ind i hvad jeg smider på mit target.
Hvordan holder sproget f.eks. styr på ejerskabet. Hvad er overhead ved det og hvilke dumheder kan man lave med det.

Mantraet indenfor Rust er zero cost abstractions. Det vil sige at alt det med ejerskab med videre er noget der tjekkes af oversætteren og herefter smides det væk. Der er ingen tjeks i den generede maskinkode.

Et andet eksempel er at der ingen "null" i sproget, men det er der i maskinkoden. Fordi det er effektivt og oversætteren laver ikke fejl, så den kan godt bruge konstruktioner der er farlige for os mennesker.

  • 3
  • 0
Kjeld Flarup Christensen

Mantraet indenfor Rust er zero cost abstractions. Det vil sige at alt det med ejerskab med videre er noget der tjekkes af oversætteren og herefter smides det væk. Der er ingen tjeks i den generede maskinkode.


Det lyder jo godt.
Men hvordan det så hjælper i forbindelse med f.eks. multithreading bliver lidt mere tåget for mig. Specielt når der ikke sker checks på target.

  • 0
  • 0
Baldur Norddahl

Men hvordan det så hjælper i forbindelse med f.eks. multithreading bliver lidt mere tåget for mig. Specielt når der ikke sker checks på target.

Du kan kun lave sikre operationer. Eksempelvis kan du give ejerskab over noget data til en anden tråd. Det er så den tråd der har ansvaret for at frigive hukommelse. Den oprindelige tråd kan ikke tilgå data mere, end ikke read only, så der er ikke risiko for at data tilgås efter hukommelse er frigivet.

Alt det er sikret og tjekket inden maskinkoden bliver genereret. Derfor behøver maskinkoden ikke at indeholde tjeks for det samme.

  • 3
  • 0
Sune Marcher

Han dekomponerer maskinkoden og kigger på hvordan han i givet fald kan udnytte sårbarheder. De opstår naturligvis som beskrevet hvis den logiske sammenhæng i programmeringssproget har huller, men så sandelig også hvis compileren generere dårlig maskinkode.


Er dette ikke primært et problem i C og C++, hvor der er så kæmpe mængder af implementation-defined, unspecified og undefined behavior at det er forbandet svært at skrive korrekt kode?

Jeg kan ikke huske at have set nogle eksempler på et compiler-fejl har genereret exploitable kode. Eksempler på at selv dygtige udviklere bliver bidt af ID/US/UB er derimod en anden sag.

Og hvis man skriver C-kode som om det var en "high-level assembly" kan man også få sig nogle overraskelser, ikke mindst på grund af hvilke optimeringer compilere (ganske tilladt af standarden) kan lave. Det har mere end én gang fjernet runtime null-checks i Linux kernen, og har ledt til privesc bugs.

  • 0
  • 0
Esben Nielsen

Der er en del forskel på macroer og templates: de sidste er et Turing-komplet, funktionelt programmeringssprog, som kører i compileren og genererer ny kode og typer undervejs. Med optimering slået til, vil man ofte få fjernet meget af koden igen, og lokkeren kan måske også fjerne ubrugte symboler; men generelt bliver alle "mellemregningerne" hængende i det endelige program.

Jeg foretrækker selv templates frem for macroer, da disse bliver meget værere, hvis de skal skulle bare en smule af, hvad templates kan. Se blot på Linux kernens list implementation: det kan gøres meget kønnere med templates.

  • 1
  • 0
Esben Nielsen

Der er en del forskel på macroer og templates: de sidste er et Turing-komplet, funktionelt programmeringssprog, som kører i compileren og genererer ny kode og typer undervejs. Med optimering slået til, vil man ofte få fjernet meget af koden igen, og lokkeren kan måske også fjerne ubrugte symboler; men generelt bliver alle "mellemregningerne" hængende i det endelige program.

Jeg foretrækker selv templates frem for macroer, da disse bliver meget værere, hvis de skal skulle bare en smule af, hvad templates kan. Se blot på Linux kernens list implementation: det kan gøres meget kønnere med templates.

  • 0
  • 0
Kjeld Flarup Christensen
  • 0
  • 0
Torben Rune

Er dette ikke primært et problem i C og C++, hvor der er så kæmpe mængder af implementation-defined, unspecified og undefined behavior at det er forbandet svært at skrive korrekt kode?


Jo, det er en af de nærliggende årsager. En anden er, at meget kode i dag genbruges på flere platforme, og krydskompileres, med deraf risiko for manglende styr på "undefined behavior".

  • 0
  • 0
Sune Marcher

Hvad er det for en kobling du ser mellem krydskompilering og undefined behaviour? Sidstnævnte er et koncept fra sprogspecifikationen, og har ikke noget at gøre med en konkret platform, endsige krydskompilering.


Mit gæt ville være kodebaser hvor der er en bunke ID/US/UB, hvor det ikke har bidt én i røven endnu, fordi man kun har brugt én compiler. Ny platform, ny compiler, bang.

  • 0
  • 0
Esben Nielsen

Har Rust macroer???

Jeg kan se type generiske metoder som i ML og andre funktionelle sprog. Og generiske typer. De minder end del om templates, men er umiddelbart ikke så kraftfulde: man kan så vidt jeg kan se ikke angive andet end typer som argument. Jeg kan derfor ikke se, hvordan man kan lave noget, som minder om boost::unit - fysiske enheder indlejret i typerne og checket compile-time med zero runtime overhead. Man får f.eks. en compile fejl, hvis man ligger en længde til en længde med en tid, fås en hastighed.
Enhedsalgebra compile-time, kort og godt.

Det jeg kunne finde på nettet bar rundt på enheder runtime, ligesom forsøget på at lave det i Java. Det giver jo selv sagt et overhead.

Det som man mangler er en generisk type, som kan regne på potenser i enhederne, f.eks. m*m / s / s = m^2 s^-2 compile time.

Det er ikke lige til i Rust, da man ikke kan angive potenserne ovenfor som "template" argumenter og regne på dem compile time.

  • 0
  • 0
Troels Henriksen

Har Rust macroer???

Ja.

De tillader vilkårlige transformationer og kodegenerering, ganske som Lisp-makroer, og med nogenlunde de samme fordele og ulemper. Beregningsmæssigt er de ikke stærkere end C++ templates (begge er Turing-komplette), men de er langt mere udtryksfulde, da deres definitioner udtrykkes via ordinær Rust-kode, i stedet for C++'s sære implicitte template-metaprogrammeringssprog.

Hvad typesikre måleenheder angår har jeg fundet dette bibliotek der påstår at være zero-overhead. Det foregår dog ikke via makroer, men via almindelig parametrisk polymorfi. Det er for så vidt også godt nok, da Rust's nuværende implementering af parametrisk polymorfi gør brug af monomorfisering, hvilket har samme kodemæssige effekt som C++'s template-instantiering (nemlig en kopi af den polymorfe kode for hver type den anvendes med).

  • 0
  • 0
Thomas Nielsen

Når programmøren flere gange bliver nævnt som en almindelig kilde til problemer, så synes jeg det er værd at bemærke, at der er gode grunde til at det er således og at de altså ikke altid skal læses som et angreb på programmørstanden:

Skriver man alene, vil man have svært ved at se dårlige mønstre i sin programmering, og deri kan der skjule sig uhensigtsmæssig opførsel.

Skriver man i grupper, bliver en del af det første problem afhjulpet af flere øjne der kigger, men til gengæld opstår et nyt, hvor een udvikler ikke nødvendigvis er i samme tankesæt som en anden, og dermed misforstår konstruktioner og bagvedliggende motivation. Det kan minimeres med god dokumentation og kommunikation, men det koster penge og er et af de første gode adfærdsmønstre der ofres på deadline-alteret.

  • 0
  • 0
Kjeld Flarup Christensen

Mit gæt ville være kodebaser hvor der er en bunke ID/US/UB, hvor det ikke har bidt én i røven endnu, fordi man kun har brugt én compiler. Ny platform, ny compiler, bang.


Der er det så måske en fordel at bruge den samme compiler.
Jeg må sige at det er længe siden jeg har døjet med compiler problemer (7-9-13) da jeg bruger GCC og Linux.
Ja principielt er der tale om en ny platform når der kommer en ny CPU, men da antallet af arkitekturer er begrænset, så kører det fint.

  • 0
  • 0
Sune Marcher

Der er det så måske en fordel at bruge den samme compiler.


Tværtimod, det er en fordel at teste flere compilere samt flere arkitekturer. ID/US/UB er fejl i din kode, ikke i compileren – hvis du vil forbedre dine chancer for at finde fejl før din nuværende compiler introducerer en ny optimering, der genererer fejlbehæftet kode på grund af din UB, har du bedre chancer hvis du tester flere compilere allerede nu.

  • 0
  • 0
Troels Henriksen

Derudover er GCC sammen med LLVM de oversættere der udnytter udefineret opførsel allermest aggressivt (eksempler. Det er også mit indtryk at de fleste C-programmører ikke har forståelse for hvad der egentlig er udefineret opførsel - f.eks. regner de fleste med at signed heltal bare løber over og bliver negativ ved overflow, men det passer ikke, og det har ikke noget med maskinen at gøre.

Før C11 var det også udefineret opførsel hvis ens C-fil (eller "compilation unit" i spec-sprog) ikke sluttede med et linjeskift. Jeg har dog aldrig hørt om en oversætter der udnyttede det til noget!

  • 2
  • 0
Philip Munksgaard

Det er ret besværligt at fremprovokere undefined behavior i Rust. Manish Goregaokar (som er en del af rusts "core" developers) har skrevet en fin artikel om det her: Undefined vs Unsafe in Rust

Pointen er at man skal gøre sig umage hvis man skal producere undefined behaviors i (ikke-unsafe) rust, og det samme gør sig gældende for implementation defined og unspecified behaviors. Langt de fleste udviklere vil aldrig have brug for at skrive mere end en håndfuld meget overskuelige unsafe blokke, som man nemt kan sikre sig rent faktisk er sikre.

Helt principielt vil jeg også give Troels ret i at forekomsten af undefined behavior kun kan forekomme som resultat af (mangelfuldt) sprogdesign. Standard ML har så vidt jeg ved ingen udefineret opførsel. Det er primært C og C++ der har den slags problemer, og det korte og det lange er at Rust undgår/løser dem tilfredsstillende, lige som så mange andre programmeringssprog gør det.

  • 1
  • 0
Ivan Skytte Jørgensen

Helt principielt vil jeg også give Troels ret i at forekomsten af undefined behavior kun kan forekomme som resultat af (mangelfuldt) sprogdesign. Standard ML har så vidt jeg ved ingen udefineret opførsel. Det er primært C og C++ der har den slags problemer,


Det kan også være et bevidst valg at ikke specificere opførslen. C specificerer ikke hvad der sker når en signed integer laver overløb, fordi sproget tillader at hardwaren repræsenterer signed integers som 2-complement, one's-complement og sign-magnitude. Man kunne have valgt at der skulle ske en "trap", men flere arkitekturer har ingen effektiv måde at gøre det på, og det skulle checkes for hver addition/subtraktion/multiplikation. Så man valgte at ikke specificerer hvad der sker. Det samme gør sig gældende for de fleste andre steder i C/C++ hvor opførslen ikke er specificeret.

  • 0
  • 0
Sune Marcher

Det kan også være et bevidst valg at ikke specificere opførslen.


...hvilket vel egentligt er en større fejl end Tony Hoares "Billion Dollar Mistake", hvis man ser på hvor meget exploitable kode det har resulteret i :-)

Det gav nok OK mening back then, hvor der var noget mere flippede arkitketurer i dag, og maskinerne var væsentligt langsommere. Men det har godt nok kostet os en del... og der er så meget ID/US/UB i C/C++ at jeg er lidt mistænksom overfor personer der påstår de kan lave fejlfri kode.

  • 2
  • 0
Log ind eller Opret konto for at kommentere
IT Company Rank
maximize minimize