Pointer types in c - c

I am trying to pass the address of an int[] to a system call. However messages only have fields for char pointers.
I have tried converting the int pointer to a char pointer and back again but the results in the array are not correct.
int pidarray[j];
m.m1_p3 = (char*)pidarray;
Also I tried to store the address of the array as an integer and pass it through a message integer field.
int pidarray[j];
m.m1_i3 = &pidarray;
EDIT:
This will be a system call of my creation, aimed at filling an array with pids and copying the data back to the process hence why I need to pass the address of the array. I call the system call a so,
_syscall(PM_PROC_NR, GETCHILDPIDS, &m);
It fills an array and attempts to copy it back to memory space owned by the calling process. This is done as:
sys_vircopy(SELF, (vir_bytes) &test, who_e,(vir_bytes) m_in.m1_i3, sizeof(test));
where test is a int[].
How can I send the address of a int[] in this format?

In C, arrays are decayed into pointers, in particular when passed as arguments.
So just handle that as a pointer. You may need to change the interface of your new system call (e.g. perhaps give it a pointer and a size, or have a convention saying that pidarray should be 0 terminated).
BTW, it smells like your system call is useless. You can do all that on Linux in user-land, thru existing syscalls(2) using /proc/ (see proc(5)...).

Related

Why can I pass an integer as a task parameter but can't pass a struct variable?

I was trying to pass a set of parameters to a task. So I created a struct and passed it to my task, like this:
my_type_t parameters_set;
//... assigning values to parameters_set
xTaskCreate( vMyTask, "MyTask", STACK_SIZE, (void*)parameters_set, 2,
&xHandle);
Inside my task I tried to retrieve the struct values doing the following:
my_type_t received_parameters = (my_type_t) pvParameters;
The task creation line triggers the following error while compiling: "cannot convert to a pointer type" and the struct retrieving line triggers the "Conversion to non-scalar type requested" error. I know if I use a pointer instead of the variable itself it will compile, but I can't do this because the function that creates the task will die and the task will have a reference to a variable that does not exist anymore. In the end I'll use a global struct variable.
But what I really would like to understand is why do tasks accept int values (not by reference), and don't accept a typedef struct? For example, the following snippet builds and works without problem:
//Inside the function that creates the task
int x = 0;
xTaskCreate( vMyTask, "MyTask", STACK_SIZE, (void*)x, 2,
&xHandle);
//Inside the Task
int received_parameter = (int) pvParameters;
Thanks in advance!
The code you show is not taking an int value as a parameter. You pass the parameter using (void*)x, which is an expression that converts the int x to a pointer.
The function xTaskCreate accepts a pointer. You have given it a pointer, so the compiler does not complain. However, the pointer you have given it is not a pointer to x (which would be written as &x) but is a pointer converted from the value of x. Although the compiler does not complain, this is generally not the right thing to pass to xTaskCreate.
The reason this is not working with a structure is that (void*)parameters_set is not a proper expression when parameters_set is a structure. This is because C provides for integers to be converted to pointers but not for structures to be converted to pointers. Generally, there is a natural correspondence between integers and pointers: In a “flat” address space, every byte in memory has an address, and those addresses are essentially counts of bytes from the “start” of the memory address space. So an integer can serve as an address and vice-versa. (In other address spaces, the correspondence may be more complicated, but C still allows the conversions, with some rules.) Thus, when you write (void*)x, the compiler converts the integer value in x to a pointer.
There is no such correspondence between structures and pointers, so the C standard does not define any conversion from structures to pointers, and the compiler complains when you write (void*)parameters_set.
What you should be passing for this parameter is the address of some data to be given to the task. If you want the task to have the data in x, you should pass &x. If you want the task to have the dat in parameters_set, you should pass &parameters_set. The & operator takes the address of its operand, which is different from using the (void*) cast, which attempts to convert its operand to a pointer.
According to the RTOS documentation for xTaskCreate, you should not pass the address of a “stack variable,” by which it effectively means, for C, an object with automatic storage duration. In other words, you should not pass an x or parameters_set that is defined within a function without static or (possibly, depending on arrangements made by RTOS and the C implementation; I am unfamiliar with RTOS) _Thread_local. Alternatively, you can allocate space for the parameters using malloc (or, per comment below, pvPortMalloc for RTOS) and pass that to xTaskCreate.

Following a pointer to a pointer

