C buffer overflow - c

I tried to make a function that replaces all occurrences of str1 in a text t with str2 but I keep getting a "buffer overflow" error message. Can you please tell me what is wrong with my function?
#include <stdio.h>
#include <string.h>
#include <assert.h>
//replace all *str1 in *t with *str2, put the result in *x, return *x
char * result(char *str1,char *str2,char *t)
{
char *x=NULL,*p=t,*r=t;
x=malloc(400*sizeof(char));
assert(x!=NULL);
x[0]='\0';
r=strstr(t,str1); //r is at the first occurrence of str1 in t, p is at the beginning of t
while(r!=NULL)
{
strncat(x,p,r-p); //copy r-p chars from p to x
strcat(x,str2); //copy str2 to x
p=r+strlen(str1); //p will be at the first char after the last occurrence of str1 in t
r=strstr(r+strlen(str1),str1); //r goes to the next occurrence of str1 in t
}
strcat(x,p);
return x;
}
I did not used the gets() function to read any char array.
My compiler is gcc version 4.6.3
I updated the code, it works, but the result is not the as expected.
main() function:
int main(void)
{
char *sir="ab",*sir2="xyz",*text="cabwnab4jkab",*final;
final=result(sir,sir2,text);
puts(final);
free(final);
return 0;
}
printed string:
b
I expected cxyzwnxyz4jkxyz

It looks like you've got your strncpy arguments mixed up: the second argument is the source string, not the limit on the number of chars to copy, which should be the third argument:
strncpy(x, p, r - p); // copy r - p chars from p to x
Furthermore, you want to use strcat instead of strcpy. Using strcpy, you'll just overwrite the contents of the result with the replacement string, every time. Using strcat, be sure to initialize the result with \0 before starting.
Finally, you're returning a reference to a local variable x from your function: you can't do this as the memory isn't usable after the function returns.

Your code contains quite a few weird bugs.
Firstly, x is a pointer to your destination buffer. For come reason you are doing all your copyings directly to x, i.e. everything is copied to the very beginning of the buffer, overwriting previously copied data. This doesn't make any sense at all. Whay are you doing this? You need to create a dedicated pointer to would keep the current destination position in x and write data to that position (instead of writing it to x).
I see that you edited your code and replaced copying with concatenation. Well... Even though it might fix the problem, this is still bad design. strcat/strncat functions have no place in good C code. Anyway, your code is still broken, since you are trying to use strcat functions on uninitialized buffer x. You need to initialize x as an empty string first.
Secondly, there's a more subtle problem with your search for replacement string. At the end of the cycle you continue the search from the next symbol r=strstr(r+1,str1), i.e. you increment the search position by only 1. I'm not sure this is what you want.
Consider aaaa as input text, and the request to replace aa with bc. How many replacements do you want to do in this case? How many occurrences of aa are there in aaaa? 2 or 3? If you want to get bcbc as the result (2 replacements), you have to increase r by strlen(str1), not by 1.
In fact, in the current implementation you set p=r+strlen(str1), but continue the search from r+1 position. This will lead to completely meaningless results with overlapping occurrences of search string, as in my example. Try this
char *str1="aa",*str2="xyz",*text="aaaa",*final;
final=result(str1,str2,text);
and see what happens.

Related

How do I create a global string variable, set it somewhere, and fputs it to a file?

I'm new to the C language although I hear its very similar to c++ since c++ is kind of an add on to C?
I can't seem to get a global variable (empty string) to be set in a method and then printed to a text file.
I've tried a few things, but based on what seems to make sense and worked for me in other parts of my program.. this is where I'm at:
char fileReqName[1024] = "";//trying to create the global variable
//code lines and methods
//theres a pointer that point's to a "token" thats a string.. called pptr
strncpy(fileReqName, pptr, sizeof(pptr));
//in another method:
fputs(fileReqName,file_ptr);
But it's not working.
It's supposed to be getting a "filename" from a browser request. Sometimes it's cutting the name of the file the browser goes to into a smaller string and sometimes its not displaying anything. It could be a problem with the token, but when I was displaying it before, the token was always correct.
I also just tried:
strcpy(fileReqName, pptr);
which seems to work sometimes as well haha. I think I might have to check the other code for why it's not displaying the correct string/path?
Any suggestions? Thanks
If pptr is a pointer, sizeof(pptr) is probably 4 bytes. That would copy 4 bytes into fileReqName. You need to copy the length of the string, not just sizeof(pptr) (something like strlen(pptr)).
From the man page of strncpy:
char * strncpy ( char * destination, const char * source, size_t num );
Where:
num
Maximum number of characters to be copied from source.
size_t is an unsigned integral type.
Here you are using sizeof(pptr) instead of strlen(pptr). Take a look at this simple example:
#include <stdio.h>
int main(void) {
char * pptr = "this is a string literal";
printf("pptr = '%s', sizeof(pptr) = %ld, strlen(pptr) = %d",
pptr,sizeof(pptr),strlen(pptr));
}
Output:
pptr = 'this is a string literal', sizeof(pptr) = 8, strlen(pptr) = 24
strncpy copies n characters from the second parameter to the first... If the length of the second parameter is more than n you are no copying the null terminator... If you do strlen(pptr) you get the length of the string without the null terminator too!... then you will get some unpredictable results trying to use fileReqName in other functions like fputs(). You need to try:
strncpy(fileReqName, pptr, (strlen(pptr) + 1));
but it's the same as strcpy do...
I disagree with the 3 posted answers and submit another solution. The primary use of the n parameter is to insure the destination s1 is not overrun.
// prototype
#include <string.h>
char *strncpy(char * restrict s1, const char * restrict s2, size_t n);
// Recommended usage for OP
char fileReqName[1024];
fileReqName[sizeof(fileReqName) - 1] = '\0';
...
strncpy(fileReqName, pptr, sizeof(fileReqName) - 1);
This will perform the usual strcpy() function with 2 added prevention features.
1 Even if strlen(pptr) is 1023 or more, only the first 1023 are written, preventing a buffer overwrite.
2 Should #1 occur, the \0 assignment will insure fileReqName ends with a \0.
The first solution suggested strlen(pptr). This creates all sorts of issues as the \0 byte is not copied to fileReqName, leaving it potential unterminated. It does not prevent overruns.
The problem with strncpy(fileReqName, pptr, (strlen(pptr) + 1)) is that is does not prevent buffer overrun in fileReqName. Really no different than strcpy(fileReqName, pptr).
The printf() solution describes well the issues in the OP's trial solution, but does not supply what the OP should do.

How do you explain the output from this function-like macro `slice` in C?

