Im trying to create two paths in order to copy file from one folder to another.
I get Segmentation fault on the second time Im trying to concat args[1].
Tried copy the cell to another char with strcpy but it wouldnt help. and a lot more stuff I didnt succeed with.
I guess something with those string commands is messing with my char array and doesnt let me do the concat twise.
the path should be of the form
"Server/File#"
or "Client#/File#"
the # is the argument from args.
I looked all over and saw some similar things but not exactly that.
please help.
all the needed "include" are in there.
void copy_file(char *args[]){
char dst_path[100],src_path[100];
memset(dst_path,0,100);
memset(src_path,0,100);
strcpy(dst_path,"Client");
strcat(dst_path,args[0]);
strcat(dst_path,"/File");
strcat(dst_path,args[1]);
strcpy(src_path,"Server/File");
strcat(src_path,args[1]);
}
This code is supposed to segfault because there is no bounds checking and you can easily overflow the destination buffers.
Also, you do not check the number of elements in args[] array. There may be fewer arguments than you expect, probably args[1] is NULL.
To fix:
Check the number of elements in args[] array.
Calculate the required buffer size for your final string, allocate a buffer of that size and then format the string. Alternatively, use snprintf to format the string in one call. snprintf does bound checks for you, so that you do not overflow your destination buffer, e.g:
char dst_path[16384];
int n = snprintf(dst_path, sizeof dst_path, "Client %s /File %s", args[0], args[1]);
if(n >= sizeof dst_path)
// dst_path is not large enough
Hopefully you can gather from this where you have mis-stepped. Tested with GCC 4.8.3. The long and short of it is that you are overflowing your buffer.
/* gcc -g -Wall -Wextra main.c */
#include <assert.h>
#include <string.h>
#define BUFSIZE 30
void copy_file(char* args[]) {
char dst_path[BUFSIZE];
char src_path[BUFSIZE];
int i;
for (i = 0; i < 30; i++) { //initializing - tried without it too.
dst_path[i] = 0;
src_path[i] = 0; }
assert(strlen(dst_path) + strlen("Client") < BUFSIZE);
strcpy(dst_path, "Client");
assert(strlen(dst_path) + strlen(args[0]) < BUFSIZE);
strcat(dst_path, args[0]);
assert(strlen(dst_path) + strlen("/File") < BUFSIZE);
strcat(dst_path, "/File");
assert(strlen(dst_path) + strlen(args[1]) < BUFSIZE);
strcat(dst_path, args[1]);
assert(strlen(src_path) + strlen("Server/File") < BUFSIZE);
strcpy(src_path, "Server/File");
assert(strlen(src_path) + strlen(args[1]) < BUFSIZE);
strcat(src_path, args[1]); }
int main(int argc, char* argv[]) {
copy_file(&argv[1]);
return 0; }
One of the main reasons you are having buffer overflows most likely is your use of strcpy. This does not have a fixed copy length, and thus if your strings are not terminated by a NULL character \0 memory that is not part of the string will be copied as well. What you should use is strncpy; then you can use strlen to get the length of the string after adding a terminating NULL character. It is good practice to always set the last character of your buffer to NULL after writing to it.
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';
int main(int argc, char** argv) {
char data[1024];
data[0] = '\0';
for(int i = 1; i < argc; i++){
strcpy(data+strlen(data), (argv[i] + 1));
}
strcpy(data+strlen(data), data+strlen(data)/2);
printf(data);
return 0;
}
As you can see this is my code so far. What I'm trying to do is: Remove first letter from every argument, concat them into data and after the loop take half of the resulting string and concat it again, then print it. Example:
Calling the program with the arguments hello, world and yes should print:
elloorldesrldes
it works until strcpy(data+strlen(data), data+strlen(data)/2);. Here I try to take half of the string (data) and concat it to the end of the same string. When I leave that part out I get the result elloorldes but when I put it in, instead of giving me the expected results I get the error RUN FAILED (exit value -1.073.741.819, total time: 4s), however I'm not sure why that's the case.
You cannot do this
strcpy(data+strlen(data), data+strlen(data)/2);
because strcpy cannot handle cases when memory overlaps.
man strcpy
char *strcpy(char *dest, const char *src);
DESCRIPTION
The strcpy() function copies the string pointed to by src, including the terminating null byte ('\0'),
to the buffer pointed to by dest. The strings may not overlap, and the destination string dest must be large enough to receive the copy.
You need to use memmove for this, which handles memory overlap:
size_t oldsize = strlen(data);
size_t size = oldsize/2;
memmove(data+oldsize, data+size, size);
data[oldsize + size] = 0;
Also don't do printf(data) with content provided by the user. Let's say the
passed arguments are hello, world%d, then data will contain %d and
printf would yield undefined behaviour, because there are arguments missing.
You should do this:
printf("%s\n", data);
or
puts(data);
I don't know the title correctly addresses my problem or not. So, I will just go with it.
Here is the problem, I have to input a char array of a file path (in Windows) containing lots of backslashes in it, eg. "C:\myfile.txt" and return an unsigned char array of C-style file paths, eg. "C:\myfile.txt".
I tried to write a function.
unsigned char* parse_file_path(char *path);
{
unsigned char p[60];
int i,j;
int len = strlen(path);
for(i=0,j=0; i<len; i++, j++)
{
char ch = path[i];
if(ch==27)
{
p[j++]='\\';
p[j]='\\';
}
else
p[j] = path[i];
}
p[j]='\0';
return p;
}
The weird thing (for me) I am encountering is, here path contains only one backslash '\'. In order to get one backslash, I have to put '\' in path. This is not possible, cause path cannot contain '\'. When I call it like this parse_file_path("t\es\t \it), it returns
t←s it. But parse_file_path("t\\es\\t \\it") returns t\es\t \it.
How can I accomplish my task? Thanks in advance.
If I can just mention another problem with your code.
You are returning a local variable (your unsigned char p). This is undefined behavior. Consider declaring a char* p that you assign memory to dynamically using malloc and then returning p as you do. E.g. something like:
char* p = malloc(60);
A common practice is to use sizeof when allocating memory with malloc but here I've passed 60 directly as the C standard guarantees that a char will be 1 byte on all platforms.
But you have to free the memory assigned with malloc.
Or alternatively, you can change the function to take a buffer as an input argument that it then writes to. That way you can pass a normal array where you would call this function.
Regarding your slashes issue, here:
p[j++]='\\';
p[j]='\\';
Position j in p will be changed to \\, then j will be incremented and at the very next line you do the same for the succeeding char position. Are you sure you want the two assignments?
By the way if you are inputting the path from the command line, the escaping will be taken care of for you. E.g. consider the following code:
#include <stdio.h>
#include <string.h> /* for strlen */
#include <stdlib.h> /* for exit */
int main()
{
char path[60];
fgets(path, 60, stdin); /* get a maximum of 60 characters from the standard input and store them in path */
path[strlen(path) - 1] = '\0'; /* replace newline character with null terminator */
FILE* handle = fopen(path, "r");
if (!handle)
{
printf("There was a problem opening the file\n");
exit(1); /* file doesn't exist, let's quite with a status code of 1 */
}
printf("Should be good!\n");
/* work with the file */
fclose(handle);
return 0; /* all cool */
}
And then you run it and input something like:
C:\cygwin\home\myaccount\main.c
It should print 'Should be good!' (provided the file does exist, you can also test with 'C:\').
At least on Windows 7 with cygwin this is what I get. No need for any escapes as this is handled for you.
I have an assignment that is supposed to be written in C (not C++), in which I need to create some structs from reading multiple text files. I have learnt c before (2 years ago) - I'm far more comfortable with Java, just can't use that for this project. I guess my issue comes from not understanding the pointer syntax very well :/.
However, my real issue:
The code I have written crashes when I try to use the strcpy function:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
char* filename;
int time;
} JOB;
JOB **jobQueue;
int nJobs;
void trimLine(char* line) {
for (int i = strlen(line); i >=0; i--) {
if (line[i] == '\n' || line[i] == '\r') line[i] = '\0';
}
}
int main(int argc, char* argv[]) {
if (argc !=2) {
printf("Error - Usage is: my_project file\n");
exit(-1);
}
FILE *fp;
fp = fopen(argv[1],"r");
if (fp==NULL) {
printf("Error - file %s could not be read.\n",argv[1]);
exit(-1);
}
jobQueue = malloc(3*sizeof(JOB*));
char filename[BUFSIZ];
nJobs = 0;
while (fgets(filename,sizeof(jobfilename),fp)!=NULL) {
trimLine(filename);
JOB* newjob;
newjob = malloc(sizeof(JOB));
//** THIS IS WHERE IT SCREWS UP
strcpy(newjob->filename,filename);
jobQueue[nJobs++] = newjob;
}
}
If I delete the line containing strcpy, the program runs fine (well, I realise this part doesn't really do anything, but still). However, when the program contains the strcpy line, it breaks when attempting to do Job #2. Any idea why?
Also: If I need to maintain an array of JOBs for use in other functions, is the way I have done it correct? JOB **jobQueue is an array of pointers to JOBs, JOB *newjob is a pointer to a JOB, would this work correctly?
newjob->filename is a wild pointer(not set to anything), you have to allocate memory before you can store things at it.
Change:
typedef struct{
char* filename;
int time;
} JOB;
to:
#include <limits.h>
typedef struct{
char filename[PATH_MAX];
int time;
} JOB;
I'd like to add a few suggestions
nJobs = 0;
Globals are initialised with 0, you don't need to do it manually.
while (fgets(filename,sizeof(jobfilename),fp)!=NULL) {
jobfilename is not declared in your code. I guess you mean filename.
for (int i = strlen(line); i >=0; i--) {
if (line[i] == '\n' || line[i] == '\r') line[i] = '\0';
}
You start with the ending \0 which you could skip.
You declare new variables everywhere you like, it's good practice (and C89 standard) that increases readability to declare variables at the start of a code block.
Additional suggestions for improvement of your code:
You do never free() the malloced pointers.
What is there are more than 3 Jobs?
Your code doesn't handle this. You
could use a linked list instead of an
array.
You do not call fclose() on your file handle.
Trasvi, don't forget that your jobQueue is malloc'ed to hold only 3 instances of the JOB struct. However, your "while loop" goes around as many times as the user inputs.
But to answer your original question, simply add this to your code before the strcpy.
newjob->filename = malloc ( strlen( filename) +1 );
//You only need to malloc the amount of characters in the filename + 1,
//which is for the null-terminated char, and you don't need to worry about
//multiplying by 'sizeof' because a char is one byte on any compiler.
You have a null pointer in newjob->filename:
int nJobsMax=3;
char* filename;
JOB* newjob;
...
jobQueue = malloc(nJobsMax*sizeof(JOB*));
filename=(char*)malloc(BUFSIZ);
while (fgets(filename,BUFSIZ,fp)!=NULL) {
trimLine(filename);
newjob = (JOB*)malloc(sizeof(JOB));
newjob->filename = filename;
filename=(char*)malloc(BUFSIZ);
jobQueue[nJobs++] = newjob;
if (nJobs > nJobsMax)
//possible buffer overflow need escape
}
free(filename);
fclose(fp);
more things:
void trimLine(char* line) {
int i = strlen(line)-1;
do{
if (line[i] == '\n' || line[i] == '\r')
line[i] = '\0';
}while(!(line[i]>=' ')||i-->=0);
}
really you don't need iterate all the string
example: fgetd output => text_text_text\r\n\0aq
' ' is character space values over this element are printer characters see ascii.
fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A terminating null byte (aq\0aq) is stored after the last character in the buffer.
source: fgets
strncpy is more recommended that strcpy because protect your code against buffer overflow.
The strncpy() function is similar, except that at most n bytes of src are copied. Warning: If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated.
If the length of src is less than n, strncpy() writes additional null bytes to dest to ensure that a total of n bytes are written.
source:strncpy
other solution to strcmp:
The strdup() function returns a pointer to a new string which is a duplicate of the string s. Memory for the new string is obtained with malloc(3), and can be freed with free(3).
The strndup() function is similar, but only copies at most n bytes. If s is longer than n, only n bytes are copied, and a terminating null byte ('\0') is added.
source:strndup
I trying to do some very basic string processing in C (e.g. given a filename, chop off the file extension, manipulate filename and then add back on the extension)- I'm rather rusty on C and am getting segmentation faults.
char* fname;
char* fname_base;
char* outdir;
char* new_fname;
.....
fname = argv[1];
outdir = argv[2];
fname_len = strlen(fname);
strncpy(fname_base, fname, (fname_len-4)); // weird characters at the end of the truncation?
strcpy(new_fname, outdir); // getting a segmentation on this I think
strcat(new_fname, "/");
strcat(new_fname, fname_base);
strcat(new_fname, "_test");
strcat(new_fname, ".jpg");
printf("string=%s",new_fname);
Any suggestions or pointers welcome.
Many thanks and apologies for such a basic question
You need to allocate memory for new_fname and fname_base. Here's is how you would do it for new_fname:
new_fname = (char*)malloc((strlen(outdir)+1)*sizeof(char));
In strlen(outdir)+1, the +1 part is for allocating memory for the NULL CHARACTER '\0' terminator.
In addition to what other's are indicating, I would be careful with
strncpy(fname_base, fname, (fname_len-4));
You are assuming you want to chop off the last 4 characters (.???). If there is no file extension or it is not 3 characters, this will not do what you want. The following should give you an idea of what might be needed (I assume that the last '.' indicates the file extension). Note that my 'C' is very rusty (warning!)
char *s;
s = (char *) strrchr (fname, '.');
if (s == 0)
{
strcpy (fname_base, fname);
}
else
{
strncpy (fname_base, fname, strlen(fname)-strlen(s));
fname_base[strlen(fname)-strlen(s)] = 0;
}
You have to malloc fname_base and new_fname, I believe.
ie:
fname_base = (char *)(malloc(sizeof(char)*(fname_len+1)));
fname_base[fname_len] = 0; //to stick in the null termination
and similarly for new_fname and outdir
You're using uninitialized pointers as targets for strcpy-like functions: fname_base and new_fname: you need to allocate memory areas to work on, or declare them as char array e.g.
char fname_base[FILENAME_MAX];
char new_fname[FILENAME_MAX];
you could combine the malloc that has been suggested, with the string manipulations in one statement
if ( asprintf(&new_fname,"%s/%s_text.jpg",outdir,fname_base) >= 0 )
// success, else failed
then at some point, free(new_fname) to release the memory.
(note this is a GNU extension which is also available in *BSD)
Cleaner code:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
const char *extra = "_test.jpg";
int main(int argc, char** argv)
{
char *fname = strdup(argv[1]); /* duplicate, we need to truncate the dot */
char *outdir = argv[1];
char *dotpos;
/* ... */
int new_size = strlen(fname)+strlen(extra);
char *new_fname = malloc(new_size);
dotpos = strchr(fname, '.');
if(dotpos)
*dotpos = '\0'; /* truncate at the dot */
new_fname = malloc(new_size);
snprintf(new_fname, new_size, "%s%s", fname, extra);
printf("%s\n", new_fname);
return 0;
}
In the following code I do not call malloc.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
/* Change this to '\\' if you are doing this on MS-windows or something like it. */
#define DIR_SYM '/'
#define EXT_SYM '.'
#define NEW_EXT "jpg"
int main(int argc, char * argv[] ) {
char * fname;
char * outdir;
if (argc < 3) {
fprintf(stderr, "I want more command line arguments\n");
return 1;
}
fname = argv[1];
outdir = argv[2];
char * fname_base_begin = strrchr(fname, DIR_SYM); /* last occurrence of DIR_SYM */
if (!fname_base_begin) {
fname_base_begin = fname; // No directory symbol means that there's nothing
// to chop off of the front.
}
char * fname_base_end = strrchr(fname_base_begin, EXT_SYM);
/* NOTE: No need to search for EXT_SYM in part of the fname that we have cut off
* the front and then have to deal with finding the last EXT_SYM before the last
* DIR_SYM */
if (!fname_base_end) {
fprintf(stderr, "I don't know what you want to do when there is no extension\n");
return 1;
}
*fname_base_end = '\0'; /* Makes this an end of string instead of EXT_SYM */
/* NOTE: In this code I actually changed the string passed in with the previous
* line. This is often not what you want to do, but in this case it should be ok.
*/
// This line should get you the results I think you were trying for in your example
printf("string=%s%c%s_test%c%s\n", outdir, DIR_SYM, fname_base_begin, EXT_SYM, NEW_EXT);
// This line should just append _test before the extension, but leave the extension
// as it was before.
printf("string=%s%c%s_test%c%s\n", outdir, DIR_SYM, fname_base_begin, EXT_SYM, fname_base_end+1);
return 0;
}
I was able to get away with not allocating memory to build the string in because I let printf actually worry about building it, and took advantage of knowing that the original fname string would not be needed in the future.
I could have allocated the space for the string by calculating how long it would need to be based on the parts and then used sprintf to form the string for me.
Also, if you don't want to alter the contents of the fname string you could also have used:
printf("string=%s%c%*s_test%c%s\n", outdir, DIR_SYM, (unsigned)fname_base_begin -(unsigned)fname_base_end, fname_base_begin, EXT_SYM, fname_base_end+1);
To make printf only use part of the string.
The basic of any C string manipulation is that you must write into (and read from unless... ...) memory you "own". Declaring something is a pointer (type *x) reserves space for the pointer, not for the pointee that of course can't be known by magic, and so you have to malloc (or similar) or to provide a local buffer with things like char buf[size].
And you should be always aware of buffer overflow.
As suggested, the usage of sprintf (with a correctly allocated destination buffer) or alike could be a good idea. Anyway if you want to keep your current strcat approach, I remember you that to concatenate strings, strcat have always to "walk" thourgh the current string from its beginning, so that, if you don't need (ops!) buffer overflow checks of any kind, appending chars "by hand" is a bit faster: basically when you finished appending a string, you know where the new end is, and in the next strcat, you can start from there.
But strcat doesn't allow to know the address of the last char appended, and using strlen would nullify the effort. So a possible solution could be
size_t l = strlen(new_fname);
new_fname[l++] = '/';
for(i = 0; fname_base[i] != 0; i++, l++) new_fname[l] = fname_base[i];
for(i = 0; testjpgstring[i] != 0; i++, l++) new_fname[l] = testjpgstring[i];
new_fname[l] = 0; // terminate the string...
and you can continue using l... (testjpgstring = "_test.jpg")
However if your program is full of string manipulations, I suggest using a library for strings (for lazyness I often use glib)