How are parameters passed on the stack in variable argument function? - c

I thought that the function removes the parameters from the stack after it's done, but a function like printf removes a variable number of parameters from the stack when it's called.
How does it know how many parameters to remove from the stack? Is there a secret argument to specify how many arguments are passed?
Thanks

The C calling convention specifies that is the caller and not the callee the one responsible from popping the parameters from the stack. That's why functions with a variable argument list must be cdecl. So,
I thought that the function removes the parameters from the stack after it's done.
That's only true for certain calling conventions, it isn't true for the C calling convention.
How does it know how many parameters to remove from the stack? Is there a secret argument to specify how many arguments are passed?
It doesn't, and no there is no secret argument.

The caller function will clean the stack (in the correct calling convention). The compiler will generate the code for that. The compiler is the one knowing exactly how many arguments you passed on the arguments list, because, well, it compiled it..

The calling code cleans up the stack, and it's up to the called function to correctly determine that there is "enough" arguments have been passed for whatever it wants to do. This doesn't have to be an argument as such, it could be something like this:
int sum(int first, ...)
{
int s = first;
int v;
va_list va;
va_start(va, first);
while (v = va_arg(va, int) != -1)
{
sum += v;
}
va_end(va);
return sum;
}
x = sum(1, 2, 3, -1);
y = sum(1, 2, 3, 4, 5, 6, 7, 8, 9, -1);
Link to how many arguments in varargs function

Related

Can you have in C variable length arguments functions with cases when you don't want to pass any variable?