#include <stdio.h>
#define slice(bare_string,start_index) #bare_string+start_index
#define arcane_slice(bare_string,start_index) "ARCANE" #bare_string+start_index
int main(){
printf("slice(FIRSTA,0)==> `%s`\n",slice(FIRSTA,0));
printf("slice(SECOND,2)==> `%s`\n",slice(SECOND,2));
printf("slice(THIRDA,5)==> `%s`\n",slice(THIRDA,5));
printf("slice(FOURTH,6)==> `%s`\n",slice(FOURTH,6));
printf("slice(FIFTHA,7)==> `%s`\n",slice(FIFTHA,7));
printf("arcane_slice(FIRSTA,0)==> `%s`\n",arcane_slice(FIRST,0));
printf("arcane_slice(SECOND,2)==> `%s`\n",arcane_slice(SECOND,2));
printf("arcane_slice(THIRDA,5)==> `%s`\n",arcane_slice(THIRDA,5));
printf("arcane_slice(FOURTH,6)==> `%s`\n",arcane_slice(FOURTH,6));
printf("arcane_slice(FIFTHA,7)==> `%s`\n",arcane_slice(FIFTHA,7));
return 0;
}
OUTPUT:
slice(FIRSTA,0)==> `FIRSTA`
slice(SECOND,2)==> `COND`
slice(THIRDA,5)==> `A`
slice(FOURTH,6)==> ``
slice(FIFTHA,7)==> `slice(FIFTHA,7)==> `%s`
`
arcane_slice(FIRSTA,0)==> `ARCANEFIRST`
arcane_slice(SECOND,2)==> `CANESECOND`
arcane_slice(THIRDA,5)==> `ETHIRDA`
arcane_slice(FOURTH,6)==> `FOURTH`
arcane_slice(FIFTHA,7)==> `IFTHA`
I have the above C code that I need help on. I am getting weird behaviour from
the function-like macro slice that is supposed to 'slice' from a passed index
to the end of the string. It does not slice in the real sense but passes
a pointer from a certain point to printf which starts printing from that
address. I have managed to figure out that in arcane_slice the strings
are concatenated first then 'sliced'. I also have figured out that when start_index
is equal to 6 printf starts printing from the null byte and that is why
you get the 'empty' string. The strange part is when start_index is 7. It prints
the first argument to printf(interpolator string) concatendated with the passed bare string in both.
arcane_slice and slice(as shown in the 5th and 10th lines in the output)
Why is that so?
My wildest guess is that when the start_index exceeds the length of the strings,
the pointer points to the start of the data segment in the program's address space. But
then you could counter that with "why didn't it start printing from FIRSTA"
Not any "data segment", the stack. This is what I remember: when C calls a function it first puts data on stack, first variable arguments, then the format, all being the addresses to the memory sequentially allocated with your text. In that block of memory, the last argument (c-string) goes first, and the first goes last, thus:
Memory:
"FIFTHA\0slice(FIFTHA,7)==> `%s`\n\0"
Arguments:
<pointer-to-"FIFTHA"> <pointer-to-"slice...">
Since you overincrement the first one it skips the '\0' character and points at the format as well.
Try to experiment with this with more placeholders, like
printf("1: %s, 2: %s\n", slice(FIFTHA,7), slice(FIFTHA,6));
slice(bare_string,start_index) #bare_string+start_index
you are passing a string and bare_string stores the starting address of string which you have passed and then you returning changed pointer location which is bare_string+start_index
char str[6]="Hello";
char *ptr =str;
printf("%s\n",str);//prints hello
printf("%s\n",str+1);//prints ello
printf("%s\n",str+2);//prints llo
printf("%s\n",str+3);//prints lo
printf("%s\n",str+4);//prints o
printf("%s %c=%d \n",str+5,*(str+5),*(str+5));//prints Null
printf("%s %c=%d \n",str+6,*(str+6),*(str+6));//prints Null or may be Undefined behavior
printf("%s %c=%d \n",str+7,*(str+7),*(str+7));//prints Null or may be Undefined behaviour
the same scenario is happing in your case.
Test Code:
#include<stdio.h>
main()
{
char str[6]="Hello";
char *ptr =str;
printf("%s\n",str);//prints hello
printf("%s\n",str+1);//prints ello
printf("%s\n",str+2);//prints llo
printf("%s\n",str+3);//prints lo
printf("%s\n",str+4);//prints o
printf("%s %c=%d \n",str+5,*(str+5),*(str+5));//prints Null
printf("%s %c=%d \n",str+6,*(str+6),*(str+6));//prints Null or may be Undefined behavior
printf("%s %c=%d \n",str+7,*(str+7),*(str+7));//prints Null or may be Undefined behaviour
}
You have answered your question yourself. "FIFTHA"+7 gives you a pointer outside the string object, which is undefined behavior in C.
There's no easy way to get a more Python-like behavior for such "slices" in C. You could make it work for indexes up to a certain upper limit by adding a suffix to your string, full of zero bytes:
#define slice(bare_string,start_index) ((#bare_string "\0\0\0\0\0\0\0")+(start_index))
Also, when using macros, it's good practice (and avoids bugs too) to use parentheses excessively.
#define slice(bare_string,start_index) ((#bare_string)+(start_index))
#define arcane_slice(bare_string,start_index) (("ARCANE" #bare_string)+(start_index))

String concatenation when trying to copy arrays in C

I'm confused as to what is causing this behavior in my program. I'm just trying to copy the contents of one char* array to another and instead of copying the element, but it's concatenating the strings in a strange way. I'm doing something like this:
char* a[50];
char* b[50];
for(int n=0; n<x; n++){
a[n] = malloc(sizeof(char) * (1 + strlen(b[n])));
strcpy(a[n], b[n]);
}
Has anyone experienced this before? I can post my output if that helps.
Thanks.
A few issues:
You loop while n < x. What is x? If x >= 50, you'll run off the end of your arrays. Your loop condition needs to protect against this possibility.
Also, remember that the memory returned by malloc is uninitialized. It is good that you are allocating an extra byte for the NULL terminator. What you are missing is the code that actually sets the value of the NULL terminator. The consequence of this is that your a[] strings are most likely not NULL-terminated (the last character is whatever random garbage that was previously stored in that byte). When you try to print them out or use a string function like strlen on it, you'll read past the end of the string and into whatever happens to be sitting in the memory range that follows.
Trying using strncpy, note that you have add the null termination character at the end of a[n], This way you are sure to know what you are copying rather relying on the assumption that b[n] has null terminating character.

second memcpy() attaches previous memcpy() array to it

