Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

variadic an idea #29

Open
Munken opened this issue Jan 31, 2022 · 5 comments
Open

variadic an idea #29

Munken opened this issue Jan 31, 2022 · 5 comments

Comments

@Munken
Copy link

Munken commented Jan 31, 2022

Hi

I've been toying around with how to get variadic functions working.
It uses the gcc builtin in functions (https://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Constructing-Calls.html) to forward the call.

A hacked together example for ioctl can be seen here: https://gist.github.com/Munken/df6828e275e128a8174c6e5851776a4d

This could be combined with something like:

int ioctl_(int fd, unsigned long req, int a) {
  return a;
}

MOCK(ioctl)->capture_variadic("%d");
MOCK(ioctl)->mock_implementation(ioctl_);

ioctl(1, 8, 123);

ASSERT_EQ((int) MOCK(ioctl)->get_vararg(0), 123);

The __wrap_xxx would then use va_start, va_arg and va_end to capture the varargs into an array.

@vberlier
Copy link
Owner

vberlier commented Feb 3, 2022

I wasn't aware of these builtins, looks like perfect forwarding is possible after all. However I'm still not sure how you would use va_start, va_arg and va_end to gather the variadic arguments in an array for inspection. It's up to each function to decide how many arguments should be provided, we can't figure out the number of arguments from the va_* macros alone.

@vberlier
Copy link
Owner

vberlier commented Feb 3, 2022

Just published a new version that incorporates the GCC builtins to forward the variadic arguments instead of ignoring them. This allows you to provide variadic stubs. For now the variadic arguments are not recorded in last_call like the fixed arguments.

@Munken
Copy link
Author

Munken commented Feb 3, 2022

Nice additions!

I've outlined a rough sketch of how one could gather the variable arguments.
It requires a printf-like format string to specify the type of arguments to capture.
The arguments are then collected into a uint64_t array.
The user must then perform a cast when performing ASSERT_EQ.
main...Munken:varg-capture

This restricts the captured types to <= 64 bits. If this is too narrow then one could use a dummy struct instead.
Perhaps

struct narmock_vargs_capture_type {
  uint64_t a,b,c,d;
};

@Munken
Copy link
Author

Munken commented Feb 3, 2022

Just revised the last idea a bit.

Instead of using uint64_t and requiring a cast, I'm now using a union instead.

@vberlier
Copy link
Owner

vberlier commented Feb 5, 2022

The idea of using a printf-like format string is interesting. Instead of parsing formatting syntax manually maybe it's worth considering just forwarding the arguments to vsnprintf() to simply capture the arguments as a string in a static buffer. It would be pretty easy to implement but you would only be able to make assertions about the resulting string and not the individual arguments.

Of course your proposal looks pretty good but I just need to experiment a bit with it. I'm also thinking about something more structured:

int a;
int b;
int c;

MOCK(sum_variadic)
    ->mock_implementation(fake_sum_variadic1)
    ->capture_variadic()
        ->arg_int(&a)
        ->arg_int(&b)
        ->arg_int(&c);

sum_variadic(3, &value, 1, 2, 3);

ASSERT_EQ(a, 1);
ASSERT_EQ(b, 2);
ASSERT_EQ(c, 3);

I also wonder if instead of setting up a static variadic capture you could have something like capture_variadic_from_count_argument(0) which would tell narmock the index of the fixed argument corresponding to the number of variadic arguments. Similarly something like capture_variadic_from_format_argument(0) which would do the same but the specified argument index would correspond to a format string argument from which narmock would dynamically deduce the number and types of variadic arguments.

I'm gonna try to play with some of these concepts later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants