sprintf() gone crazy - c

I need some help with this, since it baffles me in my C program
I have 2 strings(base, and path)
BASE: /home/steve/cps730
PATH: /page2.html
this is how printf reads then just before I call a sprintf to join their content together. here is the code block
int memory_alloc = strlen(filepath)+1;
memory_alloc += strlen(BASE_DIR)+1;
printf("\n\nAlloc: %d",memory_alloc);
char *input = (char*)malloc(memory_alloc+9000);
printf("\n\nBASE: %s\nPATH: %s\n\n",BASE_DIR,filepath);
sprintf(input, "%s%s",BASE_DIR,filepath); // :(
printf("\n\nPATH: %s\n\n",input);
Now, can you explain how the final printf statement returns
PATH: e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/stev
because it dont understand it at all.
** I added 9000 in the malloc statement to prevent program from crashing (since the size of the string is obviously bigger then 31 bytes.
Full Output
Alloc: 31
BASE: /home/steve/cps730
PATH: /page2.html
PATH: /home/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/steve/cps730e/stev
Sending:
HTTP/1.0 404 Not Found
Date: Sat, 12 Sep 2009 19:01:53 GMT
Connection: close
EDIT...................All the code that uses these variables
const char *BASE_DIR = "/home/steve/cps730";
char* handleHeader(char *header){
//Method given by browser (will only take GET, POST, and HEAD)
char *method;
method = (char*)malloc(strlen(header)+1);
strcpy(method,header);
method = strtok(method," ");
if(!strcmp(method,"GET")){
char *path = strtok(NULL," ");
if(!strcmp(path,"/")){
path = (char*)malloc(strlen(BASE_DIR)+1+12);
strcpy(path,"/index.html");
}
free(method);
return readPage(path);
}
else if(!strcmp(method,"POST")){
}
else if(!strcmp(method,"HEAD")){
}
else{
strcat(contents,"HTTP/1.1 501 Not Implemented\n");
strcat(contents, "Date: Sat, 12 Sep 2009 19:01:53 GMT\n");
strcat(contents, "Connection: close\n\n");
}
free(method);
}
//Return the contents of an HTML file
char* readPage(char* filepath){
int memory_alloc = strlen(filepath)+1;
memory_alloc += strlen(BASE_DIR)+1;
printf("\n\nAlloc: %d",memory_alloc);
char *input = (char*)malloc(memory_alloc+9000);
printf("\n\nBASE: %s\nPATH: %s\n\n",BASE_DIR,filepath);
sprintf(input, "%s%s\0",BASE_DIR,filepath);
printf("\n\nPATH: %s\n\n",input);
FILE *file;
file = fopen(input, "r");
char temp[255];
strcat(contents,"");
if(file){
strcat(contents, "HTTP/1.1 200 OK\n");
strcat(contents, "Date: Sat, 12 Sep 2009 19:01:53 GMT\n");
strcat(contents, "Content-Type: text/html; charset=utf-8\n");
strcat(contents, "Connection: close\n\n");
//Read the requested file line by line
while(fgets(temp, 255, file)!=NULL) {
strcat(contents, temp);
}
}
else{
strcat(contents, "HTTP/1.0 404 Not Found\n");
strcat(contents, "Date: Sat, 12 Sep 2009 19:01:53 GMT\n");
strcat(contents, "Connection: close\n\n");
}
return contents;
}

You call readPage with an invalid pointer path - it points into the memory previously allocated with the method pointer, which is freed right before the call to readPage. The next malloc can reuse this memory and then anything can happen...

Well, clearly this can't happen :-)
My guess is that your heap is horribly corrupted already.
I would look at the actual pointer values used by filepath, input and base. I wonder if you'll find that input is very close to filepath?
I would also look at how filepath, base etc were originally created, could you have a buffer over-run there?

Try this code:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
const char* BASE_DIR = "/home/steve/cps730";
const char* filepath = "/page2.html";
int memory_alloc = strlen(filepath);
memory_alloc += strlen(BASE_DIR)+1;
printf("\n\nAlloc: %d",memory_alloc);
char *input = (char*)malloc(memory_alloc);
printf("\n\nBASE: %s\nPATH: %s\n\n",BASE_DIR,filepath);
sprintf(input, "%s%s",BASE_DIR,filepath); // :(
printf("\n\nPATH: %s\n\n",input);
return 0;
}
If this doesn't have a problem, then there must be something wrong elsewhere in the code. That's how undefined behavior sometimes may manifest itself (messing up how unrelated code works).
(BTW, I didn't add +1 to both strlen calls, since the concatenated string is still going to have only one null-terminator.)

Since the BASE_DIR value is repeating itself, either BASE_DIR or filepath is probably overlapping the in input memory.
Make sure both BASE_DIR and filepath really has allocated memory.
A first try is to just make a local copy of BASE_DIR and filepath before calling sprintf.

Aaah - the thrill of the chase as the question morphs while we're trying to resolve the problem!
The current code looks like:
const char *BASE_DIR = "/home/steve/cps730";
//Handles the header sent by the browser
char* handleHeader(char *header){
//Method given by browser (will only take GET, POST, and HEAD)
char *method;
method = (char*)malloc(strlen(header)+1);
strcpy(method,header);
method = strtok(method," ");
if(!strcmp(method,"GET")){
char *path = strtok(NULL," ");
if(!strcmp(path,"/")){
path = (char*)malloc(strlen(BASE_DIR)+1+12);
strcpy(path,"/index.html");
}
free(method);
return readPage(path);
}
...
Question: if this is running in a web server, is it safe to be using the thread-unsafe function strtok()? I'm going to assume 'Yes, it is safe', though I'm not wholly convinced. Have you printed the header string? Have you printed the value of path? Did you really intend to leak the allocated path? Did you realize that the malloc() + strcpy() sequence does not copy BASE_DIR into path?
The original version of the code ended with:
printf("\n\nPATH: %s\n\n", filepath);
Hence the original suggested partial answer:
You format into input; you print from filepath?
What is the chance that filepath points to already released memory? When you allocate the memory, you could be getting anything happening to the quasi-random area that filepath used to point to. Another possibility could be that filepath is a pointer to a local variable in a function that has returned - so it points to somewhere random in the stack that is being reused by other code, such as sprintf().
I also mentioned in a comment that you might conceivably need to ensure that malloc() is declared and check the return value from it. The '(char *)' cast is not mandatory in C (it is in C++), and many prefer not to include the cast if the code is strictly C and not bilingual in C and C++.
This code works for me:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
const char *BASE_DIR = "/home/steve/cps730";
const char *filepath = "/page2.html";
int memory_alloc = strlen(filepath) + 1;
memory_alloc += strlen(BASE_DIR) + 1;
printf("\n\nAlloc: %d", memory_alloc);
char *input = (char*)malloc(memory_alloc + 9000);
printf("\n\nBASE: %s\nPATH: %s\n\n", BASE_DIR, filepath);
sprintf(input, "%s%s", BASE_DIR, filepath);
printf("\n\nPATH: %s\n\n", filepath);
printf("\n\nPATH: %s\n\n", input);
return(0);
}
It produces extraneous empty lines plus:
Alloc: 31
BASE: /home/steve/cps730
PATH: /page2.html
PATH: /page2.html
PATH: /home/steve/cps730/page2.html

The easiest way to figure out what's going on is to trace through the execution in a debugger (possibly dropping to tracing the assembly code).
A few guesses as to what might be going on:
memory corruption by another thread (seems unlikely if this is readily repeatable)
corrupt heap (also seems unlikely, as you dump the 2 component strings after the malloc() call)
as mentioned by Jonathan Leffler in a comment, you might be missing a header (perhaps stdio.h) and the compiler is generating the incorrect calling /stack clean up sequence for the printf/sprintf calls. I would expect that you would see some compile time warnings if this were the case - ones that you should take note of.
What compiler/target are you using?

To do this correctly, I'd change the code to:
/* CHANGED: allocate additional space for "index.html" */
method = (char*)malloc(strlen(header)+1+10);
strcpy(method,header);
method = strtok(method," ");
if(!strcmp(method,"GET")){
char *path = strtok(NULL," ");
if(!strcmp(path,"/")){
/* CHANGED: don't allocate new memory, use previously allocated */
strcpy(path,"/index.html");
}
/* CHANGED: call function first and free memory _after_ the call */
char *result = readPage(path);
free(method);
return result;
}

Suggestions
There is nothing obviously wrong with the program. (Update: well, there is something obvious now. For the first hour only a few lines were posted, and they had no serious bugs.) You will have to post more of it. Here are some ideas:
malloc(3) returns void * so it should not be necessary to cast it. If you are getting a warning, it most likely means you did not include <stdlib.h>. If you aren't, you should. (For example, on a 64-bit system, not prototyping malloc(3) can be quite serious. Some of the 64-bit environments don't really support K&R C. :-)
Speaking of warnings, please be sure you are turning them all on. With gcc you can turn most of them on with -Wall.
You are not checking the return value of malloc(3) for an error.
Use a memory debugger like Electric Fence. There are many choices, see my link.

