Vés al contingut

Seguretat de tipus

De la Viquipèdia, l'enciclopèdia lliure

En informàtica, la seguretat de tipus i la solidesa de tipus són el grau en què un llenguatge de programació desincentiva o evita els errors de tipus. La seguretat de tipus de vegades es considera alternativament una propietat de les eines d'un llenguatge informàtic; és a dir, algunes eines són segures pel que fa al tipus i el seu ús no donarà lloc a errors de tipus, mentre que altres eines del mateix llenguatge poden no ser segures pel que fa al tipus i un programa que les utilitza pot trobar errors de tipus. Els comportaments classificats com a errors de tipus per un llenguatge de programació determinat solen ser els que resulten dels intents de realitzar operacions sobre valors que no són del tipus de dades adequat, per exemple, afegir una cadena a un enter quan no hi ha cap definició de com gestionar aquest cas. Aquesta classificació es basa en part en l'opinió.

L'aplicació de tipus pot ser estàtica, detectant possibles errors en temps de compilació, o dinàmica, associant informació de tipus amb valors en temps d'execució i consultant-los segons calgui per detectar errors imminents, o una combinació d'ambdues opcions.[1] L'aplicació de tipus dinàmica sovint permet executar programes que no serien vàlids amb l'aplicació estàtica.

En el context dels sistemes de tipus estàtics (en temps de compilació), la seguretat de tipus normalment implica (entre altres coses) una garantia que el valor final de qualsevol expressió serà un membre legítim del tipus estàtic d'aquesta expressió. El requisit precís és més subtil que això; vegeu, per exemple, subtipificació i polimorfisme per a complicacions.

Definicions

[modifica]

Intuïtivament, la solidesa del tipus es captura amb l'afirmació concisa de Robin Milner que

Els programes ben tipificats no poden "sortir malament".

En altres paraules, si un sistema de tipus és correcte, les expressions acceptades per aquest sistema de tipus han d'avaluar-se com a valor del tipus adequat (en lloc de produir un valor d'un altre tipus no relacionat o fallar amb un error de tipus). Vijay Saraswat proporciona la següent definició relacionada:

Un llenguatge és segur pel que fa al tipus si les úniques operacions que es poden realitzar sobre les dades del llenguatge són les que permet el tipus de les dades.[2]

Tanmateix, el que significa precisament que un programa estigui "ben tipificat" o que "es faci malament" són les propietats de la seva semàntica estàtica i dinàmica, que són específiques de cada llenguatge de programació. En conseqüència, una definició formal i precisa de la solidesa de tipus depèn de l'estil de semàntica formal utilitzada per especificar un llenguatge. El 1994, Andrew Wright i Matthias Felleisen van formular el que s'ha convertit en la definició estàndard i la tècnica de prova per a la seguretat de tipus en llenguatges definits per semàntica operativa,[3] que és la més propera a la noció de seguretat de tipus tal com l'entenen la majoria dels programadors. Segons aquest enfocament, la semàntica d'un llenguatge ha de tenir les dues propietats següents per ser considerada sòlida de tipus:

Progrés
Un programa ben tipificat mai es "encalla": cada expressió o bé ja és un valor o bé es pot reduir a un valor d'alguna manera ben definida. En altres paraules, el programa mai entra en un estat indefinit on no siguin possibles més transicions.
Preservació (o reducció de subjectes)
Després de cada pas d'avaluació, el tipus de cada expressió roman igual (és a dir, es conserva el seu tipus).

També s'han publicat diversos altres tractaments formals de la solidesa dels tipus en termes de semàntica denotacional i semàntica operacional estructural.[4]

Relació amb altres formes de seguretat

[modifica]

Aïlladament, la solidesa del tipus és una propietat relativament feble, ja que essencialment només afirma que les regles d'un sistema de tipus són internament consistents i no es poden subvertir. Tanmateix, a la pràctica, els llenguatges de programació estan dissenyats de manera que una bona tipificació també implica altres propietats més fortes, algunes de les quals inclouen:

  • Prevenció d'operacions il·legals. Per exemple, un sistema de tipus pot rebutjar l'expressió 3 / "Hello, World" com a invàlida, perquè l'operador de divisió no està definit per a un divisor de cadena.
  • Seguretat de la memòria
    • Els sistemes de tipus poden evitar que els punters salvatges que d'altra manera podrien sorgir d'un punter a un tipus d'objecte siguin tractats com a punter a un altre tipus.
    • Els sistemes de tipus més sofisticats, com ara els que admeten tipus dependents, poden detectar i rebutjar accessos fora de límit, evitant possibles desbordaments de memòria intermèdia.[5]
  • Errors lògics originats en la semàntica de diferents tipus. Per exemple, les polzades i els mil·límetres es poden emmagatzemar com a nombres enters, però no s'han de substituir ni sumar. Un sistema de tipus pot imposar dos tipus diferents d'enters per a ells.

Llenguatges de tipus segurs i de tipus no segurs

[modifica]

