Rust: Sådan vil Mozilla genstarte Firefox med sikker og hurtig kode

Mozilla vil tilbage i front blandt webbrowserne. Nøglen er sproget Rust, som giver bedre kodekvalitet per arbejdstime.

Det er ikke nogen hemmelighed, at Firefox har været gennem en del hårde år. Browseren, som i sin tid stod for fornyelse og forenkling, er gået stærkt ned ad bakke i målinger på de forskellige browseres udbredelse. Mange brugere oplever, at Firefox virker langsommere i optrækket end konkurrenterne, men det skal der gøres noget ved.

Jack Moffitt er programmør i Mozilla. Her brygges der på Firefox 57, planlagt til udgivelse i oktober. Det er den version, der skal få Firefox tilbage i forreste linje. Mozillas mirakelmiddel til at opnå det mål er sproget Rust, der skal give sikker og hurtig kode.

Rust har en ambition om at være en slags sikker C ved hjælp af bestemte sprogkonstruktioner. Og Rust er helten bag den kommende Firefox 57, fortæller Jack Moffitt.

Han leder 12 programmører på Mozillas Servo-projekt, som vil skrive Firefox om fra bunden i det unge sprog, som kan noget nyt.

»Rust prøver at forene ydelse og sikkerhed. Det oprindelige mål var at skabe et nyt systemprogrammeringssprog, som vi kan anvende til at skrive en ny browser med, der løser to store problemer. Det ene er sikkerhed. For to årtier siden bestod webbet mest af statiske sider, og i dag kører vi vilkårlig Javascript-kode, som vi aldrig har set før i browseren, og som vi ikke ville stole på, hvis det blev afviklet på vores egne computere,« siger han til Version2 på et videokald fra det amerikanske midtvesten.

Jack Moffitt leder 12 programmører på Mozillas Servo-projekt, som vil skrive Firefox om fra bunden i sproget Rust.

»Så sikkerheds- og trusselsmodellerne har ændret sig dramatisk. Fejl, som i sin tid blot var ærgerlige, kan i dag benyttes til angreb og til at overtage maskinen. Det er et problem, som er svært at løse med blot at være forsigtig - der er ikke nogen programmører, som er gode nok til at helt at undgå disse fejl, i særdeleshed når mange hundrede mennesker arbejder på samme projekt.«

Det andet problem, som Rust skal løse for Mozilla, er at udnytte cpu’ernes kerner fuldt ud og undgå såkaldte ‘race conditions’, hvor flere tråde spænder ben for hinanden ved at tilgå samme hukommelse. Det kan være noget så simpelt som et fejlagtigt array-indeks, som kan få katastrofale konsekvenser. En pointer, som peger på et sted i hukommelsen, kan være gyldig, når én tråd benytter den, men ugyldig i en anden tråd.

I C++ oplever man ofte disse problemer i forbindelse med parallelisering af kode, som fører til fejl, der er meget svære at afluse. Det bliver dyrt og praktisk talt uladsiggørligt, mener Jack Moffitt.

Nej tak til garbage collection

Sikre sprog som Java og C# kan ikke løse Mozillas problem. De kan som regel ikke kompileres til systemets ‘fødte’ kode, men afvikles via just-in-time-compiler eller en fortolker.

»De synes ikke at have nået til det niveau, hvor de er hurtigere end kompilerede sprog.«

(Artiklen forsætter under eksemplet.)

// This function takes ownership of a box and destroys it
fn eat_box_i32(boxed_i32: Box<i32>) {
    println!("Destroying box that contains {}", boxed_i32);
}
 
// This function borrows an i32
fn borrow_i32(borrowed_i32: &i32) {
    println!("This int is: {}", borrowed_i32);
}
 
fn main() {
    // Create a boxed i32, and a stacked i32
    let boxed_i32 = Box::new(5_i32);
    let stacked_i32 = 6_i32;
 
    // Borrow the contents of the box. Ownership is not taken,
    // so the contents can be borrowed again.
    borrow_i32(&boxed_i32);
    borrow_i32(&stacked_i32);
 
    {
        // Take a reference to the data contained inside the box
        let _ref_to_i32: &i32 = &boxed_i32;
 
        // Error!
        // Can't destroy <code>boxed_i32</code> 
        // while the inner value is borrowed.
        eat_box_i32(boxed_i32);
        // FIXME ^ Comment out this line
 
        // <code>_ref_to_i32</code> goes out of scope 
        // and is no longer borrowed.
    }
 
    // <code>boxed_i32</code> can now give up ownership 
    // to <code>eat_box</code> and be destroyed
    eat_box_i32(boxed_i32);
}

Et eksempel på Rust og konceptet med at låne og eje værdier. Fra Rustbyexample.com.

Et større problem er garbage collection (GC), hvor kørselsmiljøet fritstiller hukommelse på egen hånd, hvilket giver uforudsigelige forsinkelser i afviklingen. ‘Latency’ - hvor hurtigt en handling udføres - er meget vigtigt i en browser.

