tags:

views:

236

answers:

6

Hey all,

If I have the following code:

main(int argc, char *argv[]){
 char serveradd[20];
 strcpy(serveradd, argv[1]);
 int port = atoi(argv[2]);
 printf("%s %d \n", serveradd, port);

The first two arguments to the command line are printed. However, if I do this:

 char serveradd[20];
 strcpy(serveradd, argv[1]);
 int port = atoi(argv[2]);
 char versionnum[1]; 
 strcpy(versionnum, argv[3]);
 printf("%s %d %s \n", serveradd, port, versionnum);`

The first argument (serveradd) does not print out to the screen and is not being stored... Why is this happening and how can I fix it? Thanks!

+10  A: 
char versionnum[1];  
strcpy(versionnum, argv[3]); 

Wild guess but you are smashing the stack with these lines. Make versionnum bigger; as it stands, it can only safely hold the empty string.

MSN
Almost certainly smashing the stack, since strcpy will add a null after the copy, even if there's only one character.versionnum at the very least needs to be 2 chars long.
John Weldon
More trickily, it *might* work, err, **not fail** on some platforms. I once had a program to maintain (not written by me!) which read a length one string into a `char` variable; the code worked on a SPARC but failed on x86 (and crashed gdb too) because the terminating NUL was smashing the return address of the function and leaving it pointing half-way through another instruction. It didn't fail on SPARC because, with the opposite endianness, the alignment of the variable left 3 spare bytes, which could hold the NUL. Truly an evil bug.
Donal Fellows
+1  A: 

Using strcpy without testing the length using strlen of the string you are copying to be sure it will fit in the destination buffer is a very bad idea. You should use strncpy, which is length-checked and will not overrun the destination buffer.

You cannot store a string in a char array of length one, because the null terminator takes one character, so all you could store would be the null character. It is all but guaranteed that you are overrunning your buffer.

James McNellis
+3  A: 

You're probably nuking memory with

char versionnum[1]; 
strcpy(versionnum, argv[3]);

Given that any non-empty null-terminated string is going to be > 1 character long.

Never use straight strcpy(); use strncpy() instead (note the - 1 to preserve space for the null terminator):

char serveradd[20] = { 0 };
strncpy(serveradd, argv[1], sizeof(serveradd) - 1);
int port = atoi(argv[2]);
char versionnum[2] = { 0 }; 
strcpy(versionnum, argv[3], sizeof(versionnum) - 1);
printf("%s %d %s \n", serveradd, port, versionnum);
pkh
Note that you need to explicitly set the last character of the array to `\0` when using `strncpy`.
James McNellis
Feh, I forgot to initialize my arrays in the first version. In the current version on the answer, you won't need to explicitly null-terminate, since initializing the first element of the array (to anything at all) will initialize the non-initialized items to 0 for you.
pkh
A: 

It works for me in the way you described. My guess is that you're over the character limit in one of the strings. I'd use strncpy instead of strcpy.

Daniel
+1  A: 

I think the answers above resolved your problem, but in the future try being a little more generous with memory allocation when you are debugging. If you think you need 5 elements, create a define make it 10, and later change it to 5 or 6 if you want to have room for the null terminator. Also if you ever find yourself allocating an array of length one, stop and ask why. If you have one element, just use a plain variable.

Whenever I have problems with argc and argv the first think I do is print them out to see if I have what I think should.

Jim Tshr
A: 

Try strdup()

An alternative is to use strdup() which allocates memory on the heap so that your can't overflow the buffers. In your case, since the variables will exist for the life of the program anyway, this is not so bad, or you can use free() to deallocate the memory right after the last time you use the variables. Make sure you don't use the variables after that! Below is some sample code.


#include <stdio.h>
#include <stdlib.h>
#include <strings.h>

int main(int argc, char *argv[])
{
      char *serveradd  = NULL;
      int   port;
      char *versionnum = NULL;

      if (argc != 4)
      {
            printf("Usage: %s SERVERADD PORT VERSIONNUM\n", argv[0]);
            exit(126);
      }

      serveradd  = strdup(argv[1]);
      port       = atoi(argv[2]);
      versionnum = strdup(argv[3]);

      if ((serveradd == NULL) || (versionnum == NULL))
      {
            perror("Could not allocate command line arguments");
            exit(125);
      }

      printf("%s %d %s \n", serveradd, port, versionnum);

      free(serveradd);
      free(versionnum);
      serveradd  = NULL;
      versionnum = NULL;
      exit(0);
}
Tom DeGisi