Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does the C standard guarantee buffers are not touched past their null terminator?

In the various cases that a buffer is provided to the standard library's many string functions, is it guaranteed that the buffer will not be modified beyond the null terminator? For example:

char buffer[17] = "abcdefghijklmnop"; sscanf("123", "%16s", buffer); 

Is buffer now required to equal "123\0efghijklmnop"?

Another example:

char buffer[10]; fgets(buffer, 10, fp); 

If the read line is only 3 characters long, can one be certain that the 6th character is the same as before fgets was called?

like image 741
Segmented Avatar asked Feb 25 '15 06:02

Segmented


People also ask

Do C strings need to be null-terminated?

Strings are actually one-dimensional array of characters terminated by a null character '\0'.

What is the purpose of null terminator?

The Null character in the C programming language is used to terminate the character strings. In other words, the Null character is used to represent the end of the string or end of an array or other concepts in C. The end of the character string or the NULL byte is represented by '0' or '\0' or simply NULL.

What is the value of null terminator in C?

0 and '\0' are exactly the same value, and in C, are both int types. This is fixed by the C standard and is irrespective of the character encoding on your platform.

Does read null terminate the buffer?

@Zaphod. buffer is not NULL-terminated.


1 Answers

The C99 draft standard does not explicitly state what should happen in those cases, but by considering multiple variations, you can show that it must work a certain way so that it meets the specification in all cases.

The standard says:

%s - Matches a sequence of non-white-space characters.252)

If no l length modifier is present, the corresponding argument shall be a pointer to the initial element of a character array large enough to accept the sequence and a terminating null character, which will be added automatically.

Here's a pair of examples that show it must work the way you are proposing to meet the standard.

Example A:

char buffer[4] = "abcd"; char buffer2[10];  // Note the this could be placed at what would be buffer+4 sscanf("123 4", "%s %s", buffer, buffer2); // Result is buffer =  "123\0" //           buffer2 = "4\0" 

Example B:

char buffer[17] = "abcdefghijklmnop"; char* buffer2 = &buffer[4]; sscanf("123 4", "%s %s", buffer, buffer2); // Result is buffer = "123\04\0" 

Note that the interface of sscanf doesn't provide enough information to really know that these were different. So, if Example B is to work properly, it must not mess with the bytes after the null character in Example A. This is because it must work in both cases according to this bit of spec.

So implicitly it must work as you stated due to the spec.

Similar arguments can be placed for other functions, but I think you can see the idea from this example.

NOTE: Providing size limits in the format, such as "%16s", could change the behavior. By the specification, it would be functionally acceptable for sscanf to zero out a buffer to its limits before writing the data into the buffer. In practice, most implementations opt for performance, which means they leave the remainder alone.

When the intent of the specification is to do this sort of zeroing out, it is usually explicitly specified. strncpy is an example. If the length of the string is less than the maximum buffer length specified, it will fill the rest of the space with null characters. The fact that this same "string" function could return a non-terminated string as well makes this one of the most common functions for people to roll their own version.

As far as fgets, a similar situation could arise. The only gotcha is that the specification explicitly states that if nothing is read in, the buffer remains untouched. An acceptable functional implementation could sidestep this by checking to see if there is at least one byte to read before zeroing out the buffer.

like image 138
caveman Avatar answered Sep 17 '22 23:09

caveman