Error: la cadena de formato no es una cadena literal

3 minutos de lectura

avatar de usuario
ShanZhengYang

He escrito un programa simple en C, que asigna memoria para un vector de cadena y luego lo imprime.

#include <stdio.h>
#include <string.h>

int main() {
    char str_a[20];

    strcpy(str_a, "Hello, world!\n");
    printf(str_a);
}

Usando el compilador gccesto da un error de compilación:

char_array2.c:8:12: warning: format string is not a string literal
      (potentially insecure) [-Wformat-security]
    printf(str_a);

1 warning generated.

No entiendo por qué recibo una advertencia. ¿Alguien puede explicar me lo?

  • El mensaje le dice exactamente lo que está pasando. ¿Qué no entiendes en él?

    – Étienne de Martel

    02/09/2015 a las 20:55


  • “1 advertencia generada”. != “un error de compilación”.

    – chux – Reincorporar a Monica

    02/09/2015 a las 21:12

  • Una advertencia no es lo mismo que un error.

    – Barmar

    02/09/2015 a las 21:17

avatar de usuario
ouah

Usar:

printf("%s", str_a);

para deshacerse de la advertencia cuando -Wformat-security está habilitado.

El diagnóstico es informativo para evitar vulnerabilidad de cadena de formato. Por ejemplo:

strcpy(str_a, "%x%x%x%x");
printf(str_a);

sería equivalente a:

printf("%x%x%x%x");

al que le faltan los argumentos necesarios y puede ser utilizado por un atacante para volcar la pila (suponiendo que str_a está bajo el control del usuario, que no es el caso en su programa, pero gcc no es lo suficientemente inteligente como para darse cuenta).

avatar de usuario
chux – Reincorporar a Monica

Considere 3 printf() declaraciones. ¿Qué puede detectar el compilador si existe una discrepancia de formato?

void foo(const char *str_a,int x) {
  printf("Hello %d\n", x);  // Compiler sees this is good
  printf("Hello %d\n");     // Compiler sees this is bad --> warning/error
  printf(str_a, x);         // Compiler cannot tell - thus the warning
}

Esto no es un error sino una advertencia. Cuando usas printf para imprimir una cadena, quieres algo como printf("%s", str_a). Siempre que tenga una cadena entre comillas (” “) es una cadena literal, esto es lo que significa la advertencia cuando dice que no es una cadena literal. No estoy completamente seguro de por qué necesita tener un literal de cadena, pero generalmente es mejor seguir el compilador; alguien más probablemente pueda aclarar la necesidad de un literal de cadena.

avatar de usuario
arbusto

Si tuvieras que hacer algo como esto:

#include <stdio.h>
#include <string.h>

int main() {
    char str_a[20];

    fgets(str_a, 20, stdin);
    printf(str_a);
}

Y el usuario ingresó A %s bad %n stringel usuario podrá bloquear su programa y tal vez iniciar un shell.

Con esta entrada, el usuario puede hacer esto de manera efectiva:

printf("A %s bad %n string");

los %s especificador hace que la función lea desde una dirección inválida, mientras que el %n especificador hace que escribe a una dirección inválida.

Las otras respuestas son mejores. Pero si todo lo demás falla, puede decirle al compilador que ignore el error.

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat"
printf(str_a);
#pragma clang diagnostic pop

perno de dios

avatar de usuario
Jens

La advertencia se emite porque los buenos compiladores comparan los especificadores de formato como %d en la cadena de formato contra los tipos (aquí un int) siguiendo el formato. Obviamente, esto solo funciona para cadenas literales que el compilador puede analizar en busca de especificadores. Un puntero a char en una variable derrota esta verificación de cordura de tipos.

Tenga en cuenta que los especificadores de formato (o tipos de argumentos) que no coinciden provocan comportamiento indefinido y, a menudo, conducen a la conversión de valores basura o fallas. Piensa en lo que sucede cuando un %s está asociado con un valor integral.

¿Ha sido útil esta solución?