Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is an encoding error for sprintf that should return -1?

I understand snprintf will return a negative value when "an encoding error occurs"

But what is a simple example of such an "encoding error" that will produce that result?

I'm working with gcc 10.2.0 C compiler, and I've tried malformed format specifiers, unreasonably large numbers for field length, and even null format strings.

  • Malformed format specifiers just get printed literally
  • Unreasonably large numbers as length specifiers produce fatal errors
  • Null format strings also produce fatal errors

This relates to repeatedly doing something like:

length += snprintf(...

to build up a formatted string.

That might be safe if it is certain not to return a negative value.

Advancing the buffer pointer by a negative length could cause it to go out of bounds. But I'm looking for a case where that would actually happen. If there is such a case then the added complexity of this may be warranted:

length += result = snprintf(...

So far I couldn't find a scenario where it would be worth adding complexity for a check of a value that the compiler may never produce. Maybe you can give a simple example of one.

like image 704
Ted Shaneyfelt Avatar asked Dec 17 '20 03:12

Ted Shaneyfelt


People also ask

What does sprintf return?

The sprintf function returns the number of characters stored in the array s , not including the terminating null character. The behavior of this function is undefined if copying takes place between objects that overlap—for example, if s is also given as an argument to be printed under control of the ' %s ' conversion.

How can sprintf fail?

In UNIX, it can fail: EILSEQ A wide-character code that does not correspond to a valid character has been detected. EINVAL There are insufficient arguments. EILSEQ has already been mentioned.

Does sprintf use write?

sprintf() function is a file handling function in C programming language which is used to write formatted output to the string.

What is sprintf in R?

Definition of sprintf: The sprintf function returns character objects containing a formatted combination of input values. In this tutorial, I’ll show you based on six examples how to use sprintf in the R programming language.

What is the output of sprintf?

Note: The output of sprintf is a character string and not a numeric value as the input was. sprintf also enables the formatting of the number of digits before the decimal separator.

How to use the sprintf R function to control exponential notation?

The sprintf R function is also used to control exponential notation in R. The following syntax returns our number as scientific notation with a lower case e… sprintf ("%e", x) # Exponential notation # "1.234560e+02" …and the following code returns an upper case E to the RStudio console:

How do you format decimal places in sprintf?

We can now use sprintf to format the decimal places. The default number of decimal places is printed as follows (i.e. six digits after the decimal point ): We can control the number of decimal places by adding a point and a number between the percentage sign and the f. For instance, we can print ten digits after the decimal point…


2 Answers

What is an encoding error for sprintf that should return -1?

On my machine, "%ls" did not like the 0xFFFF - certainly an encoding error.

  char buf[42];
  wchar_t s[] = { 0xFFFF,49,50,51,0 };
  int i = snprintf(buf, sizeof buf, "<%ls>", s);
  printf("%d\n", i);

Output

-1

Below code returned -1, but not so much due to encoding error as for pathological format.

#include <stdio.h>

int main() {
  size_t n = 0xFFFFFFFFLLu + 1;
  char *fmt = malloc(n);
  if (fmt == NULL) {
    puts("OOM");
    return -42;
  }
  memset(fmt, 'x', n);
  fmt[n - 1] = '\0';
  char buf[42];
  int i = snprintf(buf, sizeof buf, fmt);
  printf("%d %x\n", i, (unsigned) i);
  free(fmt);
  return 7;
}

Output

-1 ffffffff

I did get a surprising -1 when passing a too big a size, even though the snprintf() only needed 6 bytes.

  char buf[42];
  int i = snprintf(buf, 4299195472, "Hello");
  printf("%d\n", i);

Output

-1

I was able to come up with a short example returning -1 on a *fprintf() to stdout due to orientation conflict.

#include <wchar.h>
#include <stdio.h>

int main() {
  int w = wprintf(L"Hello wide world\n");
  wprintf(L"%d\n", w);
  int s = printf("Hello world\n");
  wprintf(L"%d\n", s);
}

Output

Hello wide world
17
-1
like image 65
chux - Reinstate Monica Avatar answered Oct 25 '22 08:10

chux - Reinstate Monica


Normally you only expect an error from printf and family when an output error occurs. From the Linux man page:

If an output error is encountered, a negative value is returned.

So if you are outputting to a FILE and an output error of some kind (EPIPE, EIO) occurs, you'll get a negative return value. For s[n]printf, since there's no output, there would never be a negative return value.

The standard talks about the possibility of an "encoding error", but only defines what that means with respect to wide character streams, with a note that byte streams might need to convert to wide streams in some cases.

An encoding error occurs if the character sequence presented to the underlying mbrtowc function does not form a valid (generalized) multibyte character, or if the code value passed to the underlying wcrtomb does not correspond to a valid (generalized) multibyte character. The wide character input/output functions and the byte input/output functions store the value of the macro EILSEQ in errno if and only if an encoding error occurs.

That would seem to imply that you can get an encoding error if you use the %ls or %lc formats to convert a wide string or characters to bytes. Not sure if there are any other cases where it could occur.

like image 24
Chris Dodd Avatar answered Oct 25 '22 07:10

Chris Dodd