La seguretat de tipus sol ser un requisit per a qualsevol llenguatge de joguina (és a dir, llenguatge esotèric) proposat en la investigació acadèmica de llenguatges de programació. Molts llenguatges, en canvi, són massa grans per a proves de seguretat de tipus generades per humans, ja que sovint requereixen la comprovació de milers de casos. No obstant això, s'ha demostrat que alguns llenguatges com ara Standard ML, que té una semàntica rigorosament definida, compleixen una definició de seguretat de tipus. Es creu que alguns altres llenguatges com ara Haskell compleixen alguna definició de seguretat de tipus, sempre que no s'utilitzin certes característiques "d'escapada" (per exemple, Haskell's , utilitzat per "escapar" de l'entorn restringit habitual en què és possible l'E/S, eludeix el sistema de tipus i, per tant, es pot utilitzar per trencar la seguretat de tipus.[6]) El joc de paraules de tipus és un altre exemple d'aquesta característica "d'escapada". Independentment de les propietats de la definició del llenguatge, es poden produir certs errors en temps d'execució a causa d'errors en la implementació o en biblioteques enllaçades escrites en altres llenguatges; aquests errors podrien fer que un tipus d'implementació determinat no fos segur en determinades circumstàncies. Una versió anterior de la màquina virtual Java de Sun era vulnerable a aquest tipus de problema.[7]

Tipat forta i feble

[modifica]

Els llenguatges de programació sovint es classifiquen col·loquialment com a fortament tipats o feblement tipats (també amb tipatge lliure) per referir-se a certs aspectes de la seguretat de tipus. El 1974, Liskov i Zilles van definir un llenguatge fortament tipat com aquell en què "sempre que un objecte es passa d'una funció que fa la crida a una funció que fa la crida, el seu tipus ha de ser compatible amb el tipus declarat a la funció que fa la crida".[8] El 1977, Jackson va escriure: "En un llenguatge fortament tipat, cada àrea de dades tindrà un tipus diferent i cada procés indicarà els seus requisits de comunicació en termes d'aquests tipus".[9] En canvi, un llenguatge feblement tipat pot produir resultats imprevisibles o pot realitzar una conversió de tipus implícita.[10]

Gestió de memòria i seguretat de tipus

[modifica]

La seguretat de tipus està estretament relacionada amb la seguretat de memòria. Per exemple, en una implementació d'un llenguatge que té algun tipus que permet alguns patrons de bits però no d'altres, un error de memòria de punter penjant permet escriure un patró de bits que no representa un membre legítim de en una variable morta de tipus , causant un error de tipus quan es llegeix la variable. Per contra, si el llenguatge és segur per a la memòria, no pot permetre que un enter arbitrari s'utilitzi com a punter, per tant, hi ha d'haver un punter o tipus de referència separat.

Com a condició mínima, un llenguatge de tipus segur no ha de permetre punters penjants entre assignacions de diferents tipus. Però la majoria de llenguatges imposen l'ús correcte dels tipus de dades abstractes definits pels programadors, fins i tot quan això no és estrictament necessari per a la seguretat de la memòria o per a la prevenció de qualsevol tipus d'error catastròfic. A les assignacions se'ls assigna un tipus que descriu el seu contingut, i aquest tipus es fixa durant la durada de l'assignació. Això permet que l'anàlisi d'àlies basada en tipus infereixi que les assignacions de diferents tipus són diferents.

La majoria de llenguatges de tipus segurs utilitzen la recollida de brossa. Pierce diu que "és extremadament difícil aconseguir la seguretat de tipus en presència d'una operació de desassignació explícita", a causa del problema del punter penjant.[11] Tanmateix, Rust generalment es considera segur de tipus i utilitza un verificador de préstecs per aconseguir la seguretat de memòria, en lloc de la recollida de brossa.

Seguretat de tipus en llenguatges orientats a objectes

[modifica]

En els llenguatges orientats a objectes, la seguretat de tipus sol ser intrínseca al fet que hi hagi un sistema de tipus. Això s'expressa en termes de definicions de classe.

Una classe defineix essencialment l'estructura dels objectes derivats d'ella i una API com un contracte per gestionar aquests objectes. Cada vegada que es crea un objecte nou, complirà amb aquest contracte.

Cada funció que intercanvia objectes derivats d'una classe específica, o que implementa una interfície específica, s'adherirà a aquest contracte: per tant, en aquesta funció, les operacions permeses sobre aquest objecte només seran les definides pels mètodes de la classe que l'objecte implementa. Això garantirà que es preservi la integritat de l'objecte.

Les excepcions a això són els llenguatges orientats a objectes que permeten la modificació dinàmica de l'estructura de l'objecte o l'ús de la reflexió per modificar el contingut d'un objecte per superar les restriccions imposades per les definicions dels mètodes de la classe.

Problemes de seguretat de tipus en llenguatges específics

[modifica]

Ada va ser dissenyat per ser adequat per a sistemes encastats, controladors de dispositius i altres formes de programació de sistemes, però també per fomentar la programació amb seguretat de tipus. Per resoldre aquests objectius contradictoris, Ada limita la inseguretat de tipus a un cert conjunt de construccions especials els noms de les quals solen començar amb la cadena. Unchecked_Deallocation es pot prohibir eficaçment d'una unitat de text Ada aplicant a aquesta unitat. S'espera que els programadors utilitzin Les construccions són molt acurades i només quan cal; els programes que no les utilitzen són segures pel que fa a tipus.

El llenguatge de programació C és segur pel que fa a tipus en contextos limitats; per exemple, es genera un error en temps de compilació quan s'intenta convertir un punter a un tipus d'estructura en un punter a un altre tipus d'estructura, tret que s'utilitzi una conversió explícita. Tanmateix, diverses operacions molt comunes no són segures pel que fa a tipus; per exemple, la manera habitual d'imprimir un enter és alguna cosa com printf("%d", 12), on %d indica printf en temps d'execució que esperi un argument enter. (Alguna cosa com printf("%s", 12), que indica a la funció que esperi un punter a una cadena de caràcters i, tanmateix, proporciona un argument enter, pot ser acceptada pels compiladors, però produirà resultats no definits.) Això es mitiga parcialment amb alguns compiladors (com ara gcc) que comproven les correspondències de tipus entre els arguments printf i les cadenes de format.

Algunes característiques de C++ que promouen un codi més segur pel que fa als tipus:

C# és segur pel que fa als tipus. Admet punters sense tipus, però s'hi ha d'accedir mitjançant la paraula clau "unsafe", que es pot prohibir a nivell de compilador. Té compatibilitat inherent amb la validació de conversions en temps d'execució. Les conversions es poden validar mitjançant la paraula clau "as", que retornarà una referència nul·la si la conversió no és vàlida, o mitjançant una conversió d'estil C que generarà una excepció si la conversió no és vàlida. Vegeu Operadors de conversió de C Sharp.

Una dependència excessiva del tipus d'objecte (del qual deriven tots els altres tipus) corre el risc de frustrar el propòsit del sistema de tipus C#. Normalment és una millor pràctica abandonar les referències a objectes en favor dels genèrics, de manera similar a les plantilles en C++ i els genèrics en Java.

Java

[modifica]

El llenguatge Java està dissenyat per aplicar la seguretat de tipus. Tot el que passa a Java passa dins d'un objecte i cada objecte és una instància d'una classe.

Per implementar l'aplicació de la seguretat de tipus, cada objecte, abans del seu ús, ha de ser assignat. Java permet l'ús de tipus primitius però només dins d'objectes assignats correctament.

Pascal

[modifica]

Pascal ha tingut diversos requisits de seguretat de tipus, alguns dels quals es mantenen en alguns compiladors. Quan un compilador de Pascal dicta "tipificació estricta", dues variables no es poden assignar entre si tret que siguin compatibles (com ara la conversió d'un nombre enter a real) o assignades al subtipus idèntic

Referències

[modifica]
  1. «What to know before debating type systems | Ovid [blogs.perl.org (en anglès). blogs.perl.org. [Consulta: 27 juny 2023].
  2. Saraswat, Vijay. «Java is not type-safe» (en anglès), 15-08-1997. [Consulta: 8 octubre 2008].
  3. Wright, A. K.; Felleisen, M. (en anglès) Information and Computation, 115, 1, 15-11-1994, p. 38–94. DOI: 10.1006/inco.1994.1093. ISSN: 0890-5401 [Consulta: free].
  4. Damas, Luis. «Principal type-schemes for functional programs». A: Proceedings of the 9th ACM SIGPLAN-SIGACT symposium on Principles of programming languages - POPL '82 (en anglès). Association for Computing Machinery, 25 January 1982, p. 207–212. DOI 10.1145/582153.582176. ISBN 0897910656.
  5. Henriksen, Troels. «Towards size-dependent types for array programming». A: Proceedings of the 7th ACM SIGPLAN International Workshop on Libraries, Languages and Compilers for Array Programming (en anglès). Association for Computing Machinery, 17 June 2021, p. 1–14. DOI 10.1145/3460944.3464310. ISBN 9781450384667.
  6. «System.IO.Unsafe» (en anglès). GHC libraries manual: base-3.0.1.0. Arxivat de l'original el 2008-07-05. [Consulta: 17 juliol 2008].
  7. Saraswat, Vijay. «Java is not type-safe» (en anglès), 15-08-1997. [Consulta: 8 octubre 2008].
  8. Liskov, B; Zilles, S ACM SIGPLAN Notices, 9, 4, 1974, p. 50–59. DOI: 10.1145/942572.807045.
  9. Jackson, K. «Parallel processing and modular software construction». A: Design and Implementation of Programming Languages (en anglès). 54, 1977, p. 436–443 (Lecture Notes in Computer Science). DOI 10.1007/BFb0021435. ISBN 3-540-08360-X.
  10. «CS1130. Transition to OO programming. – Spring 2012 --self-paced version» (en anglès). Cornell University, Department of Computer Science, 2005. [Consulta: 15 setembre 2023].
  11. Pierce, Benjamin C. Types and programming languages (en anglès). Cambridge, Mass.: MIT Press, 2002, p. 158. ISBN 0-262-16209-1.