Eagle
Eagle

Reputation: 2056

printf(string) vs. printf("%s", string)

I'm writing a proxy server, and I ran into a curious bug that I hoped someone would be able to explain.

I'm receiving the first line of a GET request from client. For example, the client would send the request:

GET http://en.wikipedia.org/wiki/Special:Random HTTP/1.0
Host: en.wikipedia.org
...

And I would forward this request to the server.

However, with certain web addresses, I would encounter a problem:

GET http://map.media6degrees.com/orbserv/curl=http%3A%2F%2Fwww.masteringemacs.org%2Farticles[trunc] HTTP/1.0

I read this line into char buffer[MAXLINE_LENGTH], which is long enough to hold the string.

When I print the received get request with

printf(buffer);

The printed string is:

GET http://map.media6degrees.com/orbserv/hbpix?pixId=2869&curl=http0X0.0000000000015P-10220.0000000.000000www.masteringemacs.org0.000000articles0.00000020100.000000110.000000010.000000running-shells-in-emacs-overview204741995430849962482228271154502456423284733956118041206315879167624419264810411254941012469231829496710329852458403099883653794777355548418601638730167027236864.000000 HTTP/1.0

It appears the %3A, %2F, etc. have been string formatted.

When I run printf("%s", buffer);, I get the correct and expected output

EDIT: I understand why this is occurring; I'm interested in why this is occurring this way. Are the values that printf is "string formatting" coming from some arbitrary area on the stack? Are the %3A et al valid format strings?

Upvotes: 5

Views: 9869

Answers (4)

Ramy Al Zuhouri
Ramy Al Zuhouri

Reputation: 22006

If you use printf(string), then the printed string may be NULL.
That's the only problem that I see with this.The printf function reads all va_list arguments according to the format provided, so it may crash if you pass a NULL pointer. With LLVM 4.1 I get this warning:

Format string is not a literal string (potentially insecure)

This is my personal opinion: if you are sure that the string isn't NULL (maybe verify it through an assertion, and then remove that assertion in the release), then you could go with printf(string).If you are not totally sure that the string may be NULL or invalid, then use a literal string.

Upvotes: 1

paulsm4
paulsm4

Reputation: 121881

1) If you look at the function prototype, you'll see that printf() expects a format string, and zero or more arguments. So, strictly speaking, "printf(string)" is not correct:

SYNOPSIS
       #include <stdio.h>

       int printf(const char *format, ...);
       int fprintf(FILE *stream, const char *format, ...);
       int sprintf(char *str, const char *format, ...);
       int snprintf(char *str, size_t size, const  char  *format,
       ...);

2) The first argument will be interpreted as a format string, and any "%XXX" entries it found will be interpreted as place holders. Which it sounds like is exactly what's happening :)

3) The solution, of course, is printf ("%s", string)

4) Or using puts(string) instead :)

Upvotes: 8

In the format argument to the printf and scanf family of functions % is treated as an escape character. You raw input has some of them and printf is trying to interpret them.

Upvotes: 1

Pavel Radzivilovsky
Pavel Radzivilovsky

Reputation: 19104

Never use an input string as a format parameter to printf.

To work correctly, it must have no "%..." items. These are special commands to the printf() function to access the parameters list.

Upvotes: 5

Related Questions