A few questions about this simple scenario:
#include <unistd.h>
#include <stdio.h>
void empty(){};
int main()
{
printf("%p\t%lu\n", empty, sizeof(empty));
write(1, empty, 100);
return 0;
}
What exactly is happening when I use the function's name as a reference?
It shows size of one but printf still treats it as a pointer and yet a void pointer is of size 8. Additionally, onto the write function:
Essentially I want to replicate the printf %p writing the value of a memory address rather than the value at that address mainly to get a better handle on how this all works :^)
Thanks!
Related
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
printf("%s %s\n", getpwnam("steve")->pw_name, getpwnam("root")->pw_name);
printf("%d %d\n", getpwnam("steve")->pw_uid, getpwnam("root")->pw_uid);
return EXIT_SUCCESS;
}
$ gcc main.c && ./a.out
steve steve
1000 0
In line 8, we try to print the user names of steve and root, but it prints steve twice. In line 9, we try to print the UIDs of steve and root, and it successfully prints them.
I wanna ascertain the root cause of that bizarre behavior in line 8.
I know the pointer returned by getpwnam points to a statically allocated memory, and the memory pointed by fields like pw_name/pw_passwd/pw_gecos/pw_dir/pw_shell are also static, which means these values can be overwritten by subsequent calls. But still confused about this strange result.
This is exercise 8-1 of The Linux Programming Interface. Add this so that someone like me could find this through the search engine in the future:). And the question in the book is wrong, go here to see the revised version.
The code calls getpwnam() in succession returning a pointer to the same address and passing the same pointer to printf() twice. The order the compiler decides to make the calls will determine whether it shows “steve” or “root”.
Allocate two buffer spaces and use one for each in the call to printf() by calling getpwnam_r() instead.
The getpwnam function can return a pointer to static data, so each time it's called it returns the same pointer value. And because you're calling this function multiple times as an argument to printf, you'll only see the result of whichever one of those function calls happens last.
The key point here is that the evaluation order of the arguments to a function are unsequenced, which means there's no guarantee whether getpwnam("steve") happens first or getpwnam("root") happens first.
The result from getpwnam() may be overwritten by another call to getpwnam() or getpwuid() or getpwent(). Your code is demonstrating that.
See the POSIX specifications of:
getpwnam()
getpwuid()
getpwent()
You have no control over the order of evaluation of the calls. If you saved the pointers returned, you'd probably get different results printed.
POSIX also says:
The application shall not modify the structure to which the return value points, nor any storage areas pointed to by pointers within the structure. The returned pointer, and pointers within the structure, might be invalidated or the structure or the storage areas might be overwritten by a subsequent call to getpwent(), getpwnam(), or getpwuid(). The returned pointer, and pointers within the structure, might also be invalidated if the calling thread is terminated.
You should treat the return values as if they were const-qualified, in other words.
Note that the code in the library functions need not overwrite previous data. For example, on macOS Big Sur 11.6.8, the following code, compiled with -DUSER1=\"daemon\" as one of the compiler options, yields the result:
daemon root
1 0
U1A = 0x7fecfa405fd0, U2A = 0x7fecfa405c60
U1B = 0x7fecfa405fd0, U2B = 0x7fecfa405c60
Modified code:
/* SO 7345-2740 */
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef USER1
#define USER1 "steve"
#endif
#ifndef USER2
#define USER2 "root"
#endif
int main(void)
{
const struct passwd *user1a = getpwnam(USER1);
const struct passwd *user2a = getpwnam(USER2);
const char *user1_name = user1a->pw_name;
const char *user2_name = user2a->pw_name;
printf("%s %s\n", user1_name, user2_name);
const struct passwd *user1b = getpwnam(USER1);
const struct passwd *user2b = getpwnam(USER2);
int user1_uid = user1b->pw_uid;
int user2_uid = user2b->pw_uid;
printf("%d %d\n", user1_uid, user2_uid);
printf("U1A = %p, U2A = %p\n", (void *)user1a, (void *)user2a);
printf("U1B = %p, U2B = %p\n", (void *)user1b, (void *)user2b);
return EXIT_SUCCESS;
}
It is moderately likely that the library functions read the whole file into memory and then pass pointers to relevant sections of that memory. Certainly, in this example, the pointers to the entry for user daemon and user root are stable.
YMWV — Your Mileage Will Vary!
I know I can just copy the function by reference, but I want to understand what's going on in the following code that produces a segfault.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int return0()
{
return 0;
}
int main()
{
int (*r0c)(void) = malloc(100);
memcpy(r0c, return0, 100);
printf("Address of r0c is: %x\n", r0c);
printf("copied is: %d\n", (*r0c)());
return 0;
}
Here's my mental model of what I thought should work.
The process owns the memory allocated to r0c. We are copying the data from the data segment corresponding to return0, and the copy is successful.
I thought that dereferencing a function pointer is the same as calling the data segment that the function pointer points to. If that's the case, then the instruction pointer should move to the data segment corresponding to r0c, which will contain the instructions for function return0. The binary code corresponding to return0 doesn't contain any jumps or function calls that would depend on the address of return0, so it should just return 0 and restore ip... 100 bytes is certainly enough for the function pointer, and 0xc3 is well within the bounds of r0c (it is at byte 11).
So why the segmentation fault? Is this a misunderstanding of the semantics of C's function pointers or is there some security feature that prevents self-modifying code that I'm unaware of?
The memory pages used by malloc to allocate memory are not marked as executable. You can't copy code to the heap and expect it to run.
If you want to do something like that you have to go deeper into the operating system, and allocate pages yourself. Then you need to mark those as executable. You would most likely need administrator rights to be able to set the executable flag on memory pages.
And it's really dangerous. If you do this in a program you distribute and have some kind of bug that lets an attacker use our program to write to those allocated memory pages, then the attacker can gain administrator rights and take control of the computer.
There's also other problems with your code, like pointers to functions might not translate well into general pointers on all platforms. It's very hard (not to mention non-standard) to predict or otherwise get the size of a function. You also print out pointers wrong in your code example. (use the "%p" format to print a void *, casting the pointer to a void * is needed).
Also when you declare a function like int fun() that's not the same as declaring a function that takes no arguments. If you want to declare a function that takes no arguments you should explicitly use void as in int fun(void).
The standard says:
The memcpy function copies n characters from the object pointed to by s2 into the object pointed to by s1.
[C2011, 7.24.2.1/2; emphasis added]
In the standard's terminology, functions are not "objects". The standard does not define behavior for the case where the source pointer points to a function, therefore such a memcpy() call produces undefined behavior.
Additionally, the pointer returned by malloc() is an object pointer. C does not provide for direct conversion of object pointers to function pointers, and it does not provide for objects to be called as functions. It is possible to convert between object pointer and function pointer by means of an intermediate integer value, but the effect of doing so is at minimum doubly implementation-defined. Under some circumstances it is undefined.
As in other cases, UB can turn out to be precisely the behavior you hoped for, but it is not safe to rely on that. In this particular case, other answers present good reasons to not expect to get the behavior you hoped for.
As was said in some comments, you need to make the data executable. This requires communicating with the OS to change protections on the data. On Linux, this is the system call int mprotect(void* addr, size_t len, int prot) (see http://man7.org/linux/man-pages/man2/mprotect.2.html).
Here is a Windows solution using VirtualProtect.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#ifdef _WIN32
#include <Windows.h>
#endif
int return0()
{
return 0;
}
int main()
{
int (*r0c)(void) = malloc(100);
memcpy((void*) r0c, (void*) return0, 100);
printf("Address of r0c is: %p\n", (void*) r0c);
#ifdef _WIN32
long unsigned int out_protect;
if(!VirtualProtect((void*) r0c, 100, PAGE_EXECUTE_READWRITE, &out_protect)){
puts("Failed to mark r0c as executable");
exit(1);
}
#endif
printf("copied is: %d\n", (*r0c)());
return 0;
}
And it works.
Malloc returns a pointer to an allocated memory (100 bytes in your case). This memory area is uninitialized; assuming that memory could be executed by the CPU, for your code to work, you would have to fill those 100 bytes with the executable instructions that the function implements (if indeed it can be held in 100 bytes). But as has been pointed out, your allocation is on the heap, not in the text (program) segment and I don't think it can be executed as instructions. Perhaps this would achieve what it is you want:
int return0()
{
return 0;
}
typedef int (*r0c)(void);
int main(void)
{
r0c pf = return0;
printf("Address of r0c is: %x\n", pf);
printf("copied is: %d\n", pf());
return 0;
}
I have the following code:
#include <stdio.h>
char * lookLine (FILE *fichero)
{
char p[25];
fgets (p, sizeof (p), fichero);
return p;
}
int main (void) {
printf ("%s\n", lookLine (fopen ("suma.c", "r")));
return 0;
}
And I get the following output:
#��x�
Not nice. My intention is to print out the first line of the file whose name "suma.c". It should print out the following:
#include <stdio.h>
Nevertheless, if I print out the content of p string into the same lookFile function, it does it fine:
#include <stdio.h>
void lookLine (FILE * fichero)
{
char p[25];
fgets (p, sizeof (p), fichero);
printf ("%s\n", p);
}
int main (void) {
lookLine (fopen ("suma.c", "r"));
return 0;
}
And the output I get now is the correct one:
#include <stdio.h>
My reasoning is this: by using fgets I save the string of the first line of "name.c" in the p array and I return its address, which is taken by the second argument of printf function in main.
But I have found out that this only works when I use the printf function directly into the same lookLine function...
Please, could someone tell me what's really going on here?
It's because you are returning a pointer to a local array from the read function.
Remember that local variables are stored on the stack, and that includes arrays. And when the function returns that stack space is reclaimed by the compiler to be used by other function calls. So you have a pointer pointing to another function's memory.
The lifetime of the array p ends at the return statement (technically p is a local variable with automatic storage duration; this means it's lifetime ends at the matching }).
The program then invokes undefined behavior because it uses an indeterminate value (reading from a pointer that no longer points to valid memory). This is the reason you can print the string while still in read(), but get garbage when printing from main().
And note that read is a POSIX function that may be interfering with the one you defined (not a problem in a strict C89 or C99 mode, but most compilers aren't by default). [The OP in the meantime renamed the function to lookLine().]
As pointed to by Joachin Pileborg correctly, you are trying to return a stack variable which will be reclaimed, when you return from the function.
Instead you can try to pass a character array and it's size as inputs to the function read. Btw, if you don't intend to do anything else apart from calling fgets in the read function, then it is better that you call fgets in the main function itself.
Incase if you are doing some additional logic in read and you also cannot pass the buffer and it's size as input to read function, you can allocate the memory required from reading using malloc and return the pointer to the calling function. But, personally, I wouldn't recommend it as it is better to ensure the caller of the read takes the responsibility of creation and deletion of the array.
I started learning C, and I don't understand what I'm doing wrong. Here is a simple code of a function that returns the pid+".data".
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
char * getfilename(){
char name[60];
sprintf(name,"%i.data",getpid());
return name;
}
void main(){
char* name = getfilename();
printf("%s",name);
}
outputs: ��#�a.
So I guess that I'm doing something wrong.
char * getfilename(){
char name[60];
sprintf(name,"%i.data",getpid());
return name;
}
You cannot access name object after getfilename has returned. The lifetime of the automatic object name ends at the getfilename last }. Accessing it after the function returns is undefined behavior.
As a temporary fix you can specify name as static and it will work. But what you should do is to have the getfilename function accepts a pointer argument where the filename will be written.
EDIT:
Why I don't suggest to use strdup?
strdup is not a Standard C function. strdup lives in the POSIX world. For portability reasons whenever I can, I prefer to use Standard C functions.
strdup performs a hidden malloc call and you have not to forget to perform a free. This is contrary to all functions of the Standard C library which never call malloc (or actually that never appear to call malloc). strdup is a bad API design.
strdup is performing a copy of a string. Why do you need to perform an extra copy? Just write the string in a place you can retrieve it.
One solution is to use strdup, i.e. change:
return name;
to:
return strdup(name);
This makes a copy of your temporary (local) string using dynamic memory allocation (i.e. malloc).
You must of course make sure that you subsequently free this string when you're done with it.
You'll need:
#include <string.h> // strdup()
#include <stdlib.h> // free()
char name[60]
lives on the stack, but only as long as being inside getfilename() afterwards its freed, so any references (as also returned by getfilename()) to it become invalid.
char name[60] is a local variable which is allocated when the function is called and deallocated when it returns. When you try to return it, you're really returning it's address (after all arrays are mostly syntactic sugar for pointer arithmetic). Now, your caller has a pointer to a block of memory that has been free, and thus will likely contain garbage.
You can't return the array name from your function getfilename, because it is a (regular) local variable and those get cleaned up when the function returnes.
So, when you get back in main and try to print the returned value, the pointer name there refers to a block of memory that has been reused for other purposes.
There are several solutions for this problem:
Make name in getfilename static. This will ensure that it outlives the call to getfilename and can safely be returned, but has the drawback that all calls to getfilename use the same buffer.
Allocate the array dynamically with malloc (and don't forget to clean it up with free when you are done with it)
Pass the buffer to store the value in as a parameter.
As mentioned in the other answers you cannot return a pointer which points somewhere in the stack of a function.
You can simply pass the allocated array to getfilename() function. You can rewrite the program as follows.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void getfilename(char * name)
{
sprintf(name,"%i.data",getpid());
}
int main(void)
{
char name[60];
getfilename(name);
printf("%s\n",name);
return 0;
}
This should work fine.
Hi I am trying to make a program with pointer in a struct. Compiler appears no problems but the program crashes.
Could you help me please ?
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
int pos;
typedef struct _Parking Parking;
struct _Parking
{
int pos;
char name[15];
char description[80];
float price;
int slots[5];
char last_driver_id;
int reservations;
};
Parking *myaccounts;
int create_Parking()
{
strcpy(myaccounts->name,"Pro");
myaccounts->pos ++;
return pos-1;
}
int main()
{
int a;
a = create_Parking();
printf("a=%d\n",a);
printf("name=%s\n",myaccounts->name);
system("pause");
return 0;
}
Your myaccounts pointer is initialized to NULL (as a global variable) and does therefore not point to usable memory. Try the manual page for malloc for more information.
Edit: Incorporated Maciej's comment.
You never allocate any memory for "myaccounts".
Pointers in C do not point to valid memory (and will crash if you try to use them), until you specifically point them somewhere valid by using the address-of operator on an object (&) or by allocating memory for them and assigning that address into the pointer (malloc() and friends). Of course if you use the address-of operator that location can go invalid when the object goes out of scope. If you use malloc() that location can go invalid when free() is called. In either case, your pointer will become invalid again.
C is hugely reliant on pointers too, so you can count on any C code you write of any size having a bug or two of this nature until you track them down and fix them. Getting your sources past the compiler in C really doesn't mean much. If you want to write in a language where your code is liable to work first time you run it after getting it past the compiler, you want Ada.
Your pointer doesn't point to anything. You can try either one of these:
Parking myaccountsInstance;
Parking *myaccounts = &myaccountsInstance;
Or in the main function:
Start with:
myaccounts = (Parking*)malloc(sizeof(Parking));
And end with:
free(myaccounts);