»I de seneste 12 måneder har vi arbejdet på at få has på alle kilder til latency i browseren, og dem er der mange af.«

Hvis brugeren forårsager en hændelse, som gør, at websiden skal se ud på en anden måde, så skal det helst ske på under 10 millisekunder, og hvis det tager over 100 millisekunder, bliver det bøvlet for brugeren.

»Der er mange kilder til latency i browseren, som hele tiden udfører komplekse opgaver. Vi kører Javascript, hægtet sammen med programmets event loops, så hvis vi putter uforudsigelige GC-pauser ind i systemet, bliver det hele bare meget værre.«

Et andet problem med f.eks. Java, er dets forskellige repræsentationer af tal og andre basale typer, hvor der både findes en såkaldt ‘primitiv-’ og objekt-udgave. Det er ikke særligt effektivt i forhold til hukommelsen. Den slags findes ikke i Rust, hvor bedre kontrol med hukommelsen giver højere ydelse, for ydelsen er meget afhængig af repræsentation af data og layout i hukommelsen.

Java og C#-programmer skjuler problemerne

Der findes dog store og komplekse programmer, som er skrevet i sikker kode og afvikles i en virtuel maskine eller lignende. Det gælder eksempelvis udviklingsværktøjer som Eclipse og Visual Studio.

»Den slags programmer kan skjule en masse latency. Den grundlæggende brugerinteraktion i Visual Studio består i, at brugeren indtaster kode. Hvert tastetryk kører noget logik til for eksempel at opmærke kode-delene. Når man klikker på en menu, er der måske noget animation, eller tegn tilføjes eller fjernes fra skærmen. Det er meget simple operationer.«

I browseren kan en webside have masser af fuldskærmsanimationer, og layoutet ændres måske dynamisk, mens brugeren ruller på siden. Hvert event køres igennem Javascript, som skal afvikles med just-in-time-princippet, med egen garbarge collector. De ting, man kan udføre med Javascript, er meget dynamiske. En webside kan tilknytte kode, der skal udføres, hver gang brugeren trykker på en tast.

»Der foregår bare meget mere i en browser, og hvis man tænker på Visual Studio, så kommer koden fra et og samme selskab, der er en projektleder bag, og koden i projektet er planlagt på forhånd. I browseren kommer måske 50 procent af koden fra det website, brugeren kigger på, og vi har ikke styr på kvaliteten af den kode.«

Jack Moffit medgiver, at hvis man ikke har de ydelsesmæssige krav, som en browser stiller, er der måske ikke så meget at hente i Rust. Han mener dog, at kode i Rust er billigere af udvikle end i C++ - fordi eksempelvis parallelisering er meget nemmere.

C++ fejler

Det, de fleste nybegyndere har det svært med i Rust, er kompilerens ‘borrow checker’ - eller låne-tjekker.

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 ‘borrow checker’, 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 jeg 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.«

Den tilgang kan gøre programmeringen svær, da man ikke kan have cirkulære referencer i Rust. Det betyder, at en grundlæggende datastruktur som en linked list, ikke kan kodes på sikker vis. Rust indeholder - i lighed med andre sikre sprog som C# og Java - en facilitet til at skrive kode, der overtræder reglerne. I Rust udmøntes det i nøgleordet ‘unsafe.’ Det kan tages i værk, når der ikke er andre muligheder. Og det kan anvendes i biblioteker, hvor der er større krav til kodekvalitet og test.

C++ har en funktion 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.

På spørgsmålet om, hvorvidt det overhovedet er muligt at forene 'sikkert' og 'effektivt', for eksempel i forbindelse med tjek af indekser i arrays, svarer Jack Moffitt, at det er en afvejning. Indeks-tjek er indbygget i Rust, som i andre sikre sprog, og det tager noget af ydelsen, men som regel er det ikke det store problem, mener han. Der vigtige er at undgå fejlene.

»Når man har programmeret i Rust i et stykke tid, finder man ud af, hvor nemt det er at begå fejl, og det er lidt uhyggeligt for mig nu, når jeg skriver kode i C - det føles bare ikke rart. Jeg ved, hvor mange fejl Rust fanger, men jeg kommer stadig til at lave de samme fejl, når jeg skriver C og C++.«

Tips og korrekturforslag til denne historie sendes til tip@version2.dk
Følg forløbet
Kommentarer (3)
Log ind eller Opret konto for at kommentere
Pressemeddelelser

Welcome to the Cloud Integration Enablement Day (Bring your own laptop)

On this track, we will give you the chance to become a "Cloud First" data integration specialist.
15. nov 10:31

Silicom i Søborg har fået stærk vind i sejlene…

Silicom Denmark arbejder med cutting-edge teknologier og er helt fremme hvad angår FPGA teknologien, som har eksisteret i over 20 år.
22. sep 2017

Conference: How AI and Machine Learning can accelerate your business growth

Can Artificial Intelligence (AI) and Machine Learning bring actual value to your business? Will it supercharge growth? How do other businesses leverage AI and Machine Learning?
13. sep 2017