En C, la conversión automática de tipos funciona según el principio de "conversaciones aritméticas usuales". Al participar en una expresión números declarados con diferentes signos (signed/unsigned), se producen transformaciones según las siguientes reglas:
Ejemplo de aritmética peligrosa:
int a = -1; // signed unsigned int b = 1; printf("%d\n", a < b); // siempre false, ya que 'a' se convierte en un unsigned muy grande
El resultado: -1, al ser convertido a unsigned, se convierte en un número positivo muy grande.
Lo que es importante recordar:
Pregunta: ¿Qué resultado devolverá la expresión (int)(unsigned)-1?
Respuesta inesperadamente incorrecta: "-1, ya que -1 se convierte a int."
Respuesta correcta:
En la expresión (unsigned)-1, primero se realiza la conversión de -1 a unsigned (en una plataforma de 32 bits esto es 0xFFFFFFFF), luego se convierte de nuevo a signed int, lo cual también depende de la implementación, pero a menudo esto resulta nuevamente en -1 (si se usa el complemento a dos). Sin embargo, es más correcto decir: El resultado depende de los estándares de representación de números signed, pero en la mayoría de las implementaciones será -1.
Ejemplo:
int x = (int)(unsigned)-1; // x == -1 en la mayoría de las plataformas
Historia
En el manejador de cadenas se utilizó una función para comparar tamaños: si la longitud de la cadena puede ser negativa, el programa reportaría un error. Sin embargo, la longitud era de tipo size_t (unsigned), y la comparación
if(length < 0)siempre devuelve false, lo que llevó a un bucle infinito y desbordamiento de memoria.
Historia
Al analizar un protocolo, los paquetes de red contenían campos como unsigned, mientras que las variables locales eran signed. Debido al desbordamiento unsigned al procesar ciertos valores, se produjeron cálculos incorrectos de longitud del paquete, lo que resultó en una vulnerabilidad de desbordamiento de búfer.
Historia
El módulo de comparación de fechas en los registros almacenaba la fecha como unsigned int, mientras buscaba el rango de fechas en int. Algunos valores límite, en lugar de generar la excepción esperada, llevaron a un filtrado incorrecto de los registros y pérdida de registros importantes.