Often I see a function declared like this:
void Feeder(char *buff, ...)
what does "..." mean?
Often I see a function declared like this:
void Feeder(char *buff, ...)
what does "..." mean?
It allows a variable number of arguments of unspecified type (like printf
does).
You have to access the arguments with the va_start
, va_arg
and va_end
functions.
See http://publications.gbdirect.co.uk/c_book/chapter9/stdarg.html or Where in the C standard variadic functions are described? for more information
Variadic functions are functions which may take a variable number of arguments and are declared with an ellipsis in place of the last parameter. An example of such a function is
printf
.A typical declaration is
int check(int a, double b, ...);
Variadic functions must have at least one named parameter, so, for instance,
char *wrong(...);
is not allowed in C.
The three dots '...' are called an ellipsis. Using them in a function makes that function a variadic function. To use them in a function declaration means that the function will accept an arbitrary number of parameters after the ones already defined.
For example:
Feeder("abc");
Feeder("abc", "def");
are all valid function calls, however the following wouldn't be:
Feeder();
variadic function (multiple parameters)
#include <stdarg.h>
double average(int count, ...)
{
va_list ap;
int j;
double tot = 0;
va_start(ap, count); //Requires the last fixed parameter (to get the address)
for(j=0; j<count; j++)
tot+=va_arg(ap, double); //Requires the type to cast to. Increments ap to the next argument.
va_end(ap);
return tot/count;
}
Functions with ...
as last parameter are called Variadic functions (Cppreference. 2016). This ...
is used to allow variable length parameters with unspecified types.
We can use variadic functions when we are not sure about the number of parameters or their types.
Example of variadic function: Let us assume we need a sum function that will return the summation of variable number of arguments. We can use a variadic function here.
#include <stdio.h>
#include <stdarg.h>
int sum(int count, ...)
{
int total, i, temp;
total = 0;
va_list args;
va_start(args, count);
for(i=0; i<count; i++)
{
temp = va_arg(args, int);
total += temp;
}
va_end(args);
return total;
}
int main()
{
int numbers[3] = {5, 10, 15};
// Get summation of all variables of the array
int sum_of_numbers = sum(3, numbers[0], numbers[1], numbers[2]);
printf("Sum of the array %d\n", sum_of_numbers);
// Get summation of last two numbers of the array
int partial_sum_of_numbers = sum(2, numbers[1], numbers[2]);
printf("Sum of the last two numbers of the array %d\n", partial_sum_of_numbers);
return 0;
}
Output:
Practice problem: A simple problem to practice variadic function can be found in hackerrank practice problem here
Reference:
...
= three dot = three point = called: ellipsis
...
para is called: Variadic functionint validFunctionWithNamedParameterThenEllipsis(int a, double b, ...);
int invalidFunctionOnlyEllipsis(...);
popular case:
int printf(const char *format, ...)
call:
printf("year=%d, name=%s", 2021, "crifan");
->
format
== "year=%d, name=%s"
...
== 2021, "crifan"
2021
"crifan"
va_list
, with va_start
, va_arg
, va_end
#include <stdarg.h>
void va_start(va_list ap, last_arg);
type va_arg(va_list ap, type);
void va_end(va list ap);
#include <stdarg.h>
#include <stdio.h>
double average(int count, ...) {
va_list ap;
int j;
double sum = 0;
va_start(ap, count); /* Requires the last fixed parameter (to get the address) */
for (j = 0; j < count; j++) {
sum += va_arg(ap, int); /* Increments ap to the next argument. */
}
va_end(ap);
return sum / count;
}
int main(int argc, char const *argv[]) {
printf("%f\n", average(3, 1, 2, 3));
return 0;
}
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
int maxof(int, ...) ;
void f(void);
main(){
f();
exit(EXIT_SUCCESS);
}
int maxof(int n_args, ...){
register int i;
int max, a;
va_list ap;
va_start(ap, n_args);
max = va_arg(ap, int);
for(i = 2; i <= n_args; i++) {
if((a = va_arg(ap, int)) > max)
max = a;
}
va_end(ap);
return max;
}
void f(void) {
int i = 5;
int j[256];
j[42] = 24;
printf("%d\n",maxof(3, i, j[42], 0));
}
#include <stdarg.h>
#define MAXARGS 31
/*
* execl is called by
* execl(file, arg1, arg2, ..., (char *)(0));
*/
int execl(const char *file, const char *args, ...)
{
va_list ap;
char *array[MAXARGS +1];
int argno = 0;
va_start(ap, args);
while (args != 0 && argno < MAXARGS)
{
array[argno++] = args;
args = va_arg(ap, const char *);
}
array[argno] = (char *) 0;
va_end(ap);
return execv(file, array);
}
/*==============================================================================
Hook: syscall()
==============================================================================*/
int syscall(int, ...);
// normally max number of syscall parameter is not exceed 8
// refer: https://opensource.apple.com/source/xnu/xnu-4570.1.46/bsd/kern/syscalls.master
int MaxSupportArgNum_syscall = 16;
%hookf(int, syscall, int number, ...){
os_log(OS_LOG_DEFAULT, "hook_syscall_stat_stat64: number=%d", number);
// Setting up some variables to get all the parameters from syscall
void *paraPtr, *paraList[MaxSupportArgNum_syscall];
// char *paraPtr, *paraList[MaxSupportArgNum_syscall];
va_list argList;
int curParaNum = 0;
va_start(argList, number);
while ((paraPtr = (void *) va_arg(argList, void *))) {
// while ((paraPtr = (char *) va_arg(argList, char *))) {
paraList[curParaNum] = paraPtr;
curParaNum += 1;
os_log(OS_LOG_DEFAULT, "hook_syscall_stat_stat64: [%d] paraPtr=%p", curParaNum, paraPtr);
}
va_end(argList);
// os_log(OS_LOG_DEFAULT, "hook_syscall_stat_stat64: argList=%{public}s", argList);
os_log(OS_LOG_DEFAULT, "hook_syscall_stat_stat64: curParaNum=%d", curParaNum);
bool isStat = (SYS_stat == number);
bool isStat64 = (SYS_stat64 == number);
if (isStat || isStat64){
char* curPath = (char *)paraList[0];
os_log(OS_LOG_DEFAULT, "hook_syscall_stat_stat64: isStat=%{bool}d, isStat64=%{BOOL}d, curPath=%{public}s", isStat, isStat64, curPath);
bool isJbPath = isJailbreakPath(curPath);
if (isJbPath){
os_log(OS_LOG_DEFAULT, "hook_syscall_stat_stat64: IS jailbreak path: %{public}s", curPath);
return OPEN_FAILED;
} else {
os_log(OS_LOG_DEFAULT, "hook_syscall_stat_stat64: NOT jailbreak path: %{public}s", curPath);
}
}
// return %orig;
// return %orig(number, ...);
// int retValue = %orig();
// int retValue = callOriginSyscall(number, curParaNum, paraList);
//// int retValue = callOriginSyscall(number, curParaNum, (void *)paraList);
// os_log(OS_LOG_DEFAULT, "hook_syscall_stat_file: retValue=%d", retValue);
// return retValue;
int paraNum = curParaNum;
int syscallRetValue = -1;
if (0 == paraNum){
syscallRetValue = %orig(number);
} else if (1 == paraNum){
void* para1 = paraList[0];
os_log(OS_LOG_DEFAULT, "hook_syscall_orig: para1=%p", para1);
syscallRetValue = %orig(number, para1);
} else if (2 == paraNum){
void* para1 = paraList[0];
void* para2 = paraList[1];
os_log(OS_LOG_DEFAULT, "hook_syscall_orig: para1=%p,para2=%p", para1, para2);
syscallRetValue = %orig(number, para1, para2);
} else if (3 == paraNum){
void* para1 = paraList[0];
void* para2 = paraList[1];
void* para3 = paraList[2];
os_log(OS_LOG_DEFAULT, "hook_syscall_orig: para1=%p,para2=%p,para3=%p", para1, para2, para3);
syscallRetValue = %orig(number, para1, para2, para3);
} else if (4 == paraNum){
void* para1 = paraList[0];
void* para2 = paraList[1];
void* para3 = paraList[2];
void* para4 = paraList[3];
os_log(OS_LOG_DEFAULT, "hook_syscall_orig: para1=%p,para2=%p,para3=%p,para4=%p", para1, para2, para3, para4);
syscallRetValue = %orig(number, para1, para2, para3, para4);
} else if (5 == paraNum){
void* para1 = paraList[0];
void* para2 = paraList[1];
void* para3 = paraList[2];
void* para4 = paraList[3];
void* para5 = paraList[4];
os_log(OS_LOG_DEFAULT, "hook_syscall_orig: para1=%p,para2=%p,para3=%p,para4=%p,para5=%p", para1, para2, para3, para4, para5);
syscallRetValue = %orig(number, para1, para2, para3, para4, para5);
} else if (6 == paraNum){
void* para1 = paraList[0];
void* para2 = paraList[1];
void* para3 = paraList[2];
void* para4 = paraList[3];
void* para5 = paraList[4];
void* para6 = paraList[5];
os_log(OS_LOG_DEFAULT, "hook_syscall_orig: para1=%p,para2=%p,para3=%p,para4=%p,para5=%p,para6=%p", para1, para2, para3, para4, para5, para6);
syscallRetValue = %orig(number, para1, para2, para3, para4, para5, para6);
} else if (7 == paraNum){
void* para1 = paraList[0];
void* para2 = paraList[1];
void* para3 = paraList[2];
void* para4 = paraList[3];
void* para5 = paraList[4];
void* para6 = paraList[5];
void* para7 = paraList[6];
os_log(OS_LOG_DEFAULT, "hook_syscall_orig: para1=%p,para2=%p,para3=%p,para4=%p,para5=%p,para6=%p,para7=%p", para1, para2, para3, para4, para5, para6, para7);
syscallRetValue = %orig(number, para1, para2, para3, para4, para5, para6, para7);
} else if (8 == paraNum){
void* para1 = paraList[0];
void* para2 = paraList[1];
void* para3 = paraList[2];
void* para4 = paraList[3];
void* para5 = paraList[4];
void* para6 = paraList[5];
void* para7 = paraList[6];
void* para8 = paraList[7];
os_log(OS_LOG_DEFAULT, "hook_syscall_orig: para1=%p,para2=%p,para3=%p,para4=%p,para5=%p,para6=%p,para7=%p,para8=%p", para1, para2, para3, para4, para5, para6, para7, para8);
syscallRetValue = %orig(number, para1, para2, para3, para4, para5, para6, para7, para8);
} else if (9 == paraNum){
void* para1 = paraList[0];
void* para2 = paraList[1];
void* para3 = paraList[2];
void* para4 = paraList[3];
void* para5 = paraList[4];
void* para6 = paraList[5];
void* para7 = paraList[6];
void* para8 = paraList[7];
void* para9 = paraList[8];
os_log(OS_LOG_DEFAULT, "hook_syscall_orig: para1=%p,para2=%p,para3=%p,para4=%p,para5=%p,para6=%p,para7=%p,para8=%p,para9=%p", para1, para2, para3, para4, para5, para6, para7, para8, para9);
syscallRetValue = %orig(number, para1, para2, para3, para4, para5, para6, para7, para8, para9);
}
os_log(OS_LOG_DEFAULT, "hook_syscall_orig: syscallRetValue=%d", syscallRetValue);
return syscallRetValue;
}
when call va_start
, last_arg
is the last named parameter, NOT the first one
for: int open(const char *path, int oflag, ...);
va_start(argList, oflag);
va_start(argList, path);
Second argument to 'va_start' is not the last named parameter
type va_arg(va_list ap, type);
for pass type
, there is a special case:
when pass in :
but return always is:
-> so when code:
curPara = (mode_t) va_arg(argList, mode_t);
according:
#include <sys/stat.h>
#include <sys/types.h>
-> mode_t
==unsigned short
equivalent to:
curPara = (mode_t) va_arg(argList, unsigned short);
so compiler warning:
Second argument to 'va_arg' is of promotable type 'mode_t' (aka 'unsigned short'); this va_arg has undefined behavior because arguments will be promoted to 'int'
change to:
curPara = (mode_t) va_arg(argList, unsigned int);
could avoid warning.
© 2022 - 2024 — McMap. All rights reserved.