I was just wondering, cause I have this C code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int fillBuffer(int argc, char *argv[]) {
char bufferA[4] = "aaa";
char bufferB[4] = "bbb";
if(argc > 1)
strcpy(bufferB, argv[1]);
printf("bufferA: %s\n", bufferA);
printf("bufferB: %s\n", bufferB);
return 0;
}
int main(int argc, char *argv[]) {
fillBuffer(argc, argv);
return 0;
}
and I tried turning off the stack protection by using the: -fno-stack-protector
and when I try to run it by doing: ./program (escape key) 5f, the program outputs to:
bufferA: f
bufferB: fffff
I'm just not sure how bufferA becomes f also. Can anyone explain this to me?
The local buffer A and B are stored reverse order on your stack. So, on in memory you have 8 bytes starting buffer B then buffer A.
When you strcpy your 5 "f" to buffer B, the first 4 go into buffer B, and the last one with the end string '\0' to buffer A.
Then when you printf your buffers, buffer A contain 1 "f" and the string terminator. That's where it comes from.
Your strcpy call is unsafe, and will corrupt your stack if argv[1] contains more than 3 characters (plus one for the null termination character). Do not hit escape, just space and the 5f and you get the proper output:
scott> a.out 5f
bufferA: aaa
bufferB: 5f
When you hit escape, the shell can add additional characters to the string parameter, and because your strcpy is unsafe (does not check length) it will go beyond the end of your buffer and corrupt your stack. Your buffer is only 4 characters long, so your program will corrupt the stack if a parameter longer than 3 characters is entered.
To fix it, increase your buffer size from 4 to something more reasonable like 60, and use strncpy to ensure that you do not exceed the buffer if the parameter is too long:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_PARM_LEN 60
int fillBuffer(int argc, char *argv[]) {
char bufferA[MAX_PARM_LEN] = "aaa";
char bufferB[MAX_PARM_LEN] = "bbb";
if(argc > 1)
strncpy(bufferB, argv[1], MAX_PARM_LEN);
printf("bufferA: %s\n", bufferA);
printf("bufferB: %s\n", bufferB);
return 0;
}
int main(int argc, char *argv[]) {
fillBuffer(argc, argv);
return 0;
}
One last point: don't turn off stack protection.
Related
This question already has answers here:
Why do I get a segmentation fault when writing to a "char *s" initialized with a string literal, but not "char s[]"?
(19 answers)
Closed 3 years ago.
I'm learning pointers in C, using Linux. I'm trying to use the strcat function, but it doesn't work and I don't understand why.
I'm passing a username to the main as an argument because I need to concatenate and put a number 1 in the first position of this username. For example if the I got as argument username123 I need to convert this to 1username123
I got this code:
#include <stdio.h>
#include <string.h>
int main(int argc, char *arg[]){
const char *userTemp;
char *finalUser;
userTemp = argv[1]; //I got the argument passed from terminal
finalUser = "1";
strcat(finalUser, userTemp); //To concatenate userTemp to finalUser
printf("User: %s\n",finalUser);
return 0;
}
The code compiles, but I got a segmentation fault error and doesn't know why. Can you please help me going to the right direction?
It is undefined behaviour in C to attempt to modify a string literal (like "1"). Often, these are stored in non-modifiable memory to allow for certain optimisations.
Let's leave aside for the moment the fact that your entire program can be replaced with:
#include <stdio.h>
int main(int argc, char *argv[]){
printf("User: 1%s\n", (argc > 1) ? argv[1] : "");
return 0;
}
The way you ensure you have enough space is to create a buffer big enough to hold whatever you want to do. For example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]){
// Check args provded.
if (argc < 2) {
puts("User: 1");
return 0;
}
// Allocate enough memory ('1' + arg + '\0') and check it worked.
char *buff = malloc(strlen(argv[1]) + 2);
if (buff == NULL) {
fprintf(stderr, "No memory\n");
return 1;
}
// Place data into memory and print.
strcpy(buff, "1");
strcat(buff, argv[1]);
printf("User: %s\n", buff);
// Free memory and return.
free(buff);
return 0;
}
What you shouldn't do is to allocate a fixed size buffer and blindly copy in the data provided by a user. That's how the vast majority of security problems occur, by people overwriting buffers with unexpected data.
I'm trying to use the strcat function, but it doesn't work and I don't understand why.
For starters, you really shouldn't use strcat(). Use strlcat() instead. The "l" version of this and other functions take an extra parameter that let you tell the function how large the destination buffer is, so that the function can avoid writing past the end of the buffer. strcat() doesn't have that parameter, so it relies on you to make sure the buffer is large enough to contain both strings. This is a common source of security problems in C code. The "l" version also makes sure that the resulting string is null-terminated.
The code compiles, but I got a segmentation fault error and doesn't know why.
Here's the prototype for the function: char *strcat( char *dest, const char *src );
Now, you're calling that essentially like this: strcat("1", someString);. That is, you're trying to append someString to "1", which is a string constant. There's no extra room in "1" for whatever string is in someString, and because you're using a function that will happily write past the end of the destination buffer, your code is effectively writing over whatever happens to be in memory next to that string constant.
To fix the problem, you should:
Switch to strlcat().
Use malloc() or some other means to allocate a destination buffer large enough to hold both strings.
Unlike in other languages there is no real string type in C.
You want this:
#include <stdio.h>
#include <string.h>
int main(int argc, char *arg[]){
const char *userTemp;
char finalUser[100]; // finalUser can contain at most 99 characters
userTemp = argv[1]; //I got the argument passed from terminal
strcpy(finalUser, "1"); // copy "1" into the finalUser buffer
strcat(finalUser, userTemp); //To concatenate userTemp to finalUser
printf("User: %s\n",finalUser);
return 0;
}
or even simpler:
#include <stdio.h>
#include <string.h>
int main(int argc, char *arg[]){
char finalUser[100]; // finalUser can contain at most 99 characters
strcpy(finalUser, "1"); // copy "1" into the finalUser buffer
strcat(finalUser, argv[1]); //To concatenate argv[1] to finalUser
printf("User: %s\n",finalUser);
return 0;
}
Disclaimer: for the sake of brevity this code contains a fixed size buffer and no check for buffer overflow is done here.
The chapter dealing with strings in your C text book should cover this.
BTW you also should check if the program is invoked with an argument:
int main(int argc, char *arg[]){
if (argc != 2)
{
printf("you need to provide a command line argument\n");
return 1;
}
...
You're missing some fundamentals about C.
finalUser = "1";
This is created in "read-only" memory. You cannot mutate this. The first argument of strcat requires memory allocated for mutation, e.g.
char finalUser[32];
finalUser[0] = '1';
I have the following code where I try to access the command line arguments but I am having trouble doing so.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char *argv) {
int fd = open("drawing.ppm", O_RDWR | O_CREAT | O_APPEND, 0700);
char colour[] = "0 0 0 ";
if(argv[1] == "red") {
char colour[] = "255 0 0 ";
}
printf("%s\n", &argv[1]);
int date = write(fd, colour, sizeof(colour));
close(fd);
}
When I run the code, the terminal displays 1▒ which is some weird unexpected symbol. Can someone please tell me why this isn't working?
A few things.
First your signature for main() is wrong it should be
int main(int argc, char *argv[])
Notice how argv is an array (pointer) of strings not chars.
Second you don't check to see if there were any args passed.
Something like
if (argc > 2)
Third your printout is the address of argv[1] instead of argv[1]
Try (inside/after the argc check)
printf("%s\n", argv[1]);
you declare 2 times colour variable take care of that the second one is local to the if-scope.
The type of argv[1] is char* and you try to use with the operator == which is useful for string type variables. Here you are comparing two pointers, in fact, two memory addresses.
You may try to use strcmp to compare the contents of objects pointed by the pointers.
I need to get a clue in how know when to stop storing a string from a file after i hit a space between the words. After i open a file and read it, for example: the first line that is there is:427 671 +. I need to store "427" in an array of int, same with "671" and "+"in a variable.
So far i have figure out how to read the whole line and print it but the problem i have is to read char by char and store it before i hit a space.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include <Laboratorio.h>
#include <string.h>
int main(int argc, char **argv) {
FILE *datos;
FILE *resultados;
char bin[64]="",hex[16]="";
int oct[21];
ep = fopen ( argv[1], "r" );
if (ep==NULL) {
printf("Archivo vacio.");
return 0;
}else{
while (fgets(bin,64,ep)!=NULL){
printf("%s",bin);
}
fclose(ep);
}
}
The simplest way to do so would be to have a char variable and store each char into it one by one like so:
while ((ch = getc(stream)) != EOF)
{
// do stuff with char
}
after you get the char you can decide what to do with it, compare it to 32 (space) to know when to stop.
if the char is a numeral you can place it in a buffer until you reach a space, then all you need to do is use the function atoi which receives a pointer to a string, and returns an int representation of the string.
for example: turns the string "432" to an int 432.
I'm trying to read in two filenames and save them as a global variable in C.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char infilename;
char outfilename;
int main(int argc, const char* argv[]){
strcopy(infilename, argv[1]);
return 0;
}
However this does not work. Can someone help me with a really simple problem like this?
You are trying to copy a string (const char *) to a character (char). You need to either declare infilename as a string:
char *infilename;
infilename = malloc(...
or make a static array:
char infilename[NUM_OF_CHARS];
Read up on c strings here.
Also choose your language, if you are really using c++ you need to start using std::string
A better way to do it.
char infilename[50];
char outfilename[50];
int main(int argc, const char* argv[]){
if(argc == 3)
{
strcpy (infilename,argv[1]);
strcpy (outfilename,argv[2]);
}
else
{
//do something else
}
return 0;
}
You need array of char and not only char. A string in C is an array of char. And you must always verify (if(argc == 3) if the user entered the quantity of argument you want, because if it's not the case your applicatin can crash.
That's not going to work.
These:
char infilename;
char outfilename;
declare a variables that store a single char, not an entire string.
You either need to make those char arrays:
char infilename[MAX_PATH];
char outfilename[MAX_PATH];
or pointers that you plan to initialize with malloced memory. You have to pick which one you mean.
P.s. there's no function called strcopy, it's strcpy.
The main problem is that you made your global variables single characters not an array of characters which is needed for a string.
Assuming you don't want to change the contents of the string then the easiest thing is to simply set a global to point to the same string rather than copying it. Because the program will end when main returns there is no worry about the parameters argv going out of scope.
Note you would have to worry about this if you create a new thread and terminate the thread running main without terminating the program.
#include <stdio.h>
#include <stdlib.h>
static char* gInFilenamePtr;
static char* gOutFilenamePtr;
int main(int argc, const char* argv[])
{
if( argc > 2 )
{
gInFilenamePtr = argv[1];
gOutFilenamePtr = argv[2];
}
return 0;
}
I am trying to get the command line arguments to use it in exec
but my code doesn't work correctly because it returns garbage as output.
(I'm ubuntu user)
Here's what I have done by far:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int argc,char *argv[]){
char command[1024];
int i;
fflush(stdin); // i try to empty the buffer
for ( i = 1; i < argc; ++i) {
strcat(command, argv[i]);
strcat(command," ") ; //here i try to copy the arguments
}
printf("%s\n",command);
return 0;
}
The output in the terminal after compilation is :
ubuntu-gnome#ubuntu-gnome:~/Desktop$ ./1 theo psallidas
����*theo psallidas
You need a NUL terminated string to use srtcat:
The strcat() function shall append a copy of the string pointed to by
s2 (including the terminating null byte) to the end of the string
pointed to by s1. The initial byte of s2 overwrites the null byte at
the end of s1. If copying takes place between objects that overlap,
the behavior is undefined.
char command[1024];
should be
char command[1024] = "";
And fflush(stdin); is undefined behavior (but you don't need this line at all).