Invalid reading strdup with size 4 when a string literal ends with a newline \ n

I get an invalid read error when the src line ends with \n , the error disappears when I delete \n :

 #include <stdio.h> #include <stdlib.h> #include <string.h> int main (void) { char *txt = strdup ("this is a not socket terminated message\n"); printf ("%d: %s\n", strlen (txt), txt); free (txt); return 0; } 

valgrind output:

 ==18929== HEAP SUMMARY: ==18929== in use at exit: 0 bytes in 0 blocks ==18929== total heap usage: 2 allocs, 2 frees, 84 bytes allocated ==18929== ==18929== All heap blocks were freed -- no leaks are possible ==18929== ==18929== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) ==18929== ==18929== 1 errors in context 1 of 1: ==18929== Invalid read of size 4 ==18929== at 0x804847E: main (in /tmp/test) ==18929== Address 0x4204050 is 40 bytes inside a block of size 41 alloc'd ==18929== at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) ==18929== by 0x8048415: main (in /tmp/test) ==18929== ==18929== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) 

How to fix this without sacrificing a new line symbol?

+2
source share
2 answers

This is not a newline, but a printf format specifier. You found that there might be a bug in strlen() , and I can say that you should use gcc.

Your program code is excellent. The printf format specifier might be a little better, but that will not result in the valgrind error you see. Let's look at this valgrind error:

 ==18929== Invalid read of size 4 ==18929== at 0x804847E: main (in /tmp/test) ==18929== Address 0x4204050 is 40 bytes inside a block of size 41 alloc'd ==18929== at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) ==18929== by 0x8048415: main (in /tmp/test) 

"Size 4 invalid reading" is the first message we need to understand. This means that the processor has executed a command that would load 4 consecutive bytes from memory. The next line indicates that the address that was trying to read was "Address 0x4204050 is 40 bytes inside a block of size 41 alloc'd."

With this information we can understand it. Firstly, if you replace '\n' with '$' or any other character, the same error will be generated. Give it a try.

Secondly, we see that your string contains 40 characters. Adding the termination character \0 causes shared bytes to be used to represent strings up to 41.

Since we have the message "Address 0x4204050 is 40 bytes inside a block of size 41 alloc'd", we now know everything about what is going wrong.

  • strdup() allocated the correct amount of memory, 41 bytes.
  • strlen() tried to read 4 bytes, starting on the 40th, which would have spread to the non-existent 43rd byte.
  • valgrind caught the problem

This is glib () error. A project called the Tiny C Compiler (TCC) once began. Coincidentally, glib has completely changed, so normal string functions like strlen() no longer exist. They have been replaced by optimized versions that read memory using various methods, such as reading four bytes at a time. gcc has been modified at the same time to generate calls for the respective implementations, depending on the alignment of the input pointer, compiled hardware, etc. The TCC project was abandoned when this change in the GNU environment made it difficult to create a new C compiler, removing the ability to use glib for the standard library.

If you report an error supporting glib, it probably won't fix it. The reason is that in practical use this will probably never lead to an actual failure. The strlen function reads 4 bytes at a time, because it sees that the addresses are aligned by 4 bytes. You can always read 4 bytes from an address with 4-byte alignment without segfault, given that reading 1 byte from this address will succeed. Therefore, a warning from valgrind does not reveal a potential failure, just a mismatch in the assumptions on how to program. I think valgrind is technically correct, but I think there is no chance that glib developers will do anything to cancel the warning.

+8
source

It appears that the error message indicates that it is strlen , which is read behind the malloc ed buffer allocated by strdup . On a 32-bit platform, the optimal strlen implementation could read 4 bytes at a time in a 32-bit register and do some twiddling to see if there is a null byte there. If at the end of the line there are less than 4 bytes left, but 4 bytes are still read to perform a zero byte check, then I could see that this error is being printed. In this case, the strlen developer would presumably know whether it’s β€œsafe” to do this on a particular platform, in which case the valgrind error is false positive.

+3
source

Source: https://habr.com/ru/post/1275869/


All Articles