martes, 25 de febrero de 2014

La que se monta por un GOTO en el código de Apple… y es que de GOTO va el artículo

Hace unos días Apple ha presentado una actualización para iOS 7 e iOS 6 para corregir una vulnerabilidad en una función de la librería del sistema SSL/TLS, usado para conexiones seguras. Y aun tendrán que sacar un parche para OSX próximamente, porque ese bug también le afecta.
El fallo/bug puede verse en el código que aparece a continuación resaltado en rojo, fragmento de código obtenido directamente de la web de Apple (al final hay el link al archivo de código concreto):
  45:      hashOut.data = hashes + SSL_MD5_DIGEST_LEN;

  46:      hashOut.length = SSL_SHA1_DIGEST_LEN;

  47:      if ((err = SSLFreeBuffer(&hashCtx)) != 0)

  48:          goto fail;

  49:   

  50:      if ((err = ReadyHash(&SSLHashSHA1, &hashCtx)) != 0)

  51:          goto fail;

  52:      if ((err = SSLHashSHA1.update(&hashCtx, &clientRandom)) != 0)

  53:          goto fail;

  54:      if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)

  55:          goto fail;

  56:      if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)

  57:          goto fail;

  58:          goto fail;

  59:      if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)

  60:          goto fail;

  61:   

  62:      err = sslRawVerify(ctx,

  63:                         ctx->peerPubKey,

  64:                         dataToSign,                /* plaintext */

  65:                         dataToSignLen,            /* plaintext length */

  66:                         signature,

  67:                         signatureLen);

  68:      if(err) {

  69:          sslErrorLog("SSLDecodeSignedServerKeyExchange: sslRawVerify "

  70:                      "returned %d\n", (int)err);

  71:          goto fail;

  72:      }

  73:   

  74:  fail:

  75:      SSLFreeBuffer(&signedHashes);

  76:      SSLFreeBuffer(&hashCtx);

  77:      return err;

  78:   

  79:  }



El fallo en si es muy grave, aunque tremendamente fácil de corregir, solo hay que eliminar esa línea de código… aunque solo afecta a las últimas versiones, ya que se introdujo a finales del 2012 (antes no estaba presente).

No voy a meterme si ha sido la NSA, a petición de esta, o si ha sido fruto de un merge mal revisado y después se aprovechó la NSA o no…

El artículo no va de eso, sino del revuelo entre muchos con conocimientos de programación al ver tantos GOTO juntos (o directamente por haber algún GOTO).

Con la programación estructurada, el uso de GOTO se vio como el mayor problema de legibilidad del código... por ello se debía usar lo mínimo posible y solo para ciertos fines y jamás de los jamases un uso que rompiera el ámbito (en cristiano, si se usa dentro de una función, jamás debe sacarte de la función).

ProgEstruc

Y para muchos autores el uso de GOTO directamente debía ser erradicado, por ejemplo Edsger Dijkstra, el padre del algoritmo de los caminos más cortos (que suele llamarse como su autor), el que creo la expresión “la crisis del software”… uno de los padres de la programación estructurada y un acérrimo enemigo del uso de GOTO.

Aun así, por las mismas fechas, otros más importantes en las ciencias de la computación, como Donald Knuth, que incluso escribió un libro sobre el uso de la instrucción GOTO en programación estructurada «Structured Programming with goto Statements».

Más en nuestros días, por ejemplo es famoso el capítulo 7 de la guía de estilo de Linux para programadores, pues recomienda el uso de GOTO para ciertos fines y donde es adecuado, etc.

Pero a pesar de lo escrito en los 2 párrafos anteriores, existe una muy popular animadversión a los GOTO, especialmente en ambientes educativos, en donde se llega a criminalizar casi el recurrir a esa característica de tantos lenguajes y un recurso muy útil para ciertos fines. Pero esa animadversión que aprendieron muchos cuando dieron clases de programación, pues acaba siendo anatema de FE para muchos programadores.

Y esa animadversión por el GOTO muchas veces llega muy lejos. Hay programadores que por no usar un GOTO, pues acaban convirtiendo lo que sería una función de 30 o 40 líneas de código en 200 líneas (si alguien no me cree, alguien intente unificar 6 o siete puntos de salida en una sola en un código en donde hay enlazadas varias estructuras y confirmará lo que viene después). Por encima, lo que sería código muy legible y fácilmente modificable, para a ser código imposible de mantener y leer. Cualquier cambio mínimo que hubiese que acometer, podría implicar que la mejor opción fuese reescribir toda la función… simplificando, por no usar unos GOTO claramente justificables, acaban contradiciendo el espíritu de la programación estructurada (porque aunque programes en un lenguaje orientado a objetos, los principios de la programación estructura siguen siendo válidos)…

Y es que hay casos en donde el uso del GOTO no es que sea admisible, sino que es la mejor opción. Simplemente hay que saber el como y el cuando de un uso de GOTO correcto.

Ejemplos de uso de GOTO correcto y recomendable:



  • Toda función tiene que tener centralizada la salida de la función (aunque no devuelva nada), ya que debe actuar como una caja negra con una sola entrada y una sola salida... o más claro: todo los RETURN (haya uno o mil) deben estar juntos. No debe haber RETURNs mezclados con el resto del código de la función.


  • Cuando el uso de un GOTO reduzca la complejidad y facilite la legibilidad del código... hay que decir que normalmente este punto se debe a lo comentado en el anterior, que hacer que una función medio compleja, pues hacer que terminen de forma unificada implicaría una complicación estúpidamente innecesaria para cumplir el punto anterior de buenas prácticas... en otros casos habría que justificarlo bien, pero suele ser por temas similares, en donde es mejor tener 3 GOTO que complicar estúpidamente el código.


  • También para la gestión de excepciones en lenguajes que carezcan de estructuras apropiadas... y que normalmente viene a relacionarse con el primer punto de estos, ya que normalmente las excepciones acaban implicando la finalización de la función y toda función debe terminar controladamente y en siempre unificadamente.

Y hay algunos puntos más que podría mencionar... pero creo que la idea está clara, y aunque como suele pasar, cuando muchos aprenden a programar, pues les dicen que usar un GOTO es casi un crimen e internalizan tanto que después no lo usan ni cuando se debe usar... y cuando ven uno, se rasgan las vestiduras.

Bueno, creo que ya es suficiente. Creo que el artículo ya es demasiado largo para lo que quería decir y “a buen entendedor pocas palabras bastan”.

Hasta próximos artículos.

NOTA: Fichero de código en donde está la función afectada por el problema: Link

No hay comentarios:

Publicar un comentario