I am trying to fill the gaps in my self-education in computer science and taking the CS50 course on Edx. I am completely new to C. In one of the problems sets, I have to compare strings encrypted with crypt function.
In the following example, I cannot understand why strcmp returns 0 (i.e. 'claims' that the strings are equal:
#include <crypt.h>
#include <stdio.h>
#include <string.h>
#define _XOPEN_SOURCE
int main(void)
{
char string1[4] = "foo\0";
char string2[4] = "bar\0";
printf("crypt1: %s\n",crypt(string1, "50\0"));
printf("crypt2: %s\n",crypt(string2, "50\0"));
if (strcmp(crypt(string1, "50\0"),crypt(string2, "50\0")) == 0)
{
printf("crypt1: %s\n",crypt(string1, "50\0"));
printf("crypt2: %s\n",crypt(string2, "50\0"));
return 0;
}
}
When I run the program, the output value is:
crypt1: 50GbL/FUeE/J6
crypt2: 50hmnpE.bRNiU
crypt1: 50GbL/FUeE/J6
crypt2: 50hmnpE.bRNiU
How is it possible, that the code inside if condition is even executed?
Apparently, crypt() uses the same buffer for the encrypted string on each call:
char string1[] = "foo";
char string2[] = "bar";
char *crypt1 = crypt(string1, "50");
printf("crypt1: %s\n", crypt1); // crypt1: 50GbL/FUeE/J6
char *crypt2 = crypt(string2, "50");
printf("crypt1: %s\n", crypt1); // crypt1: 50hmnpE.bRNiU
printf("crypt2: %s\n", crypt2); // crypt2: 50hmnpE.bRNiU
In order to keep (and compare) both results, you have to strdup()
them or copy them to a separate array.
As mentioned in Martin's comment, crypt returns a pointer to a static buffer that is overwritten on each call. So strcmp is actually being passed the same buffer - the first value of crypt already having been overwritten by the second - once the two arguments have been evaluated.
Related to the following: C crypt function, malloc and valgrind
[And, for what its worth, in C, any function that returns a string (char *) has to get the memory for that string from somewhere. You either need to pass the buffer in as an argument, or it needs to find it itself. And because C doesn't do garbage collection and requires manual memory management (e.g. malloc/free), a function that does not take a result buffer as an argument should throw up a red flag - is the result a static buffer (that gets overwritten like this)? does it need to be free'd when I'm done with it? Otherwise, you risk memory leaks or bugs like the one you're experiencing.)
Related
I am trying to write code to implement strchr function in c. But, I'm not able to return the string.
I have seen discussions on how to return string but I'm not getting desired output
const char* stchr(const char *,char);
int main()
{
char *string[50],*p;
char ch;
printf("Enter a sentence\n");
gets(string);
printf("Enter the character from which sentence should be printed\n");
scanf("%c",&ch);
p=stchr(string,ch);
printf("\nThe sentence from %c is %s",ch,p);
}
const char* stchr(const char *string,char ch)
{
int i=0,count=0;
while(string[i]!='\0'&&count==0)
{
if(string[i++]==ch)
count++;
}
if(count!=0)
{
char *temp[50];
int size=(strlen(string)-i+1);
strncpy(temp,string+i-1,size);
temp[strlen(temp)+1]='\0';
printf("%s",temp);
return (char*)temp;
}
else
return 0;
}
I should get the output similar to strchr function but output is as follows
Enter a sentence
i love cooking
Enter the character from which sentence should be printed
l
The sentence from l is (null)
There are basically only two real errors in your code, plus one line that, IMHO, should certainly be changed. Here are the errors, with the solutions:
(1) As noted in the comments, the line:
char *string[50],*p;
is declaring string as an array of 50 character pointers, whereas you just want an array of 50 characters. Use this, instead:
char string[50], *p;
(2) There are two problems with the line:
char *temp[50];
First, as noted in (1), your are declaring an array of character pointers, not an array of characters. Second, as this is a locally-defined ('automatic') variable, it will be deleted when the function exits, so your p variable in main will point to some memory that has been deleted. To fix this, you can declare the (local) variable as static, which means it will remain fixed in memory (but see the added footnote on the use of static variables):
static char temp[50];
Lastly, again as mentioned in the comments, you should not be using the gets function, as this is now obsolete (although some compilers still support it). Instead, you should use the fgets function, and use stdin as the 'source file':
fgets(string, 49, stdin);/// gets() has been removed! Here, 2nd argument is max length.
Another minor issue is your use of the strlen and strncpy functions. The former actually returns a value of type size_t (always an unsigned integral type) not int (always signed); the latter uses such a size_t type as its final argument. So, you should have this line, instead of what you currently have:
size_t size = (strlen(string) - i + 1);
Feel free to ask for further clarification and/or explanation.
EDIT: Potential Problem when using the static Solution
As noted in the comments by Basya, the use of static data can cause issues that can be hard to track down when developing programs that have multiple threads: if two different threads try to access the data at the same time, you will get (at best) a "data race" and, more likely, difficult-to-trace unexpected behaviour. A better way, in such circumstances, is to dynamically allocate memory for the variable from the "heap," using the standard malloc function (defined in <stdlib.h> - be sure to #include this header):
char* temp = malloc(50);
If you use this approach, be sure to release the memory when you're done with it, using the free() function. In your example, this would be at the end of main:
free(p);
I expected to get errors in following code, but I did not. I did not use & sign. Also I am editing array of chars.
#include <stdio.h>
int main()
{
char name[10] ="yasser";
printf("%s\n",name);
// there is no error ,
// trying to edit array of chars,
// also did not use & sign.
scanf("%s",name);
// did not use strcpy function also.
printf("%s\n",name);
return 0;
}
I expected to get errors in following code, but I did not.I did not use & sign.
scanf("%s",name);
That's totally ok as name is already the address of the character array.
It sounds like you have several questions:
calling scanf("%s", name) should have given an error, since %s expects a pointer and name is an array? But as others have explained, when you use an array in an expression like this, what you always get (automatically) is a pointer to the array's first element, just as if you had written scanf("%s", &name[0]).
Having scanf write into name should have given an error, since name was initialized with a string constant? Well, that's how it was initialized, but name really is an array, so you're free to write to it (as long as you don't write more than 10 characters into it, of course). See more on this below.
Characters got copied around, even though you didn't call strcpy? No real surprise, there. Again, scanf just wrote into your array.
Let's take a slightly closer look at what you did write, and what you didn't write.
When you declare and initialize an array of char, it's completely different than when you declare and initialize a pointer to char. When you wrote
char name[10] = "yasser";
what the compiler did for you was sort of as if you had written
char name[10];
strcpy(name, "yasser");
That is, the compiler arranges to initialize the contents of the array with the characters from the string constant, but what you get is an ordinary, writable array (not an unwritable, constant string constant).
If, on the other hand, you had written
char *namep = "yasser";
scanf("%s", namep);
you would have gotten the problems you expected. In this case, namep is a pointer, not an array. It's initialized to point to the string constant "yasser", which is not writable. When scanf tried to write to this memory, you probably would have gotten an error.
When you pass arrays to functions in C, they decay to pointers to the first item.
Therefore for:
char name[] ="yasser";
scanf("%s", name) is the same as scanf("%s", &name[0]) and either of those invocations should send shivers down your spine, because unless you control what's on your stdin (which you usually don't), you're reading a potentially very long string into a limited buffer, which is a segmentation fault waiting to happen (or worse, undefined behavior).
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv, char **envp) {
char *myName = (char *) calloc(10, sizeof(char));
*(myName)='K'; *(myName+1)='h'; *(myName+2)='a'; *(myName+3)='l'; *(myName+4)='i'; *(myName+5)='d';
printf("%s\n",myName);
scanf("%s",myName);
printf("%s\n",myName);
return (EXIT_SUCCESS);
}
#include <stdio.h>
#include <string.h>
int main()//fonction principale
{
char name[10] ="yasser";
int longeur=0;
printf("%s\n",name);
scanf("%s",name);
longeur = strlen(name);
for (int i=0;i<longeur;i++) {
printf("%c",*(name+i));
}
return 0;}
I am trying to convert an arbitrary buffer to a string of its binary representation. I was looking at some code from here: http://snippets.dzone.com/posts/show/2076 in order to get started. I realize that this code can not convert an arbitrary buffer, but only the specific case of an int; however, I figured that I could adapt it to any case once it was working.
The problem is that it returns some strange symbols (like this: �왿") instead of the binary. Does anyone either know what is wrong with this code specifically or explain how to convert an arbitrary buffer?
Please keep in mind that I am new to c++.
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
char *getBufferAsBinaryString(void *in)
{
int pos=0;
char result;
char bitstring[256];
memset(bitstring, 0, 256);
unsigned int *input= (unsigned int *)in;
for(int i=31;i>=0;i--)
{
if (((*input >> i) & 1)) result = '1';
else result = '0';
bitstring[pos] = result;
if ((i>0) && ((i)%4)==0)
{
pos++;
bitstring[pos] = ' ';
}
pos++;
}
return bitstring;
}
int main(int argc, char* argv[])
{
int i=53003;
char buffer[1024];
char *s=getBufferAsBinaryString(&i);
strcpy(buffer, s);
printf("%s\n", buffer);
}
The array bitstring has what is known as automatic duration, which means that it springs into existence when the function is called and disappears when the function returns.
Therefore, the pointer that this version of getBufferAsBinaryString returns is to an array which no longer exists by the time the caller receives the pointer. (Remember that the statement return bitstring; returns a pointer to the first character in bitstring; by the "equivalence of arrays and pointers," the mention of the array bitstring in this context is equivalent to &bitstring[0].)
When the caller tries to use the pointer, the string created by getBufferAsBinaryString might still be there, or the memory might have been re-used by some other function. Therefore, this version of getBufferAsBinaryString is not adequate and not acceptable. Functions must never return pointers to local, automatic-duration arrays.
Since the problem with returning a pointer to a local array is that the array has automatic duration by default, the simplest fix to the above non-functional version of getBufferAsBinaryString is to declare the array static, instead:
char *getBufferAsBinaryString(void *in)
{
int pos=0;
char result;
static char bitstring[256];
memset(bitstring, 0, 256);
unsigned int *input= (unsigned int *)in;
for(int i=31;i>=0;i--)
{
if (((*input >> i) & 1)) result = '1';
else result = '0';
bitstring[pos] = result;
if ((i>0) && ((i)%4)==0)
{
pos++;
bitstring[pos] = ' ';
}
pos++;
}
return bitstring;
}
Now, the bitstring array does not disappear when getBufferAsBinaryString returns, so the pointer is still valid by the time the caller uses it.
Returning a pointer to a static array is a practical and popular solution to the problem of "returning" an array, but it has one drawback. Each time you call the function, it re-uses the same array and returns the same pointer. Therefore, when you call the function a second time, whatever information it "returned" to you last time will be overwritten. (More precisely, the information, that the function returned a pointer to, will be overwritten.)
Although the static return array technique will work, the caller has to be a little bit careful, and must never expect the return pointer from one call to the function to be usable after a later call to the function
But you still have a different problem with passing in void * which I did not cover, in addition not passing in the size of your buffer. Since you shouldn't assume that your array ends in the \0, you should also pass in the size of your buffer.
Ignoring the other issues with memory and safety, you are not returning a valid null terminated string. Nor do you pass in the size of the input buffer, so you really just print out the 32-bit bit representation of the first 32-bits of the input buffer.
So, in addition to passing in a char buffer to write to or simply returning a std::string, you should also pass in the size of the input buffer and loop over that as well.
You can't return locally-allocated arrays from a function. As soon as the function finishes, the array ceases to exist, so the pointer you've returned no longer points to a valid object.
Instead of using a char array to represent your bitstring, you should consider using std::string, which has sensible value semantics (i.e., you can copy it, return it from a function, etc, without having to worry about it except from an efficiency standpoint).
I have a variable 'jmp_code' that is declared as a char *. When I run the following commands
printf("char by char, the code is '%c%c%c%c'\n", *jmp_code, *(jmp_code+1), *(jmp_code+2),*(jmp_code+3));
printf("printing the string, the code is '%s'\n", jmp_code);
I get the following results
char by char, the code is '0,0,0, ,'
printing the string, the code is 'ö\├w≡F┴w'
I am using codeblocks. Here is the sample code I am playing with.
#include <stdio.h>
#include <string.h>
char * some_func(char * code);
char * some_func(char * code) {
char char_array[4];
strcpy(char_array, "000");
code = char_array;
return code;
}
int main ( void ) {
char * jmp_code = NULL;
jmp_code = some_func(jmp_code);
printf("char by char, the code is '%c,%c,%c,%c,'\n", *jmp_code, *(jmp_code+1), *(jmp_code+2),*(jmp_code+3));
printf("printing the string, the code is '%s'\n", jmp_code);
return 0;
}
I am quite confused by this. Any help would be appreciated.
Thanks
Some quick observations:
char * some_func(char * code) {
char char_array[4];
strcpy(char_array, "000");
code = char_array;
return code;
}
You can't assign strings using = in C. That messes things up - you're assigning code the pointer of your locally allocated char_array to code, but you're not copying the contents of the memory. Also note that since char_array is allocated on the stack (usually), you'll find it disappears when you return from that function. You could work around that with the static keyword, but I don't think that's the nicest of solutions here. You should use something along the lines of (big warning this example is not massively secure, you do need to check string lengths, but for the sake of brevity):
void some_func(char * code) {
strcpy(code, "000");
return;
}
(Refer to this (and this) for secure string handling advice).
And call it via some_func(jmp_code) in main. If you're not sure what this does, read up on pointers.
Second problem.
char * jmp_code = NULL;
Currently, you've declared space enough for a pointer to a char type. If you want to use my suggestion above, you'll need either to use malloc() and free() or else declare char jmp_code[4] instead, such that the space is allocated.
What do I think's happening? Well, on my system, I'm getting:
and the code is '0,0,0,,' and the code
is ''
But I think it's chance that jmp_code points to the zeros on the stack provided by your some_func function. I think on your system that data has been overwritten.
Instead you're reading information that your terminal interprets as said character. Have a read of character encoding. I particularly recommend starting with The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)
You're returning a reference to a temporary array. char_array goes away when some_func() retuns, but you keep using the address of it. You need to use malloc() to allocate an array and then free() it after you use it.
You're printing from an invalid pointer. char_array is on the stack of some_func() function.
The function returns the pointer of something that is on the stack and will be no more after the function returns!
The first printf finds the stack still unchanged, the second, maybe, found it filled with... garbage!
It might be interesting to see:
const char *pos = jmp_code;
while (*pos)
printf("%d ", *pos++);
I think char type can not use non-ascii char codes. Meaning your string contains UTF-8 or like symbols which code could be in (0, over9000) range, while char codes could be in (0, 255) range.
I am going through a book and I tried running this example but I receive a segmentation fault - gdb says it's when it sets argv[0] = filename;
this code is copied/pasted straight from book's downloadable code samples.
#include <unistd.h>
int main() {
char filename[] = "/bin/sh\x00";
char **argv, **envp; // arrays that contain char pointers
argv[0] = filename; // only argument is filename - segmentation fault here
argv[1] = 0; // null terminate the argument array
envp[0] = 0; // null terminate the environment array
execve(filename, argv, envp);
}
Edit: The book is Hacking: The Art of Exploitation by Jon Erickson, which has VERY good reviews. This specific example is used as the first tutorial on converting C into machine code in the shellcode section, specifically it is exec_shell.c and can be downloaded from http://nostarch.com/hacking2/htm . I imagine some context around the use of this code was necessary in order to avoid some of the negative comments below, sorry for leaving details out, and thanks for the help.
It obviously isn’t a very good book. The problem is that neither argv nor envp are initialized, so when you write to argv[0], you’re trying to overwrite some random location in memory.
Try something like this:
#include <unistd.h>
int main() {
char *filename = "/bin/sh";
char *argv[2], *envp[1];
argv[0] = filename;
argv[1] = 0;
envp[0] = 0;
execve(filename, argv, envp);
}
This alternative initializes argv and envp on the stack, with enough space to contain two pointers and one pointer respectively.
In the code above, I’ve made one additional change to repair an additional common (but, in this case, harmless) misunderstanding. The \x00 that was at the end of "/bin/sh\x00" is redundant, since in C static strings are implicitly null-terminated. "/bin/sh\x00" is a string terminated by two nulls.
Alternatively, as pointed out by caf, here is a more compact example with exactly equivalent meaning:
#include <unistd.h>
int main() {
char *filename = "/bin/sh";
char *argv[2] = { filename, 0 };
char *envp[1] = { 0 };
execve(filename, argv, envp);
}
You never allocate the "arrays of pointers" meant to go in argv and envp! What book is it, that omits such crucial steps?!
Either add argv = malloc(2 * sizeof(char*)) (and similarly for envp) before you start assigning to argv[0] and friends, or change argv's and envp's declarations to be arrays of pointers rather than pointers to pointers (the latter's quite a feasible approach, in this specific case, since you do know exactly how many pointers you need in each at the time you're writing the code -- dynamic allocation is therefore somewhat supererogatory;-).
char **argv
argv is pointing to a memory location which you are not allowed to access/write to. It is something that is better known as a wild pointer.
Looks like you need to get a better book! In this code argv is a pointer with no storage allocated to it and pointing at random memory (or probably NULL). When you dereference it with argv[0] = ..., your code ends up trying to write to random memory. Your variable declaration should be something more like:
char *argv[3], *envp[1];
I have no idea where did you get this book, but it obviously sucks. argv is an uninitialized pointer, it holds a random address. Hence accessing it will most probably lead to the access violation.
Before using such multi-level pointers, I recommend reading up on dynamic memmory allocation in C.
Whenever you use pointers, you must also think whether you need to allocate space for the data that the pointers are going to point to (as also the pointers themselves, for multi-level pointers).
For example,
char **bar;
here, bar allocates space for 1 pointer-to-pointer, ie. enough space to store one address. This is not very useful without any additional data allocation.
In reality, you should be doing:
char **bar = calloc( 2 , sizeof(char *) );
here, bar allocates space for 1 pointer-to-pointer, ie. again, space to store one address as bar, AND 2 consecutive locations for storing 2 more pointers, namely bar[0] & bar1.
char bar[0]= calloc( 10 , sizeof(char) );
here, bar[0] allocates space for storing a string of size 10 - 1 (for \0 at end).
Now, if you do a string copy:
strcpy(bar[0],"Hello!");
the final memory map comes to: (addresses in circles, contents in blocks)
Many of the people here are on the right track, but missing some of the numerous problems here.
#include <unistd.h>
int main() {
char filename[] = "/bin/sh\x00";
char **argv, **envp; // arrays that contain char pointers
argv[0] = filename; // only argument is filename - segmentation fault here
argv[1] = 0; // null terminate the argument array
envp[0] = 0; // null terminate the environment array
execve(filename, argv, envp);
}
The problems here are:
1. The pointer array of character strings is never initialized. Pointers take up space too, and thus an array of pointers needs to use malloc in c.
2. Each character pointer in your pointer array needs its own malloc statement before use.
Here is the working code, with printouts to show you what is going on:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
unsigned int i=0;
char filename[] = "/bin/sh\x00";
char **argv; // arrays that contain char pointers
argv=(char **)malloc(sizeof(char*));
argv[0]=(char *)malloc(strlen(filename)*sizeof(char));
strcpy(argv[0],filename);
printf("Arg 0 is %u chars long...\n",strlen(argv[0]));
printf("Arg 0 is ");
while (argv[0][i] != '\0') {
printf("%c",argv[0][i]);
i++;
}
printf("!\n");
free(argv[0]);
}