Codificación defensiva (era Re: Pleonasmos booleanos)

Cuidado con las vulnerabilidades.

En Pleonasmos Booleanos, publicación del excelente blog Developeando, del cual me considero un ávido seguidor, Mario nos sensibiliza sobre la legibilidad de código. Nos dice que al escribir código debemos tomar en cuenta que no solo escribimos para la maquina. Concuerdo con él.

Sin embargo, hay que considerar qué pasa cuando lo que parece que es código redundante, realmente no lo es. Qué pasa si tenemos un código donde sólo debemos lanzar un misil cuando explícitamente no está prohibido:

function deboLanzarMisil(statusProhibicion) {
    result = false

    if (statusProhibicion == false)
        result = true;

    return result;
}

y lo que parece código redundante se legibiliza así:

function deboLanzarMisil(statusProhibicion) {
    return !statusProhibicion;
}

o incluso así:

function deboLanzarMisil(statusProhibicion) {
    if (!statusProhibicion)
        return true;

    return false;
}

En ambos casos habríamos introducido una vulnerabilidad (o bueno, de bug para arriba) que se presenta cuando statusProhibicion es null. En el primer código:

> deboLanzarMisil(true)
false
> deboLanzarMisil(false)
true
> deboLanzarMisil(null)
false

En ambos ejemplos de código legibilizado:

> deboLanzarMisil(true)
false
> deboLanzarMisil(false)
true
> deboLanzarMisil(null)
true

El código que estoy usando como ejemplo de lo que es supuestamente ilegible en realidad sigue un patrón de programación defensivo. En esta técnica:

  1. Se inicializa una variable a un valor seguro o valor por defecto.
  2. Sólo se modifica el valor bajo validaciones estrictas.

Claro que, aún cuando el siguiente código sigue esta técnica, habría sido inseguro, pero eso es porque se violó la regla #2:

function deboLanzarMisil(statusProhibicion) {
    result = false

    if (!statusProhibicion)
        result = true;

    return result;
}

El punto es que la única manera de corregir un potencialmente vulnerable return !x manteniendo la legibilidad hubiera sido usar más de una línea de código o invertir la lógica de la función.

El código que usa Mario para ejemplificar el caso de ilegibilidad resulta ser funcionalmente equivalente al código legibilizado y no son vulnerables ante una entrada null. Sin embargo consideremos los dos siguientes códigos, que no son funcionalmente equivalentes.

Este código es seguro:

function deboLanzarMisil(statusProhibicion) {
    if (statusProhibicion == false)
        return true;
    else
        return false;
}

> deboLanzarMisil(true)
false
> deboLanzarMisil(false)
true
> deboLanzarMisil(null)
false

Este otro código, aparentemente equivalente, resulta inseguro ante una entrada null:

function deboLanzarMisil(statusProhibicion) {
    if (statusProhibicion == true)
        return false;
    else
        return true;
}

> deboLanzarMisil(true)
false
> deboLanzarMisil(false)
true
> deboLanzarMisil(null)
true

Al final todo depende del lenguaje de programación. En SQL, por ejemplo, la lógica es distinta: NULL <> NULL da NULL y NULL == NULL da NULL.

En resumen, sí, hay que considerar que nuestro código será leído por otras personas o por nosotros mismos en el futuro (o por un violento psicópata que sabe dónde vives), pero recuerda que, en Javascript, x == false no es funcionalmente equivalente a !x.

alwayslast.bash

Este script permite poner en un archivo las últimas N líneas de una salida. Por ejemplo, ping [...] | alwayslast.bash FILE 10 permitiría que FILE tuviera las últimas 10 líneas de la salida de ping.

This script allows for a file to have the las N lines of an output. For example, ping [...] | alwayslast.bash FILE 10 would make FILE always have the last 10 lines from the output of ping.

#!/bin/bash

if [ "$#" -ne 2 ]; then
 echo "Usage: $0 output_file maxlines"
 exit 2
fi

FILE="$1"
MAXLINES="$2"

START=0
LINES=1

while IFS= read -r NEWLINE; do
 BUFFER[START]="$NEWLINE"

 TEMPFILE=$(mktemp)
 trap -- 'rm "$TEMPFILE"' EXIT INT TERM

 for INDEX in $(seq "$((START+1))" "$((LINES-1))") $(seq 0 "$START"); do
 printf '%s\n' "${BUFFER[$INDEX]}"
 done > "$TEMPFILE"

 chmod --reference="$FILE" "$TEMPFILE"
 mv "$TEMPFILE" "$FILE"
 trap -- EXIT INT TERM

 LINES="$((LINES+1))"
 if [ "$LINES" -gt "$MAXLINES" ]; then
 LINES="$MAXLINES"
 fi
 START="$(((START + 1) % MAXLINES))"
done

Gracias a Eduardo Bustamante por sus correcciones.

Feed al podcast Dr. IPv6

LAC-TF es la Fuerza de Trabajo de IPv6 en la región de Latinoamérica y el Caribe

LAC-TF es la Fuerza de Trabajo de IPv6 en la región de Latinoamérica y el Caribe

Dr. IPv6 es un podcast en español preparado por LAC-TF y dirigido por Alejandro Acosta en el que se busca a especialistas para contestar preguntas que tenga la comunidad sobre IPv6. Puedes enviar tus preguntas a dr.ipv6@lacnic.net.

Debido a que el podcast aún no tiene un feed RSS, sólo los audios, decidí hacer un feed para poder agregar este útil e intersante podcast a mi Rhythmbox y AntennaPod.

Aquí lo comparto con ustedes. Se actualiza cada hora según lo que se publique en la página oficial de Dr. IPv6, extrayendo los metadatos y convirtiéndola en formato RSS. Siéntete en la libertad de usarlo para agregar Dr. IPv6 al “podcatcher” de tu preferencia.

La dirección de los feeds:

Dr. IPv6 en formato Ogg: http://blog.alvarezp.org/dripv6/feed-ogg/feed.xml

Dr. IPv6 en formato MP3: http://blog.alvarezp.org/dripv6/feed-mp3/feed.xml

Para qué sirve la tilde en el idioma español

TL;DR en tres enunciados

  • La mayoría de las palabras en español que son graves (o llanas) y terminan en n, s o vocal; no llevan tilde.
  • Si terminan en otra letra por defecto son agudas y tampoco llevan tilde.
  • La tilde sirve para romper lo anterior: agudas que terminan en n, s o vocal, graves que terminan en otra letra y todas las esdrújulas.

Sigue leyendo

Actualización sobre cointoss en Bash para evitar azar cargado

Hace unas 3 semanas publiqué una nota personal para implementar “cosstoin” en Bash:

cointoss() {
    # Probability is $1/$2, for example, cointoss 3 5
    # will hit 60% of the time. Defaults to 1/2 if no
    # arguments are supplied.
    [ $((RANDOM % ${2-2})) -lt ${1-1} ];
}

Sigue leyendo