sqlite3_open takes a pointer to a pointer. Id like to trace the address of the second pointer.
E.g: p1(p2(obj))
https://www.sqlite.org/c3ref/open.html
int sqlite3_open(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
What is the syntax to get the address of that pointer in DTrace?
Im using the pid$target::sqlite3_open:return probe to read from the arg1 that was set from the entry probe.
Im currently using:
// Copy pointer bytes from arg1 to kernel, cast to pointer.
(uintptr_t *)copyin(arg1, sizeof(uintptr_t))
Which results in: invalid kernel access in action.
Im on MacOS with SIP enabled, is this the issue?
I may be misunderstanding your question, but what I suspect is that you've misunderstood how sqlite3_open works.
To call sqlite3_open you should have a code that looks like this:
sqlite3 * pDB = NULL;
/* ... */
int result = sqlite3_open("file:database.db", &pDB);
As you see, there's no "pointer to pointer" variable in my code. Instead, sqlite3_ope takes the address of of a pointer variable I allocated on the stack.
To copy that pointer is as simple as:
sqlite3 * pDB2 = pDB
The reason for this is simple:
The sqlite3_open function wants to return two variable, which is impossible in C.
Instead of returning two variables, sqlite3_open returns only one variable directly and returns the second variable indirectly.
In order to return the second, it takes a pointer to a variable of the same type it wants to return. Then, by dereferencing the address and filling in the value, it provides you with the second variable's value.
However, the second variable sqlite3_open returns is a pointer. This is why, in order to return a pointer as a second variable, sqlite3_open requires a pointer to a pointer variable.
Reading the address
In the example above, the pDB variable holds the address for the sqlite3 object (the one allocated by sqlite3_open).
The address, as you know, is simply a number representing a location in the memory. To read the pointer value as a number, simply cast the pointer to a uintptr_t. i.e.:
uintptr_t db_mem_addr_value = (uintptr_t)pDB;
Of course, numbers (and memory addresses) can't be printed as hex strings directly, they need a function that will convert them into hex notation.
Consider that in C you would print the memory address in Hex notation by using printf i.e.,
fprintf(stderr, "%p\n", (void *)pDB);
Using dtrace would be the same. You might want to convert the pointer address to a number, for example, using the lltostr dtrace function:
lltostr((uintptr_t)*(void**)arg1, 16)
Not a dtrace pro, but here are some observations.
uintptr_t is defined to be large enough to hold any pointer converted to an integer. Note that this does not imply that sizeof(uintptr_t) == sizeof(void*). It is perfectly valid (and on some platforms, necessary) for uintptr_t to be strictly larger than a pointer. That means your copyin call might be copying more bytes than are actually there. Try using a size of sizeof(sqlite**) instead.
Also, it's possible that some of OSX's internal protection mechanisms are causing you problems. See the answer on this related question for a good explanation.

Is the gist/importance of pointers due to the fact that non-primitive data requires multiple memory blocks?

I feel like this is the final piece in me understanding pointers. "Why are pointers important?"
(I mean, I'm sure there's a lot of reasons, but is this not the biggest?)
For awhile I've understood that int num = 5; was done because num is a way for us to refer to the value stored at whatever memory address we put 5 into. If I then do num = 10; it updates that memory address to store 10 instead, and num still points to the value at that particular memory address. Am I right so far?
So I was confused why we wouldn't just do char str = "string", or the same for other objects. Is it because what we're trying to store cannot be stored in one memory block, unlike int and other primitives?
We do it because we need multiple memory blocks, and pointers effectively give us a reference to where it starts and then we can go as far as we need to collect all the data needed for the object?
Is the importance of pointers due to the fact that non-primitive data requires multiple memory blocks? We need multiple memory blocks, and pointers effectively give us a reference to where it starts and then we can go as far as we need to collect all the data needed for the object?
No. What you are describing is the important of arrays.
So what is the importance of pointers?
Suppose you have some data:
12
What can you do with that data? You can store it in a storage location and fetch it from that location later when you need it.
int height = 12;
You can pass it as a value to a method:
doit(12);
You can compare it for equality with other values:
if (height == 13)
and a few other things as well, but these are some of the big ones.
Well, the same thing is true of pointers. Pointers are values, so they can be stored, fetched, passed and compared. But any addressable storage location can be turned into a pointer. So this is the power of pointers in C: they allow you to treat storage locations like any other data.
and num still points to the value at that particular memory address
No, because num is not a pointer. I'm counting beans here, but that's important to get your ideas right. When you define a variable num, the compiler assigns the name num to a memory address, which stays valid as long as the variable is in scope - for the whole program, if it's a global variable, or until your function returns, for local variables.
Objects can be any size, for example, a structure might consist of a lot of elements. And something like
char c[100]="string"
is perfectly valid; there are no pointers involved (yet).
One of the reasons why you need pointers is when you call a function. Normally, all parameters to a function are called by value. So, if you have a function
void swap (int x, int y) {
int temp=x;
x=y;
y=temp;
}
and call it
int a=3;
int b=5;
swap(a, b);
printf("%d %d\n", a, b);
you'll get output values 3 and 5 - the variables have, obviously, not been swapped. The reason for this is the compiler creates copies of the variables and passes the copies to swap.
Now, if you want to tell the compiler "I don't want copies, i want swap to change the memory locations that i named a and b", you need pointers:
void swap (int *x, int *y) {
int temp=*x;
*x=*y;
*y=temp;
}
int a=3;
int b=5;
swap(&a, &b);
printf("%d %d\n", a, b);
The & operator tells the compiler "I want the memory address that i named a, not the value that i wrote into that memory address". Within the swap function, the * means "x is not the value that i want, it's the address of the memory i really want to change - the variable that belongs to the function that called me". Other programming languages like pascal call this "call by reference", vs. "call by value" in C.
Now your language has pointers. Let's reconsider strings, and arrays.
If i call a function
myfunction("Thisisaverylongstringthatjustwontendnoway....")
the call by value has to copy a lot of bytes from the caller to the callee, which is inefficient. So, one of the design decisions in C was:
Whenever a function calls another, passing an array as a parameter, the array is not passed by value, instead, we automatically pass a pointer the the start of the array, making it a call by reference.
So, in function calls, arrays (and strings are just a special case of an array) are always passed as pointer. Which is why, in C, you have to learn about pointers quite soon; you can get along without them much longer in, say, Pascal. Or Java (where, behind the scenes, you work with pointers all the time when you're working with Objects, but Java hides that from you).
And this is why pointers are, very often, introduced shortly after arrays and strings, when you learn C. As soon as you know what a function is, and what an array, or a string, is, you need to know about pointers or you won't get functions and arrays together.
Your last sentence about "multiple memory blocks" isn't correct in the sense that anything that's larger than a few bytes needs a pointer - structures do not - but, in most cases, your program will just be faster with pointers. If you have two strings, each 100 bytes long, and want to swap them, you'd need to do a lot of copying stuff around. Just swapping the pointers is much faster (typically, a pointer needs 4-8 bytes), so as soon as you're dealing with larger objects, you want to deal with pointers pointing to them, for efficiency reasons.
Now i haven't even begun with dynamic memory allocation .. but i guess my answer is large enough already.

C call from Smalltalk

I'm trying to call EnumServicesStatus from within VisualWorks. For the first call I set the parameters to the required values to know how many bytes the returned information will require (pcbBytesNeeded).
Now I need to allocate memory for the lpServices buffer using malloc:, which expects the number of instances as an argument. How can I calculate this easily? Just dividing the pcbBytesNeeded by the size of of an LPENUM_SERVICE_STATUS struct makes my code crash when freeing the memory.
/Edit
I solved the crash when freeing the memory. (I accidently manipulated the variable holding the pointer). However, my question in the comment to Karsten is still valid. Why doesn't the size of ENUM_SERVICE_STATUS divide pcbBytesNeeded? Is this because of the LPTSTR lpServiceName and LPTSTR lpDisplayName members?
you can send #sizeOf to the ENUM_SERVICE_STATUS structure, similar to the sizeof(ENUM_SERVICE_STATUS) in C.
Something like:
numItems := pcbBytesNeeded / self ENUM_SERVICE_STATUS sizeOf.
please also make sure that you call the EnumServicesStatusW function, because EnumServicesStatus is a macro that actually points to EnumServicesStatusW.

what is the correct way to define a string in C?

what is the correct way to define a string in C?
using:
char string[10];
or
char *string="???";
If I use an array, I can use any pointer to point to it and then manipulate it.
It seems like using the second one will cause trouble because we didn't allocate memory for that. I am taught that array is just a pointer value, I thought these two are the same before.
Until I did something like string* = *XXXX, and realize it didn't work like a pointer.
As #affenlehrer points out, how you "define" a string depends on how you want to use it. In reality, 'defining' a string in C really just amounts to putting it in quotes somewhere in your program. You should probably read more about how memory works and is allocated in C, but if you write:
char *ptr = "???"
What happens is that the compiler will take the string "???" (which is really four bytes of data, three '?'s followed by one zero byte for the NUL terminator). It will insert that at some static place in your program (in something called the .bss segment), and when your program starts running, the value of ptr will be initialized to point to that location in memory. This means you have a pointer to four bytes of memory, and if you try to write outside of those bytes, your program is doing something bad (and probably violating memory safety).
On the other hand, if you write
char string[10];
Then this basically tells the compiler to go allocate some space in your program of 10 bytes, and make the variable 'string' point to it. It depends where you put this: if you put it inside a function, then you will have a stack allocated buffer of 10 bytes. If you manipulate this buffer inside a function, and then don't do anything with the pointer afterwards, you're all fine. However, if you pass back the address of string -- or use the pointer in any way -- after the function returns, you're in the wrong. This is because, after the function returns, you lose all of the stack allocated variables.
There are even more ways to create strings in C (e.g. using malloc). What is your usecase? Basically you need a place in memory where the data is stored (on the stack, on the heap, static as in your second example) and then a character pointer to the first character of your string. Most string related functions will "see" the end of the string by the trailing '\0', in some other cases (mostly general purpose data related functions) you also have to provide the length of the string.

Resources