Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c

printf

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?

like image 818
Eagle Avatar asked Dec 12 '22 20:12

Eagle


2 Answers

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 :)

like image 173
paulsm4 Avatar answered Dec 23 '22 12:12

paulsm4


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.

like image 21
Pavel Radzivilovsky Avatar answered Dec 23 '22 11:12

Pavel Radzivilovsky