Hopp til innhold
NorscodeNorscode

Inne i kjøretiden: minne, sikkerhet og hvorfor programmet ditt ikke kan lyve

EksempelAv Norscode-prosjektet

En gjennomgang av hvordan Norscode-kjøretiden håndterer minne, hvorfor kapabilitetsmodellen ikke kan omgås, og hva det betyr for kode du ikke har lest.

De fleste språk lar deg ikke se hva som skjer under. Denne artikkelen går gjennom hvordan Norscode-kjøretiden faktisk fungerer — fordi det forklarer hvorfor enkelte ting er trygge her som ikke er det andre steder.

Arenaen

All allokering går gjennom en arena med 8-byte justering. Arenaen har en øvre grense, gjenbruker frigjorte blokker etter first-fit, og har vern mot dobbel frigjøring. Går minnet tomt, får du en ryddig feil — ikke udefinert oppførsel.

Det viktige er at arenaen er flyttbar. Ved komprimering flyttes levende objekter fysisk sammen, og en relokasjonstabell oppdaterer alle adressene som pekte på dem. Fragmentering blir dermed ikke en langsom lekkasje slik den ofte blir i langtkjørende tjenester.

Innsamlingen

Søppelinnsamleren er mark/sweep med aktiv rammeskanning: kjøretiden går gjennom kallstakkens rammer for å finne røttene, i stedet for å stole på at programmereren har holdt orden.

Den håndterer sykluser. To objekter som peker på hverandre uten at noe annet peker på dem, blir samlet inn — noe ren referansetelling ikke klarer uten hjelp.

Det føres byte-regnskap, og innsamlingen er terskelstyrt: små, hyppige innsamlinger av unge objekter, sjeldnere fulle runder. Objekter som overlever nok runder, forfremmes fra young til old. Det følger den vanlige observasjonen at de fleste objekter dør unge, og at de som overlever de første rundene som regel lever lenge.

Når kode ikke kan flyttes

En detalj som sier mye om hvor nøye dette er gjort: regioner som holdes av kompilatorens native del med rå C-pekere, blir pinnet. De flyttes ikke under komprimering, fordi en rå peker ikke kan oppdateres av relokasjonstabellen. Å flytte dem ville gitt en peker som stille pekte feil — den verste klassen av feil.

Dette er den typen detalj du bare får til hvis du eier hele stakken.

Hvorfor kapabiliteter ikke kan omgås

Her er poenget som betyr mest i praksis.

I de fleste språk arver et program rettighetene til brukeren som startet det. En avhengighet fem lag ned i treet kan lese nøkkelfilene dine, skrive hvor som helst og ringe ut på nettet — og du oppdager det ikke uten å granske hver linje.

I Norscode gis tilgangen når programmet startes:

NORSCODE_VM_CAPABILITIES="disk.read" \
NORSCODE_VM_DISK_ROOT="/srv/data" \
  nc run rapport.no

Det avgjørende er at det ikke finnes noe API for å be om mer underveis. Kapabilitetene er ikke en innstilling programmet leser og kan velge å ignorere — de er grensene kjøretiden håndhever rundt hver eneste operasjon. Et kall som går utenfor, stopper med manglar capability.

Det betyr at et bibliotek du ikke har lest, ikke kan nå lenger enn du har sluppet det. Ikke fordi det oppfører seg pent, men fordi veien ikke finnes.

Hva dette gir deg

Tre ting som er vanskelige å få til hver for seg, og som henger sammen her:

  1. Minnet er trygt uten at du håndterer det. Ingen manuell frigjøring, ingen bruk-etter-frigjøring, ingen dobbel frigjøring.
  2. Langtkjørende tjenester fragmenterer ikke. Komprimeringen flytter levende objekter sammen i stedet for å la hullene vokse.
  3. Tilgang er noe du gir, ikke noe som antas. Det gjør det forsvarlig å kjøre kode du ikke har gransket i sin helhet.

Hvor du finner det

Alt dette er skrevet i Norscode og kan leses: minnehåndteringen i std.runtime_memory og std.runtime.allocator, kallstakken i std.runtime_stack, typesystemet under kjøring i std.runtime_type, unntakshåndtering i std.runtime_exception, sikkerhetslaget i std.runtime_security, trådene i std.sched og std.tråd, og en baseline-JIT i std.runtime_jit.

Du trenger ikke lære et annet språk for å forstå hvordan koden din blir kjørt. Det er en av de underliggende grunnene til at språket er selvhostende: verktøykjeden er lesbar for alle som kan språket den kompilerer.

Les mer om språket · Se standardbiblioteket

Les også

Tilbake til oversikten