2011-01-28 14 views
5

Antecedentes: Tengo una pequeña rutina que imita a fgets(character, 2, fp), excepto que toma un carácter de una cadena en lugar de una secuencia. newBuff se asigna dinámicamente a la cadena pasada como parámetro y el carácter se declara como char character[2].Valgrind Advertencia: Debería tomarlo en serio

rutina:

character[0] = newBuff[0]; 

character[1] = '\0'; 

strcpy(newBuff, newBuff+1); 

El strcpy replica la pérdida de información ya que cada personaje se lee de la misma.

Problema: Valgrind hace me advierte sobre esta actividad, "Origen y destino superposición en strcpy (0x419b818, 0x419b819)".

¿Debo preocuparme por esta advertencia?

Respuesta

9

Probablemente, el estándar no especifique qué sucede cuando estos búferes se superponen. Entonces sí, valgrind tiene razón en quejarse sobre esto.

En términos prácticos, lo más probable es encontrar que sus strcpy copias en orden de izquierda a derecha (por ejemplo. while (*dst++ = *src++);) y que no es un problema. Pero sigue siendo incorrecto y puede tener problemas cuando se ejecuta con otras bibliotecas de C.

Uno estándares correcta manera de escribir esto sería:

memmove(newBuff, newBuff+1, strlen(newBuff)); 

Debido memmove se define para manejar la superposición. (Aunque aquí terminaría atravesando la cuerda dos veces, una para verificar la longitud y otra para copiar. También tomé un atajo, ya que strlen(newBuff) debería ser igual a strlen(newBuff+1)+1, que es lo que originalmente escribí)

+0

Incluso si el orden es de izquierda a derecha, podría haber problemas debido al desenrollado/reordenamiento y unidades de copia más grandes que el byte. Considero que este uso de 'strcpy' es altamente inseguro y es probable que se reparta entre diferentes versiones de la misma biblioteca, o incluso diferentes compilaciones con compiladores diferentes. –

+0

@R .. Estoy de acuerdo, especialmente con el punto sobre las unidades más grandes que el byte. Para que quede claro, acepto que el código es incorrecto y debe cambiarse. – asveikau

2

El comportamiento de strcpy() es oficialmente indefinido si el origen y el destino se superponen.

Desde la página del manual de establecimiento de memoria viene una sugerencia:

Los memcpy() copia n bytes del área de memoria a s2 s1 área de memoria. Si s1 y s2 se superponen, el comportamiento no está definido. Las aplicaciones en las que s1 y s2 podrían superponerse deberían usar memmove (3) en su lugar.

+1

Independientemente de cómo se implemente, el comportamiento no está definido. Esto se afirma explícitamente en el estándar. –

+0

'strcpy' da un comportamiento indefinido si los búferes se superponen. 'memcpy' hace lo mismo, pero es irrelevante. –

+0

OK, mi página de manual local para strcpy no contiene esa advertencia, pero la de memcpy sí. – mkb

4

Sí, el comportamiento de strcpy solo se define si la fuente y el destino no se superponen. En su lugar, puede considerar una combinación de strlen y memmove.

3

Sí, debes preocuparte. El estándar C establece que el comportamiento de strcpy es undefined cuando los objetos de origen y destino se superponen. Comportamiento no definido significa que puede funcionar a veces, o puede fallar, o puede parecer exitoso pero puede manifestar fallas en otras partes del programa.

+0

+1 para el enlace a los demonios nasales! –

5

Sí, y usted también debería preocuparle que su función tenga un rendimiento patológicamente malo (O(n^2) para una tarea que debería ser O(n)). Mover todo el contenido de la cadena por un personaje cada vez que lees un personaje es una gran pérdida de tiempo. En su lugar, solo debe mantener un puntero a la posición actual e incrementar ese puntero.

Situaciones en las que necesita memmove o su equivalente (copia entre búferes que se superponen) casi siempre indican un error de diseño. A menudo no es solo un defecto en la implementación, sino en la interfaz .

2

La respuesta es sí: con ciertas implementaciones de compilador/biblioteca, las más recientes, supongo, terminarás con un resultado falso. Vea How is strcpy implemented? para un ejemplo.