Related

Segmentation fault while function call

I got a struct Chat
struct Chat
{
int m_FD;
int m_BindPort;
char m_NameLength;
char* m_Name;
char m_PeerCount;
char** m_PeerList;
} typedef Chat_t;
i'm initializing it with this function:
int chat_init(Chat_t* this, unsigned int nameLen, char* name, unsigned short int bindPort, unsigned int peerCount, char** peerList)
{
this->m_NameLength = nameLen;
this->m_Name = malloc(sizeof(char) * (nameLen+1));
strcpy(this->m_Name, name);
this->m_BindPort = bindPort;
this->m_PeerCount = peerCount;
this->m_PeerList = malloc(sizeof(char*) * peerCount);
for(int i=0; i<peerCount; i++)
{
this->m_PeerList[i] = malloc(sizeof(char) * 16); // enough for xxx.xxx.xxx.xxx\0
strcpy(this->m_PeerList[i], peerList[i]);
}
//Socket initialization for TCP connection...
//Commenting this out doesn't change anything so i'm hiding it for simplification
return 0;
}
After that i'm calling a second function
int chat_communicate(Chat_t* this)
{
printf("2\n");
fflush(stdout);
//Some stuff that doesn't matter because it isn't even called
return retVar;
}
in main like this
void main(void)
{
char* peerList[1];
char username[USERNAME_MAX_LEN];
int initRet;
int loopRet;
Chat_t chat;
peerList[0] = "192.168.2.2";
memset(username, 0, USERNAME_MAX_LEN);
printf("Please enter your user name: ");
scanf("%s", username);
username[USERNAME_MAX_LEN-1] = 0;
initRet = chat_init(&chat, strlen(username), username, 1234, 1, peerList);
printf("File Descriptor: %d\n", chat.m_FD);
printf("Binding Port: %d\n", chat.m_BindPort);
printf("Name Length: %d\n", chat.m_NameLength);
printf("Name: %s\n", chat.m_Name);
printf("Peer Count: %d\n", chat.m_PeerCount);
for(int i=0; i< chat.m_PeerCount; i++)
{
printf("Peer[%d]: %s\n", i, chat.m_PeerList[i]);
}
printf("1");
ret = chat_communicate(&chat);
//Even more Stuff that isn't even called
}
My program outputs the following
File Descriptor: 3
Binding Port: 1234
Name Length: 4
Name: User
Peer Count: 1
Peer[0]: 192.168.2.2
1
Segmentation Fault
It compiles without errors or even warnings.
You can also assume that every string is null-Terminated The stuff i replaced with comments itn't that complicated but just too much to show.
Every value inside the struct is printed with printf right before but when passing this very struct per reference the application crashes.
What i want to know is why i'm getting this Segmentation Fault. Since it appeared while calling a function i thought it is some kind of layout problem but i havn't find anything like that.
Addition:
Because some people weren't able to believe me that the code i hid behind "some stuff" comments doesn't change anything i want to state this here once again. This code just contains a tcp socket communication and only performs read-operations. I also am able to reproduce the error mentioned above without this code so please don't get stuck with it. Parts does not influence the object under observation at all.
Among other potential problems,
this->m_PeerList = malloc(sizeof(char)*peerCount);
is clearly wrong.
m_PeerList is a char **, yet you're only allocating peerCount bytes, which only works if a char * pointer is one byte on your system - not likely.
Replace it with something like
this->m_PeerList = malloc(peerCount * sizeof( *( this->m_peerList ) ) );
Note that sizeof( char ) is always one - by definition.
You're not allocating enough memory for the this->m_Name. It should be on more than this if you want it to store the null-terminated string of the name.
That, or we need more information about the peerList.
Now that you have posted an almost complete code, I was able to spot two problems next to each other:
int chat_init(Chat_t* this, unsigned int nameLen, char* name, unsigned short int bindPort, unsigned int peerCount, char** peerList)
{
this->m_NameLength = nameLen;
this->m_Name = malloc(sizeof(char) * (nameLen + 1)); // correct
//< this->m_Name = malloc(sizeof(char) * nameLen); // wrong
strcpy(this->m_Name, name); // correct
//< memcpy(this->m_Name, name, nameLen); // wrong
...
The lines starting with //< is your original code:
Here you don't allocate enough space, you need to account for the NUL terminator:
this->m_Name = malloc(sizeof(char) * nameLen);
And here you don't copy the NUL terminator:
memcpy(this->m_Name, name, nameLen);
You really need to be aware how strings work in C.
Why don't you debug it yourself. If using GCC, compile your code with options -g -O0. Then run it with gdb:
gdb ./a.out
...
(gdb) r
If it crashes do:
(gdb) bt
This will give exactly where it crashes.
Update: There may be potential problems with your code as found by other users. However, memory allocation related issues will not crash your application just on calling function chat_communicate. There could be different reasons for this behaviour ranging from stack overflow to improper compilation. Without seeing the whole code it is very difficult to tell. Best advice is to consider review comments by other users and debug it yourself.

How could I get directory name from the full path without using dirname()?

dirname() is really terrible, because it modifies the argument so that it need another ugly copy of the original string. So no dirname(), please.
Is there any function like that but which is able to use safely?
EDIT: To fix the horrible workaround when I was stupid (two years ago);
std::string_view getDirName(std::string_view filePath) {
return filePath.substr(0, filePath.rfind('/'));
}
Standard C99 or C11 do not know about directories, which is a notion provided by some operating system API (or some external library above it).
On Linux, dirname(3) man page shows examples calling strdup(3):
char *dirc, *basec, *bname, *dname;
char *path = "/etc/passwd";
dirc = strdup(path);
basec = strdup(path);
dname = dirname(dirc);
bname = basename(basec);
printf("dirname=%s, basename=%s\n", dname, bname);
(of course you should free both dirc and basec, and the code above don't check for failure of strdup)
You might also want the canonical directory of a path, using realpath(3). For example, you would code:
char* filepath = something();
char* canpath = realpath(filepath, NULL);
if (!canpath) { perror("realpath"); exit(EXIT_FAILURE); };
// so canpath is malloc-ed
char *candir = dirname(canpath); // would modify the string in canpath
/// use candir here, e.g.
printf("canonical directory for %s is %s\n", filepath, candir);
free (canpath);
BTW, glib offers g_path_get_dirname (whose result should be freed).
The freebsd man page of dirname(3) says that The dirname() function returns a pointer to internal storage space allocated on the first call that will be overwritten by subsequent calls. so check your documentation. Anyway, you can get a safe call if your implementation modifies directly the input string with:
char *aux = dirname(strdup(the_path));
...
free(aux);

VS2010, scanf, strange behaviour

I'm converting some source from VC6 to VS2010. The code is written in C++/CLI and it is an MFC application. It includes a line:
BYTE mybyte;
sscanf(source, "%x", &mybyte);
Which is fine for VC6 (for more than 15 years) but causing problems in VS2010 so I created some test code.
void test_WORD_scanf()
{
char *source = "0xaa";
char *format = "%x";
int result = 0;
try
{
WORD pre = -1;
WORD target = -1;
WORD post = -1;
printf("Test (pre scan): stack: pre=%04x, target=%04x, post=%04x, sourse='%s', format='%s'\n", pre, target, post, source, format);
result = sscanf(source, format, &target);
printf("Test (post scan): stack: pre=%04x, target=%04x, post=%04x, sourse='%s', format='%s'\n", pre, target, post, source, format);
printf("result=%x", result);
// modification suggested by Werner Henze.
printf("&pre=%x sizeof(pre)=%x, &target=%x, sizeof(target)=%x, &post=%x, sizeof(post)=%d\n", &pre, sizeof(pre), &target, sizeof(target), &post, sizeof(post));
}
catch (...)
{
printf("Exception: Bad luck!\n");
}
}
Building this (in DEBUG mode) is no problem. Running it gives strange results that I cannot explain. First, I get the output from the two printf statemens as expected. Then a get a run time waring, which is the unexpected bit for me.
Test (pre scan): stack: pre=ffff, target=ffff, post=ffff, source='0xaa', format='%x'
Test (post scan): stack: pre=ffff, target=00aa, post=ffff, source='0xaa', format='%x'
result=1
Run-Time Check Failure #2 - Stack around the variable 'target' was corrupted.
Using the debugger I found out that the run time check failure is triggered on returning from the function. Does anybody know where the run time check failure comes from? I used Google but can't find any suggestion for this.
In the actual code it is not a WORD that is used in sscanf but a BYTE (and I have a BYTE version of the test function). This caused actual stack corruptions with the "%x" format (overwriting variable pre with 0) while using "%hx" (what I expect to be the correct format) is still causing some problems in overwriting the lower byte of variable prev.
Any suggestion is welcome.
Note: I edited the example code to include the return result from sscanf()
Kind regards,
Andre Steenveld.
sscanf with %x writes an int. If you provide the address of a BYTE or a WORD then you get a buffer overflow/stack overwrite. %hx will write a short int.
The solution is to have an int variable, let sscanf write to that and then set your WORD or BYTE variable to the read value.
int x;
sscanf("%x", "0xaa", x);
BYTE b = (BYTE)x;
BTW, for your test and the message
Run-Time Check Failure #2 - Stack around the variable 'target' was corrupted.
you should also print out the addresses of the variables and you'll probably see that the compiler added some padding/security check space between the variables pre/target/post.

Regarding FOPEN in C

I am having a problem regarding FOPEN in C.
I have this code which reads a particular file from a directory
FILE *ifp ;
char directoryname[50];
char result[100];
char *rpath = "/home/kamal/samples/pipe26/divpipe0.f00001";
char *mode = "r";
ifp = fopen("director.in",mode); %director file contains path of directory
while (fscanf(ifp, "%s", directoname) != EOF)
{
strcpy(result,directoname); /* Path of diretory /home/kamal/samples/pipe26 */
strcat(result,"/"); /* front slash for path */
strcat(result,name); /* name of the file divpipe0.f00001*/
}
Till this point my code works perfectly creating a string which looks " /home/kamal/samples/pipe26/divpipe0.f00001 ".
The problem arises when I try to use the 'result' to open a file, It gives me error. Instead if I use 'rpath' it works fine even though both strings contain same information.
if (!(fp=fopen(rpath,"rb"))) /* This one works fine */
{
printf(fopen failure2!\n");
return;
}
if (!(fp=fopen(result,"rb"))) /* This does not work */
{
printf(fopen failure2!\n");
return;
}
Could some one please tell why I am getting this error ?
I think you mean char result[100];; i.e. without the asterisk. (Ditto for directoryname.)
You're currently stack-allocating an array of 100 pointers. This will not end well.
Note that rpath and mode point to read-only memory. Really you should use const char* for those two literals.
The error is the array 'char* result[100]', here you are allocating an array of 100 pointers to strings, not 100 bytes / characters, which was your intent.

Redis: SET command when data starts with a newline character

I'm using Redis in a C program I'm writing (with hiredis C binding).
Here is my code:
void insert(redisContext* c,char* buf){
static redisReply *reply;
const char* hash="asdf";
char* cmd=(char*)malloc((strlen("SET ")+strlen(hash)+strlen(" ")+CHUNKSIZE)*sizeof(char));
//hash=getHash(buf);
memcpy(cmd,"SET ",(size_t)strlen("SET "));
memcpy(cmd+strlen("SET "),hash,(size_t)strlen(hash));
memcpy(cmd+strlen("SET ")+strlen(hash)," ",(size_t)strlen(" "));
memcpy(cmd+strlen("SET ")+strlen(hash)+strlen(" "),buf,(size_t)CHUNKSIZE);
fwrite(cmd,strlen("SET ")+strlen(hash)+strlen(" ")+CHUNKSIZE,sizeof(char),stdout);
printf("\n\n\n\n\n\n");
reply=(redisReply*)redisCommand(c,cmd);
freeReplyObject(reply);
free(cmd);
}
As you can see, the cmd looks like: SET asdf xxx, where xxx is 512 bytes long (binary data).
The problem arises when the binary data string begins with '\n'. I keep getting an error (segmentation fault).
Anyone have any ideas?
Many thanks in advance,
I'm using the code you posted and didn't get any crash.
My code is:
#define CHUNKSIZE 512
char asd[CHUNKSIZE];
memset(asd, 0, 512);
asd[0] = '\n';
insert(c, asd);
Try running your app with valgrind that will probably give you a better idea of what's wrong before it crashes.
hiredis docs:
When you need to pass binary safe strings in a command, the %b specifier can be used. Together with a pointer to the string, it requires a size_t length argument of the string:
reply = redisCommand(context, "SET foo %b", value, valuelen);

Resources