I have a little problem here with memcpy()
When I write this
char ipA[15], ipB[15];
size_t b = 15;
memcpy(ipA,line+15,b);
It copies b bytes from array line starting at 15th element (fine, this is what i want)
memcpy(ipB,line+31,b);
This copies b bytes from line starting at 31st element, but it also attaches to it the result for previous command i.e ipA.
Why? ipB size is 15, so it shouldnt have enough space to copy anything else. whats happening here?
result for ipA is 192.168.123.123
result for ipB becomes 205.123.123.122 192.168.123.123
Where am I wrong? I dont actually know alot about memory allocation in C.
It looks like you're not null-terminating the string in ipA. The compiler has put the two variables next to one another in memory, so string operations assume that the first null terminator is sometime after the second array (whenever the next 0 occurs in memory).
Try:
char ipA[16], ipB[16];
size_t b = 15;
memcpy(ipA,line+15,b);
ipA[15] = '\0';
memcpy(ipB,line+31,b);
ipB[15] = '\0';
printf("ipA: %s\nipB: %s\n", ipA, ipB)
This should confirm whether this is the problem. Obviously you could make the code a bit more elegant than my test code above. As an alternative to manually terminating, you could use printf("%.*s\n", b, ipA); or similar to force printf to print the correct number of characters.
Are you checking the content of the arrays by doing printf("%s", ipA) ? If so, you'll end up with the described effect since your array is interpreted as a C string which is not null terminated. Do this instead: printf("%.*s", sizeof(ipA), ipA)
Character strings in C require a terminating mark. It is the char value 0.
As your two character strings are contiguous in memory, if you don't terminate the first character string, then when reading it, you will continue until memory contains the end-of-string character.

Looping until a specific string is found

I have a simple question. I want to write a program in C that scans the lines of a specific file, and if the only phrase on the line is "Atoms", I want it to stop scanning and report which line it was on. This is what I have and is not compiling because apparently I'm comparing an integer to a pointer: (of course "string.h" is included.
char dm;
int test;
test = fscanf(inp,"%s", &dm);
while (test != EOF) {
if (dm=="Amit") {
printf("Found \"Atoms\" on line %d", j);
break;
}
j++;
}
the file was already opened with:
inp = fopen( .. )
And checked to make sure it opens correctly...
I would like to use a different approach though, and was wondering if it could work. Instead of scanning individual strings, could I scan entire lines as such:
// char tt[200];
//
// fgets(tt, 200, inp);
and do something like:
if (tt[] == "Atoms") break;
Thanks!
Amit
Without paying too much attention to your actual code here, the most important mistake your making is that the == operator will NOT compare two strings.
In C, a string is an array of characters, which is simply a pointer. So doing if("abcde" == some_string) will never be true unless they point to the same string!
You want to use a method like "strcmp(char *a, char *b)" which will return 0 if two strings are equal and something else if they're not. "strncmp(char *a, char *b, size_t n)" will compare the first "n" characters in a and b, and return 0 if they're equal, which is good for looking at the beginning of strings (to see if a string starts with a certain set of characters)
You also should NOT be passing a character as the pointer for %s in your fscanf! This will cause it to completely destroy your stack it tries to put many characters into ch, which only has space for a single character! As James says, you want to do something like char ch[BUFSIZE] where BUFSIZE is 1 larger than you ever expect a single line to be, then do "fscanf(inp, "%s", ch);"
Hope that helps!
please be aware that dm is a single char, while you need a char *
more: if (dm=="Amit") is wrong, change it in
if (strcmp(dm, "Amit") == 0)
In the line using fscanf, you are casting a string to the address of a char. Using the %s in fscanf should set the string to a pointer, not an address:
char *dm;
test = fscanf(inp,"%s", dm);
The * symbol declares an indirection, namely, the variable pointed to by dm. The fscanf line will declare dm as a reference to the string captured with the %s delimiter. It will point to the address of the first char in the string.
What kit said is correct too, the strcmp command should be used, not the == compare, as == will just compare the addresses of the strings.
Edit: What kit says below is correct. All pointers should be allocated memory before they are used, or else should be cast to a pre-allocated memory space. You can allocate memory like this:
dm = (char*)malloc(sizeof(char) * STRING_LENGTH);
where STRING_LENGTH is a maximum length of a possible string. This memory allocation only has to be done once.
The problem is you've declared 'dm' as a char, not a malloc'd char* or char[BUFSIZE]
http://www.cplusplus.com/reference/clibrary/cstdio/fscanf/
You'll also probably report incorrect line numbers, you'll need to scan the read-in buffer for '\n' occurences, and handle the case where your desired string lies across buffer boundaries.

Resources