views:

146

answers:

2

I'm using the ffcall (specifically the avcall package of ffcall) library to dynamically push parameters to variadic functions. i.e. we have

int blah (char *a, int b, double c, ...);

and we want to call this function with values taken from the user. To do this, we create an avcall version of the function:

int av_blah (char *a, int b, double c, char **values, int num_of_values)
{
    av_alist alist;
    int i, ret;
    av_start_int (alist, &blah, &ret); //let it know which function
    av_ptr (alist, char*, a); // push values onto stack starting from left
    av_int (alist, b);
    av_double (alist, c);
    for (i=0;i<num_of_values;i++)
    {
        // do what you want with values and add to stack
    }
    av_call (alist);  //call blah()

    return (ret);
}

Now, the function I am using avcall with is:

int read_row (struct some_struct *a, struct another_struct *b[], ...);

And it is used like so:

struct some_struct a;
struct another_struct **b = fill_with_stuff ();

char name[64];
int num;
while (read_row (&a, b, name, &num)==0)
{
    printf ("name=%s, num=%d\n", name, num);
}

But I want to use avcall to capture a certain amount of values from this function and I do not know this information in advance. So I thought I'd just create an array of void pointers and then malloc space according to the type:

char printf_string[64]=""; //need to build printf string inside av_read_row()
void **vals = Calloc (n+1, sizeof (void*)); //wrapper
while (av_read_row (&a, b, vals, n, printf_string) == 0)
{
    // vals should now hold the values i want
    av_printf (printf_string, vals, n);  //get nonsense output from this
    // free the mallocs which each vals[i] is pointing to
    void **ptrs = vals;
    while (*ptrs) {
       free (*ptrs);  //seg faults on first free() ?
       *ptrs=NULL;
       ptrs++;
    }
    //reset printf_string
    printf_string[0]='\0';
    printf ("\n");
}

And av_read_row is just:

int av_read_row (struct some_struct *a, struct another_struct *b[], void **vals, int num_of_args, char *printf_string)
{
    int i, ret;
    av_alist alist;

    av_start_int (alist, &read_row, &ret);
    av_ptr (alist, struct some_struct *, a);
    av_ptr (alist, struct another_struct **, b);

    for (i=0;i<num_of_args;i++)
    {
        switch (type)  //for simplicity
        {
          case INT: {
              vals[i] = Malloc (sizeof (int));
              av_ptr (alist, int*, vals[i]);
              strcat (printf_string, "%d, ");
              break;
          }
          case FLOAT: {
               //Same thing
          }
          //etc
        }
    }

    av_call (alist);
    return (ret);
}

I have been experiencing a bunch of memory corruption errors and it seems as though it doesn't like what I'm doing here. I can't spot anything wrong with the way I did this, can you? At the moment, it doesn't like it when I try to free the mallocs inside the av_read_row while loop. Can anyone see what I'm doing wrong, if anything?

Thanks

A: 

I did not go into the finer details of the code, but can say the following

  1. Using stack for passing large number of arguments is not advisable, as stack is limited. I am not sure if av_stuff really checks the stack limit.
  2. Isn't there a simpler method to do the same operation instead of pushing the variable to stack?
Alphaneo
+1  A: 

The only information I can easily find about avcall is from 2001, but it does suggest POSIX. If you can run your stuff on Linux, valgrind will find your memory faults in a jiffy. It's a terrific tool.

Norman Ramsey