I want to create a function in C with variable length arguments in which I may not want to pass any variable at some point. I such a thing possible in C? I would like some code snippets if possible. Also, I have to mention that the function will have passed only char* variables when there are passed some variables.
A function with variable arguments must have at least one names argument in order to read the others.
For your particular case, since you want to pass a list of char * arguments you can use NULL to denote the end of the argument list. So in the case where there is nothing to pass, you just pass a singe NULL argument.
This is not supported by standard C.
For a function parameter type list terminated with an ellipsis, there must be at least one named parameter.
For a function defined with an identifier list, the number of arguments in the call must match the number of parameters in the definition; varying numbers of arguments are not supported.
If you will call a function with a varying number of char * arguments, and that number may be zero, you could declare the function with a dummy first argument that is always passed but never used, as with:
void foo(int dummy,...);
Note that passing no arguments is a troublesome design. Normally, routines that accept varying numbers of arguments infer the number of arguments from one or more arguments. For example, the first argument might contain the number of remaining arguments, or it might be a format string (as with printf) from which the number and types of remaining arguments can be deduced. If you want a function to accept zero arguments in some situations, it has to have a way of knowing whether it was called with zero arguments or more. That would require information in some global state, which is typically a bad design.
no you cant
you need at least one known argument
void foo(int dummy, ...)
{
va_list ap;
C does not provide any mechanism to allow a called function to determine how many arguments were provided. The mechanism must be part of the calling interface.
For example, printf relies on the % format specifications, while execv requires the caller to place a null pointer as the last argument.
A varargs function can be called with no variable arguments, but the caller must not attempt to access any variable argument in that case. For example, the mode argument to the Posix open() function is only consulted in the case that a new file is created, so it need not be supplied if the flags argument doesn't contain the O_CREAT flag (or some other extension flag, such as O_TMPFILE in Linux, which requests file creation).
The variable-length part of the prototype must follow at least one fixed argument. So it is not possible fir a varargs function to be called with no arguments at all.
Can you have in C variable length arguments functions with cases when you don't want to pass any variable?
Yes. In modern C, Code cannot define a ... function with no arguments, yet you can call such a function with no arguments by declaring the a function without function signature. In that way the function can be called with zero arguments.
The function still needs some way to understand the count of arguments. This is often done with the first argument as a count (or format) or a final argument as a sentinel.
Given "will have passed only char*"...
int foo_count(int counter, ...);
// zero usage example
foo_count(0);
int foo_sentinel(char *s);
// zero usage example
foo_sentinel((char*) NULL);
To do so with passing no arguments, the count needs to be conveyed in some other fashion, perhaps with a global variable - although this is not recommended. (Better to simply pass the count.)
Declare function:
int foo_count;
int foo(); // no prototype
Call function
foo_count = 0; foo()
foo_count = 1; foo("one")
foo_count = 2; foo("one", "two")
Define the function
int foo(char *s1, ...) {
if (foo_count > 0) {
va_list ap;
va_start(ap, s1);
puts(s1);
for (int i=1; i < foo_count; i++) {
puts(va_arg(ap, char *));
}
va_end(ap);
}
}

Direct access to the function stack

I previously asked a question about C functions which take an unspecified number of parameters e.g. void foo() { /* code here */ } and which can be called with an unspecified number of arguments of unspecified type.
When I asked whether it is possible for a function like void foo() { /* code here */ } to get the parameters with which it was called e.g. foo(42, "random") somebody said that:
The only you can do is to use the calling conventions and knowledge of the architecture you are running at and get parameters directly from the stack. source
My question is:
If I have this function
void foo()
{
// get the parameters here
};
And I call it: foo("dummy1", "dummy2") is it possible to get the 2 parameters inside the foo function directly from the stack?
If yes, how? Is it possible to have access to the full stack? For example if I call a function recursively, is it possible to have access to each function state somehow?
If not, what's the point with the functions with unspecified number of parameters? Is this a bug in the C programming language? In which cases would anyone want foo("dummy1", "dummy2") to compile and run fine for a function which header is void foo()?
Lots of 'if's:
You stick to one version of a compiler.
One set of compiler options.
Somehow manage to convince your compiler to never pass arguments in registers.
Convince your compiler not to treat two calls f(5, "foo") and f(&i, 3.14) with different arguments to the same function as error. (This used to be a feature of, for example, the early DeSmet C compilers).
Then the activation record of a function is predictable (ie you look at the generated assembly and assume it will always be the same): the return address will be there somewhere and the saved bp (base pointer, if your architecture has one), and the sequence of the arguments will be the same. So how would you know what actual parameters were passed? You will have to encode them (their size, offset), presumably in the first argument, sort of what printf does.
Recursion (ie being in a recursive call makes no difference) each instance has its activation record (did I say you have to convince your compiler never optimise tail calls?), but in C, unlike in Pascal, you don't have a link backwards to the caller's activation record (ie local variables) since there are no nested function declarations. Getting access to the full stack ie all the activation records before the current instance is pretty tedious, error prone and mostly interest to writers of malicious code who would like to manipulate the return address.
So that's a lot of hassle and assumptions for essentially nothing.
Yes you can access passed parameters directly via stack. But no, you can't use old-style function definition to create function with variable number and type of parameters. Following code shows how to access a param via stack pointer. It is totally platform dependent , so i have no clue if it going to work on your machine or not, but you can get the idea
long foo();
int main(void)
{
printf( "%lu",foo(7));
}
long foo(x)
long x;
{
register void* sp asm("rsp");
printf("rsp = %p rsp_ value = %lx\n",sp+8, *((long*)(sp + 8)));
return *((long*)(sp + 8)) + 12;
}
get stack head pointer (rsp register on my machine)
add the offset of passed parameter to rsp => you get pointer to long x on stack
dereference the pointer, add 12 (do whatever you need) and return the value.
The offset is the issue since it depends on compiler, OS, and who knows on what else.
For this example i simple checked checked it in debugger, but if it really important for you i think you can come with some "general" for your machine solution.
If you declare void foo(), then you will get a compilation error for foo("dummy1", "dummy2").
You can declare a function that takes an unspecified number of arguments as follows (for example):
int func(char x,...);
As you can see, at least one argument must be specified. This is so that inside the function, you will be able to access all the arguments that follow the last specified argument.
Suppose you have the following call:
short y = 1000;
int sum = func(1,y,5000,"abc");
Here is how you can implement func and access each of the unspecified arguments:
int func(char x,...)
{
short y = (short)((int*)&x+1)[0]; // y = 1000
int z = (int )((int*)&x+2)[0]; // z = 5000
char* s = (char*)((int*)&x+3)[0]; // s[0...2] = "abc"
return x+y+z+s[0]; // 1+1000+5000+'a' = 6098
}
The problem here, as you can see, is that the type of each argument and the total number of arguments are unknown. So any call to func with an "inappropriate" list of arguments, may (and probably will) result in a runtime exception.
Hence, typically, the first argument is a string (const char*) which indicates the type of each of the following arguments, as well as the total number of arguments. In addition, there are standard macros for extracting the unspecified arguments - va_start and va_end.
For example, here is how you can implement a function similar in behavior to printf:
void log_printf(const char* data,...)
{
static char str[256] = {0};
va_list args;
va_start(args,data);
vsnprintf(str,sizeof(str),data,args);
va_end(args);
fprintf(global_fp,str);
printf(str);
}
P.S.: the example above is not thread-safe, and is only given here as an example...

Can you pass a function with a variable amount of arguments as an argument to another function in C?

Related to [question]: How do you pass a function as a parameter in C?
Is it possible in C to pass a function that has a variable number of arguments to another function? If so, could someone point me to some documentation or fill me in? Thanks.
You can't pass a function (of any sort) as a parameter, but you can pass a pointer to a function (again, of pretty much any sort). It's usually easiest to use a typedef:
typedef int (*fptr)(char const *, ...); // e.g., match with `printf`
int apply(fptr f, char const *a, int b) {
return f(a, b);
}
You can make a function pointer, e.g.:
typedef int (*vafunc)(const char *, ...); // like printf
However, you cannot really forward the arguments, i.e. the following doesn't exist in standard C:
void call_other(vafunc f, const char * fmt, ...)
{
// want to say:
// f(fmt, ...); // How to write this???
}
GCC offers such anonymous argument forwarding as an extension, but it's not possible in standard C. You're typically expected to match each variadic function with a v... counterpart that takes a va_list argument, precisely for this purpose. (Calling f with a fixed number of arguments is possible, of course: f("abc", 1, 2, 3);)
http://www.lemoda.net/c/function-pointer-ellipsis/index.html seems to be what you seek.
You can pass a varargs function the same way as you would another function.
Here's a short test program that demonstrates passing a varargs function as a parameter:
int bar(int x, ...) {
/* In a real program, you would actually use the arguments beyond x */
return x;
}
int foo(int (*baz)(int, ...)) {
return bar(10, "ABC");
}
int main(void) {
printf("%d\n", foo(bar));
return 0;
}
It prints 10, as you might expect.
N.B. You can't actually pass a function as an argument to another function in C - instead, you can pass a function pointer, which points to the actual function as loaded from the executable. This is weaker than the first-class status of functions in functional programming languages, or even than the status of a delegate in some object-oriented languages like C#. For instance, you can't create a function on the fly in C.
Sure. They're called "variadic functions".
1) Just use an "ellipses" ("...") as the last argument in your function prototype
2) In order for the called function to "know" how many arguments were passed to it, use the macros "va_start" and friends in "stdargs":
3) 1) and 2) above are simply to have a function that has a variable #/arguments. You can also have a function pointer with a variable #/arguments. Do the same thing - just include the ellipses ("...") in your function prototype, and use "stdargs" in your function implementation.

