Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Characters written so far in snprintf

Lately, I noticed a strange case I would like to verify:

By SUS, for %n in a format string, the respective int will be set to the-amount-of-bytes-written-to-the-output. Additionally, for snprintf(dest, 3, "abcd"), dest will point to "ab\0". Why? Because no more than n (n = 3) bytes are to be written to the output (the dest buffer).

I deduced that for the code:

int written;
char dest[3];
snprintf(dest, 3, "abcde%n", &written);

written will be set to 2 (null termination excluded from count). But from a test I made using GCC 4.8.1, written was set to 5. Was I misinterpreting the standard? Is it a bug? Is it undefined behaviour?

Edit:

@wildplasser said:

... the behavior of %n in the format string could be undefined or implementation defined ...

And

... the implementation has to simulate processing the complete format string (including the %n) ...

@par said:

written is 5 because that's how many characters would be written at the point the %n is encountered. This is correct behavior. snprintf only copies up to size characters minus the trailing null ...

And:

Another way to look at this is that the %n wouldn't have even been encountered if it only processed up to 2 characters, so it's conceivable to expect written to have an invalid value...

And:

... the whole string is processed via printf() rules, then the max-length is applied ...

Can it be verified be the standard, a standard-draft or some official source?

like image 288
Tal A. Avatar asked Aug 28 '14 18:08

Tal A.


2 Answers

written is 5 because that's how many characters would be written at the point the %n is encountered. This is correct behavior. snprintf only copies up to size characters minus the trailing null (so in your case 3-1 == 2. You have to separate the string formatting behavior from the only-write-so-many characters.

Another way to look at this is that the %n wouldn't have even been encountered if it only processed up to 2 characters, so it's conceivable to expect written to have an invalid value. That's where there would be a bug, if you were expecting something valid in written at the point %n was encountered (and there wasn't).

So remember, the whole string is processed via printf() rules, then the max-length is applied.

like image 172
par Avatar answered Oct 19 '22 21:10

par


It is not a bug: ISOC99 says

The snprintf function is equivalent to fprintf [...] output characters beyond the n-1st are discarded rather than being written to the array [...]

So it just discards trailing output but otherwise behaves the same.

like image 29
Giacomo Petrillo Avatar answered Oct 19 '22 23:10

Giacomo Petrillo