Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function call with more parameters than expected

I was reviewing some code and I came across something similar to this.

File foo.c:

int bar(int param1)
{
    return param1*param1;
}

File main.c:

#include <stdio.h>

int bar(int param1, int unusedParam);

int main (void)
{
    int param = 2, unused = 0;
    printf("%d\n", bar(param, unused));
}

Running gcc main.c foo.c -Wall --pedantic -O0 it compiles, links and works properly without throwing a single warning in the process. Why is that?

Thanks!

like image 459
Kai Avatar asked Nov 22 '18 15:11

Kai


People also ask

What happens if you pass an extra parameter to a method in JavaScript?

JavaScript is extremely broad-minded about the number of arguments you pass to a function. If you pass too many, the extra ones are ignored. If you pass too few, the missing parameters get assigned the value undefined .

What will happen if you call any function with more or less arguments than required?

If you manage to write code that calls a function with an incorrect number of arguments and get it past the compiler, the behavior is undefined. It might appear to "work", but it could blow up in your face when, for example, you compile it with a different compiler, or with the same compiler and different options.

How do you pass multiple parameters to a function?

Note that when you are working with multiple parameters, the function call must have the same number of arguments as there are parameters, and the arguments must be passed in the same order.

What will happen if you call any function with more or less arguments than required in Python?

Passing many arguments will have no effect to the function, as long as the parameters are filled in.


1 Answers

This really depends on the calling convention and architecture. For example, with cdecl on x86, where arguments are pushed right to left and the caller restores the stack, the presence of an additional parameter is transparent to the function bar:

push    11
push    10
call    _bar
add     esp, 8

bar will only "see" the 10, and will function as expected with that parameter, returning 100. The stack is restored afterwards so there is no misalignment in main either; if you had just passed the 10 it would have added 4 to esp instead.

This is also true of the x64 calling conventions for both MSVC on Windows and the System V ABI, where the first few1 integral arguments are passed in registers; the second argument will be populated in its designated register by the call in main, but not even looked at by bar.

If, however, you tried to use an alternate calling convention where the callee is responsible for cleaning up the stack, you would run into trouble either at the build stage or (worse) at runtime. stdcall, for example, decorates the function name with the number of bytes used by the argument list, so I'm not even able to link the final executable by changing bar to use stdcall instead:

error LNK2019: unresolved external symbol _bar@8 referenced in function _main

This is because bar now has the signature _bar@4 in its object file, as it should.

This gets interesting if you use the obsolete calling convention pascal, where parameters are pushed left-to-right:

push 10
push 11
call _bar

Now bar returns 121, not 100, like you expected. That is, if the function successfully returns, which it won't, since the callee was supposed to clean up the stack but failed due to the extra parameter, trashing the return address.

1: 4 for MSVC on Windows; 6 on System V ABI

like image 172
Govind Parmar Avatar answered Sep 28 '22 14:09

Govind Parmar