Is it possible to portably define a function that accepts any number of arguments?

I have a vague understanding of what 'C portability' means (IIRC, it means that the C language spans multiple platforms, but must adhere to certain standards (?)) and would like to know if we can portably write programs that would accept any number of arguments (even none).
What I do know is that without considering portability, all functions written with an empty pair of parentheses '()' can accept x-amount of arguments, but what about with it? It seems that there are a few papers on encouraging limitations regarding the number of arguments accepted by portably defined functions but I have yet to find one that says we cannot pass x-number of arguments (where is x is not bounded).
a function defined with an empty set of parenthesis:
void f() {...}
accept no parameters and it is undefined behavior to call it with any.
a function declared with an empty set of parenthesis:
void g();
must be called with the same number and same type of parameters that it has been defined, but the compiler won't check it. It is an undefined behavior if you mess up.
to declate a function as taking no parameter (and thus getting an error message if you mess up), use
void g(void);
a function may be variadic, but to call it you must see a declaration which state the function is variadic:
void h(int nb, ...);
(Not that in C a variadic function must have at least one non variadic parameter, in C++ it isn't the case) A variadic function must be called with at least the non variadic argument specified.
The minimum limit on the number of parameters (for any function) is 127. (Well, what the standard says is that an implementation must be able to compile at least one program reaching that limit).
--
To clear up a confusion:
void f() { ... }
vs
void g(void) { ... }
f is defined as accepting no parameters and can't be called with any by declared as accepting an unknow number of parameters so the compiler will not ensure that no paramaters are given. g is defined and declared as accepting no parameters. It's a left over of K&R days with functions definitions like
int h()
int i;
{...}
which declares a function taking an indeterminate number of parameters but define it as taking one int parameter. This style is totally out of fashion and the only case of practical importance remaining is the f vs g one.
Use <stdarg.h>.
See, for example, section 15, question 4 of the C-FAQ.
Edit: example of stdarg.h> usage
#include <stdarg.h>
#include <stdio.h>
/* sum all values (no overflow checking) up to a 0 (zero) */
int sum(int v, ...) {
va_list va;
int s = v;
if (v) {
va_start(va, v);
while ((v = va_arg(va, int))) {
s += v;
}
va_end(va);
}
return s;
}
int main(void) {
printf("sum(5, 4, 6, 10) is %d\n", sum(5, 4, 6, 10, 0));
return 0;
}

Is it safe to pass "too many" arguments to a external function?

This situation can only occur without name mangling (I believe), so the below code is C.
Say there is a function A defined in A.c as
void A(int x, int y){
//Do stuff
}
Now there is also a separate file B.c:
extern "C"{
void A(int x, int y, int z);
}
void B(){
A(1, 2, 3);
}
A is initially declared to have only 2 arguments yet when declared in B.c it has an extra one, and it is called with that third in B().
I know it is possible to make this situation occur, for example when linking with fortran subroutines, OR when dynamically linking.
I imagine it is unsafe to pass an extra argument to a function, can anyone explain what is happening in memory when a function is called and arguments are passed to it? And, therefore, how safe it is to pass this "extra" argument that is neither used nor wanted.
Is it possible that the extra argument overwrites a space in memory that is used within the function? Or does the function call to A allocate space in memory for the arguments then tell A where the beginning of the argument memory block is, A reads out the first two arguments and ignores the last, making it completely safe?
Any information on the function would be greatly enlightening, thanks.
Linkage is implementation-defined, so there is no way to say definitely.
That said, other features of C (notably vardic parameters) force an implementation that would usually allow it.
For example, I don't know of any implementation that would fail if you wrote:
printf("%d", 1, 2);
It would, however, merely print "1".
Many people here are bringing up cdecl, pascal and __stdcall calling conventions. However, none of those are part of the Standard and are all features of certain implementions,. which bring us back to my first sentence.
It depends on the calling convention used. With cdecl, the caller pushes arguments onto the stack in right-to-left order, and then the callee accesses them by offsetting the stack pointer. Calling too many arguments won't break anything in this case.
If, however, you have a calling convention that is left-to-right, then things would break.
With the cdecl calling convention, the caller is responsible for cleaning up the stack, so this would be safe. To contrast, the pascal calling convention makes the callee responsible for cleanup, and so this would be dangerous.
In C this is a violation of constraints, therefore it results in undefined behaviour.
"If the expression that denotes the called function has a type that includes a prototype, the number of arguments shall agree with the number of parameters." (C99, ยง6.5.2.2)
That said, in practice it will depend mostly on the underlying calling conventions.
At least in C and C++ it won't do any harm. Arguments are pushed right to left and a callee is responsible for the stack cleanup.
However, the compiler won't let you do this unless you are using variadic parameters or cast a function type. For example:
#include <stdio.h>
static void foo (int a, int b, int c, int d, int e, int f, int g)
{
printf ("A:%d B:%d C:%d D:%d E:%d F:%d G:%d \n",
a, b, c, d, e, f, g);
}
int main ()
{
typedef void (*bad_foo) (int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int);
foo (1, 2, 3, 4, 5, 6, 7);
bad_foo f = (bad_foo) (&foo);
f (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17);
}
If you look at assembly code, all parameters are pushed into register but extra onces are just getting ignored.
Such code violates the One Definition Rule (well, C's equivalent of it anyway...) Whether it works or not is entirely platform specific.
Specifically on x86, if the function was declared __cdecl, then it would work, because the caller cleans the stack, but if it was __stdcall (as most Win32 functions are), the callee cleans the stack, and would clean it wrong in that case (because it got too many parameters). Therefore it would depend on that external function's calling convention used.
I can't understand why you'd ever want to do this though.
If I get it right, this might lead to your program to execude random code from memory. When a function is called, a few values, including the return address (where the program will jump back to when the function is finished) are pushed to the stack. After that, the function arguments (x, y, z) are pushed to the stack and the program jumps to the entry point of the function. The function will then pop the arguments (x, y) from the stack, do something, then pop the return address from the stack (z in this case, which is wrong) and jump back to it.
Here's a nice description of the stack details: http://www.tenouk.com/Bufferoverflowc/Bufferoverflow2a.html

Resources