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 gcc
esto 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?
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).
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.
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 string
el 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
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.
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