Fragilt binärt gränssnittsproblem

Det ömtåliga binära gränssnittsproblemet eller FBI är en brist hos vissa objektorienterade kompilatorer för programmeringsspråk , där interna ändringar i ett underliggande klassbibliotek kan göra att underliggande bibliotek eller program slutar fungera. Det är ett exempel på mjukvarans sprödhet .

Detta problem kallas oftare för det sköra basklassproblemet eller FBC ; den termen har dock en vidare betydelse.

Orsak

Problemet uppstår på grund av en "genväg" som används med kompilatorer för många vanliga objektorienterade (OO) språk, en designfunktion som behölls när OO-språken utvecklades från tidigare icke-OO-strukturerade programmeringsspråk som C och Pascal .

I dessa språk fanns det inga objekt i modern mening, men det fanns en liknande konstruktion känd som en post (eller "struktur" i C) som innehöll en mängd relaterad information i ett minne. Delarna i en viss post nåddes genom att hålla reda på startplatsen för posten och känna till förskjutningen från den startpunkten till den aktuella delen. Till exempel kan en "person"-post ha ett förnamn, efternamn och mellaninitial, för att komma åt initialen som programmeraren skriver thisPerson.middleInitial som kompilatorn förvandlar till något i stil med en = location(thisPerson) + offset(middleInitial) . Moderna processorer inkluderar vanligtvis instruktioner för denna vanliga typ av åtkomst.

När objektorienterade språkkompilatorer först utvecklades användes mycket av den befintliga kompilatortekniken, och objekt byggdes ovanpå rekordkonceptet. På dessa språk hänvisades till objekten utifrån deras utgångspunkt, och deras offentliga data, så kallade "fält", nåddes genom den kända offset. I själva verket var den enda ändringen att lägga till ytterligare ett fält till posten, som är inställd på att peka på en oföränderlig virtuell metodtabell för varje klass, så att posten beskriver både dess data och metoder (funktioner). När de kompileras används offseten för att komma åt både data och kod (via den virtuella metodtabellen).

Symtom

Detta leder till problem i större program när de är konstruerade från bibliotek . Om författaren till biblioteket ändrar storleken eller layouten på de publika fälten i objektet är förskjutningarna nu ogiltiga och programmet kommer inte längre att fungera. Det här är FBI-problemet.

Även om förändringar i implementeringen kan förväntas orsaka problem är det lömska med FBI att ingenting egentligen har förändrats, bara layouten på objektet som är gömt i ett kompilerat bibliotek. Man kan förvänta sig att om man ändrar doSomething till doSomethingElse att det kan orsaka problem, men i det här fallet kan man orsaka problem utan att ändra doSomething , det kan orsakas lika lätt som att flytta runt rader med källkod för tydlighetens skull. Ännu värre, programmeraren har liten eller ingen kontroll över den resulterande layouten som genereras av kompilatorn, vilket gör detta problem nästan helt dolt.

I komplexa objektorienterade program eller bibliotek kan klasserna på högsta nivå ärva från tiotals klasser. Var och en av dessa basklasser kan också ärvas av hundratals andra klasser. Dessa basklasser är ömtåliga eftersom en liten ändring av en av dem kan orsaka problem för alla klasser som ärver från den, antingen direkt eller från en annan klass som gör det. Detta kan få biblioteket att kollapsa som ett korthus eftersom många klasser skadas av en ändring av en basklass. Problemet kanske inte märks när ändringarna skrivs om arvsträdet är komplext. Utvecklaren som modifierar basklassen är i allmänhet omedveten om vilka klasser, utvecklade av andra, som använder den.

Lösningar

språk

En lösning på problemet med det ömtåliga binära gränssnittet är att skriva ett språk som vet att problemet finns, och som inte låter det hända i första hand. De flesta specialskrivna OO-språk, i motsats till de som utvecklats från tidigare språk, konstruerar alla sina offsettabeller vid laddningstid. Ändringar av layouten på biblioteket kommer att "märkas" vid den tidpunkten. Andra OO-språk, som Self , konstruerar allt under körning genom att kopiera och modifiera objekten som finns i biblioteken, och har därför inte riktigt en basklass som kan vara ömtålig. Vissa språk, som Java , har omfattande dokumentation om vilka ändringar som är säkra att göra utan att orsaka FBI-problem.

En annan lösning är att skriva ut en mellanfil som listar offseten och annan information från kompileringsstadiet, känd som metadata. Länkaren använder sedan denna information för att korrigera sig själv när biblioteket laddas in i en applikation. Plattformar som .NET gör detta.

Marknaden har dock valt programmeringsspråk som C++ som verkligen är "positionsberoende" och därför uppvisar FBI. I dessa fall finns det fortfarande ett antal lösningar på problemet. Man lägger bördan på biblioteksförfattaren genom att låta dem infoga ett antal "platshållare"-objekt ifall de skulle behöva lägga till ytterligare funktionalitet i framtiden (detta kan ses i strukturerna som används i DirectX-biblioteket ) . Den här lösningen fungerar bra tills du får slut på dessa dummies - och du vill inte lägga till för många eftersom det tar upp minne.

Objective-C 2.0 tillhandahåller icke-bräckliga instansvariabler genom att ha en extra nivå av indirekt, till exempel variabel åtkomst.

En annan dellösning är att använda bromönstret , ibland känt som " Pimpl " ("pekare till implementering"). Qt -ramverket är ett exempel på en sådan implementering. Varje klass definierar endast en datamedlem, vilket är en pekare till strukturen som innehåller implementeringsdata. Storleken på själva pekaren kommer sannolikt inte att ändras (för en given plattform), så att ändra implementeringsdatan påverkar inte storleken på den offentliga strukturen. Detta undviker dock inte andra brytande förändringar som att introducera virtuella metoder till en klass som inte har några, eller att ändra arvsgrafen.

Länkare

En annan lösning kräver en smartare länk. I den ursprungliga versionen av Objective-C tillät biblioteksformatet flera versioner av ett bibliotek och inkluderade viss funktionalitet för att välja rätt bibliotek när det anropades. Detta behövdes dock inte alltid eftersom förskjutningarna bara behövdes för fält, eftersom metodförskjutningar samlades in vid körning och inte kunde orsaka FBI. Eftersom metoder tenderar att ändras oftare än fält, hade ObjC få FBI-problem i första hand, och de som det gjorde kunde korrigeras med versionssystemet. Objective-C 2.0 lade till en "modern runtime" som löste FBI-problemet även för fält. Dessutom använder TOM-språket insamlade förskjutningar av runtime för allt, vilket gör FBI omöjligt.

Att använda statiska istället för dynamiska bibliotek där det är möjligt är en annan lösning, eftersom biblioteket då inte kan modifieras utan att även kompilera om applikationen och uppdatera de offset som den använder. Men statiska bibliotek har allvarliga egna problem, såsom en större binär och oförmåga att använda nyare versioner av biblioteket "automatiskt" när de introduceras.

Arkitektur

I dessa språk minskas problemet genom att upprätthålla enstaka arv (eftersom detta minskar komplexiteten i arvsträdet), och genom att använda gränssnitt istället för basklasser med virtuella funktioner , eftersom gränssnitten i sig inte innehåller kod, bara en garanti för att varje metodsignatur som gränssnittet deklarerar kommer att stödjas av varje objekt som implementerar gränssnittet.

Distributionsmetod

Hela problemet kollapsar om källkoden för biblioteken är tillgänglig. Då kommer en enkel omkompilering att göra susen.

Se även

externa länkar