mailing list of musl libc
 help / color / mirror / code / Atom feed
* cluts weekly reports
@ 2011-07-18 17:10 Luka M.
  2011-07-25 23:04 ` Luka M.
  0 siblings, 1 reply; 16+ messages in thread
From: Luka M. @ 2011-07-18 17:10 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 568 bytes --]

Done:
* A bug or two in cluts corrected
* Numeric tests polished
* User-provided buffer tests written
* Threaded setuid test written (but still being corrected)

Priorities:
* Get setuid to finally work
* Rewrite memory allocation tests
* Start rewriting string tests

P.S. I've just chaged towns and it took me a whole day to do that, but I've
gone over setuid.c and found a bug or two on the way, and I've also had a
chance to sketch out a new alloc.c. I'll be working on that today and
tomorrow, and when there's something to show, I'll put it in the daily
report.

[-- Attachment #2: Type: text/html, Size: 636 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: cluts weekly reports
  2011-07-18 17:10 cluts weekly reports Luka M.
@ 2011-07-25 23:04 ` Luka M.
  2011-08-03  0:56   ` Solar Designer
  0 siblings, 1 reply; 16+ messages in thread
From: Luka M. @ 2011-07-25 23:04 UTC (permalink / raw)
  To: musl

Hey guys. Due to half-buttedness of the work I've done last week, I
haven't posted much about the progress here, but here it is now:

Done:
a) Finally managed to start working on this PC (virtual machine) :-/
b) Fixed some setuid.c problems, but drawing a blank on the hang
c) Rewrote alloc.c, which also needs some fixing (see priorities, 2)
d) Started working on (functions with temp strings) aka temp.c
e) Started working on a code generator in python, first to be used o
generate (parts of) temp.c, and later hopefully string.c

Priorities:
1) Finish what is started (d, e)
2) Fix that which needs fixing (a, b). At the end of the week - needs
to be done on a real PC
3) Move on to new test collections (I'm thinking task nr. 0 perhaps,
something useful anyway)


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: cluts weekly reports
  2011-07-25 23:04 ` Luka M.
@ 2011-08-03  0:56   ` Solar Designer
  2011-08-03  1:21     ` Rich Felker
  0 siblings, 1 reply; 16+ messages in thread
From: Solar Designer @ 2011-08-03  0:56 UTC (permalink / raw)
  To: musl

Luka -

On Tue, Jul 26, 2011 at 01:04:07AM +0200, Luka M. wrote:
> e) Started working on a code generator in python, first to be used o
> generate (parts of) temp.c, and later hopefully string.c

To me, the dependency of cluts development on Python is a drawback.
Wouldn't cpp macros be sufficient?  You can see some use of cpp macros
in Rich's libc-testsuite.  I like this approach better than using an
external preprocessor not native to C.

http://git.etalabs.net/cgi-bin/gitweb.cgi?p=libc-testsuite

Alexander


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: cluts weekly reports
  2011-08-03  0:56   ` Solar Designer
@ 2011-08-03  1:21     ` Rich Felker
  2011-08-03 13:15       ` Luka Marčetić
  0 siblings, 1 reply; 16+ messages in thread
From: Rich Felker @ 2011-08-03  1:21 UTC (permalink / raw)
  To: musl

On Wed, Aug 03, 2011 at 04:56:19AM +0400, Solar Designer wrote:
> Luka -
> 
> On Tue, Jul 26, 2011 at 01:04:07AM +0200, Luka M. wrote:
> > e) Started working on a code generator in python, first to be used o
> > generate (parts of) temp.c, and later hopefully string.c
> 
> To me, the dependency of cluts development on Python is a drawback.
> Wouldn't cpp macros be sufficient?  You can see some use of cpp macros
> in Rich's libc-testsuite.  I like this approach better than using an
> external preprocessor not native to C.

I tend to agree with this.

Rich


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: cluts weekly reports
  2011-08-03  1:21     ` Rich Felker
@ 2011-08-03 13:15       ` Luka Marčetić
  2011-08-03 13:31         ` Rich Felker
  0 siblings, 1 reply; 16+ messages in thread
From: Luka Marčetić @ 2011-08-03 13:15 UTC (permalink / raw)
  To: musl

On 08/03/2011 03:21 AM, Rich Felker wrote:
> On Wed, Aug 03, 2011 at 04:56:19AM +0400, Solar Designer wrote:
>> Luka -
>>
>> On Tue, Jul 26, 2011 at 01:04:07AM +0200, Luka M. wrote:
>>> e) Started working on a code generator in python, first to be used o
>>> generate (parts of) temp.c, and later hopefully string.c
>> To me, the dependency of cluts development on Python is a drawback.
>> Wouldn't cpp macros be sufficient?  You can see some use of cpp macros
>> in Rich's libc-testsuite.  I like this approach better than using an
>> external preprocessor not native to C.
> I tend to agree with this.
>
> Rich

Well it's a bit too late to stop now, but I don't think fear is 
warranted: Cluts doesn't depend on python because a code generator is 
written in it. The generated code is regular C code, which could be 
written by hand if one wanted to. A code generator is not a 
preprocessor, it is just a handy tool to automate the process of writing 
code by hand. My generator takes in a .json file, and out generates most 
of the syntactic sugar, loops etc needed for the test collection to 
compile and run. That is to say, the generator is used to write the 
tests, not to run them.
Luka



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: cluts weekly reports
  2011-08-03 13:15       ` Luka Marčetić
@ 2011-08-03 13:31         ` Rich Felker
  2011-08-03 14:51           ` Solar Designer
  2011-08-03 17:08           ` Luka Marčetić
  0 siblings, 2 replies; 16+ messages in thread
From: Rich Felker @ 2011-08-03 13:31 UTC (permalink / raw)
  To: musl

On Wed, Aug 03, 2011 at 03:15:15PM +0200, Luka Marčetić wrote:
> Well it's a bit too late to stop now, but I don't think fear is
> warranted: Cluts doesn't depend on python because a code generator
> is written in it. The generated code is regular C code, which could
> be written by hand if one wanted to. A code generator is not a
> preprocessor, it is just a handy tool to automate the process of
> writing code by hand. My generator takes in a .json file, and out
> generates most of the syntactic sugar, loops etc needed for the test
> collection to compile and run. That is to say, the generator is used
> to write the tests, not to run them.

Well the question is whether the intended usage, for someone adding
tests, is to add them by hand or by going back to the json "source"
file, adding them there, and rebuilding using the Python tool. In this
case cluts doesn't depend on Python to *run* the tests, but it does
depend on it to modify or update the tests. I'm still confused why
this can't be done in plain C, with the test parameters in C
structures that you loop over, much like some of the existing tests
(e.g. numeric).

Rich


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: cluts weekly reports
  2011-08-03 13:31         ` Rich Felker
@ 2011-08-03 14:51           ` Solar Designer
  2011-08-03 17:08           ` Luka Marčetić
  1 sibling, 0 replies; 16+ messages in thread
From: Solar Designer @ 2011-08-03 14:51 UTC (permalink / raw)
  To: musl

Luka, Rich -

On Wed, Aug 03, 2011 at 03:15:15PM +0200, Luka Mar??eti?? wrote:
> Well it's a bit too late to stop now, but I don't think fear is
> warranted: Cluts doesn't depend on python because a code generator
> is written in it. The generated code is regular C code, which could
> be written by hand if one wanted to. A code generator is not a
> preprocessor, it is just a handy tool to automate the process of
> writing code by hand. My generator takes in a .json file, and out
> generates most of the syntactic sugar, loops etc needed for the test
> collection to compile and run. That is to say, the generator is used
> to write the tests, not to run them.

The syntactic sugar could either be produced with cpp macros (see Rich's
libc-testsuite) or avoided at all (see the str.c sample I posted in
June, where the arg_next() approach avoids having to use nested loops
at C source level while achieving the same effect as nested loops would).
Or you could use a reasonable mix of these two.

On Wed, Aug 03, 2011 at 09:31:55AM -0400, Rich Felker wrote:
> Well the question is whether the intended usage, for someone adding
> tests, is to add them by hand or by going back to the json "source"
> file, adding them there, and rebuilding using the Python tool. In this
> case cluts doesn't depend on Python to *run* the tests, but it does
> depend on it to modify or update the tests. I'm still confused why
> this can't be done in plain C, with the test parameters in C
> structures that you loop over, much like some of the existing tests
> (e.g. numeric).

Right.

Anyway, now that Luka went with the Python approach already, I think it
makes sense for Rich to take a look a this stuff and discuss it with
Luka before deciding on what to do next.  I'll have to stay out of this,
focusing on other projects.

Thanks,

Alexander


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: cluts weekly reports
  2011-08-03 13:31         ` Rich Felker
  2011-08-03 14:51           ` Solar Designer
@ 2011-08-03 17:08           ` Luka Marčetić
  2011-08-03 17:22             ` Rich Felker
  1 sibling, 1 reply; 16+ messages in thread
From: Luka Marčetić @ 2011-08-03 17:08 UTC (permalink / raw)
  To: musl

On 08/03/2011 03:31 PM, Rich Felker wrote:
> On Wed, Aug 03, 2011 at 03:15:15PM +0200, Luka Marčetić wrote:
> Well the question is whether the intended usage, for someone adding
> tests, is to add them by hand or by going back to the json "source"
> file, adding them there, and rebuilding using the Python tool. In this
> case cluts doesn't depend on Python to *run* the tests, but it does
> depend on it to modify or update the tests.

It doesn't, seeing as they can be written by hand. There's nothing 
stopping one from modifying C directly. The only problem here is the 
discrepancy between json and C, but that doesn't imply python 
dependency. In fact it is assumed that C code would need to be modified 
sometimes. In such cases, one can generate a single new test with the 
generator, and paste the code into the C source file.

>   I'm still confused why
> this can't be done in plain C, with the test parameters in C
> structures that you loop over, much like some of the existing tests
> (e.g. numeric).

It's just a lot of work. The biggest problem C has when applied in 
writing unit tests is its inability to use function pointers with 
arbitrary number of arguments, and the fact that there's no (dynamic?) 
type casting - eg there's no way to pass varying type arguments to say 
printf with a correct fmt; once a float, once an int. Those two make for 
a load of syntax that like anything but sugar. That's what I'm trying to 
generate, instead of having to type it all.

Luka


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: cluts weekly reports
  2011-08-03 17:08           ` Luka Marčetić
@ 2011-08-03 17:22             ` Rich Felker
  2011-08-03 18:03               ` Luka Marčetić
  0 siblings, 1 reply; 16+ messages in thread
From: Rich Felker @ 2011-08-03 17:22 UTC (permalink / raw)
  To: musl

On Wed, Aug 03, 2011 at 07:08:34PM +0200, Luka Marčetić wrote:
> >  I'm still confused why
> >this can't be done in plain C, with the test parameters in C
> >structures that you loop over, much like some of the existing tests
> >(e.g. numeric).
> 
> It's just a lot of work. The biggest problem C has when applied in
> writing unit tests is its inability to use function pointers with
> arbitrary number of arguments, and the fact that there's no
> (dynamic?) type casting - eg there's no way to pass varying type
> arguments to say printf with a correct fmt; once a float, once an
> int. Those two make for a load of syntax that like anything but
> sugar. That's what I'm trying to generate, instead of having to type
> it all.

Could you please give some concrete examples of what trouble you're
running into? I think you're looking for a very complex solution to a
very simple problem, but I can't know until you give me a better idea
of the specific problem. There are easy ways to handle this type of
thing, with solutions ranging from a macro that concatenates the right
type of format specifier into the message string to rolling your own
rudimentary message formatting function that takes a void pointer or
union type for the data to print.

As for function pointers and the need for different numbers and types
of arguments, you can either pass a pointer to a structure that
contains all of the argument data (thereby always having the same
function signature taking a single void * argument) or have a separate
type field and cast the function pointer to the right function type
and make the call with the right parameters based on the stored type.

Rich


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: cluts weekly reports
  2011-08-03 17:22             ` Rich Felker
@ 2011-08-03 18:03               ` Luka Marčetić
  2011-08-03 18:19                 ` Rich Felker
  0 siblings, 1 reply; 16+ messages in thread
From: Luka Marčetić @ 2011-08-03 18:03 UTC (permalink / raw)
  To: musl

On 08/03/2011 07:22 PM, Rich Felker wrote:
>>>   I'm still confused why
>>> this can't be done in plain C, with the test parameters in C
>>> structures that you loop over, much like some of the existing tests
>>> (e.g. numeric).
> Could you please give some concrete examples of what trouble you're
> running into? I think you're looking for a very complex solution to a
> very simple problem, but I can't know until you give me a better idea
> of the specific problem. There are easy ways to handle this type of
> thing, with solutions ranging from a macro that concatenates the right
> type of format specifier into the message string to rolling your own
> rudimentary message formatting function that takes a void pointer or
> union type for the data to print.

Ideally what I'd want is:

     fp(args)

where fp is a function pointer to functions with different prototypes, 
and args are a number of arguments, each of an arbitrary type. Or at least:

     if (nr_args == 1)
         fp (*(type[0] *) arg[0]);
     else if (nr_args == 2)
         fp (*(type[0] *) arg[0], *(type[1] *) arg[1]);

What I'm doing instead essentially is:

     if (fp == specific_function)
         specific_function(*(int*)arg[0], *(char **)arg[1]);
     else if (fp == another_function)
         another_function(*(size_t *)arg[0]);

I'm tired of doing that. Every time I get around to that part, not only 
do I need to consider pro's and con's of using function pointers vs 
enums vs switch-cases, but also, my first instinct is always: How do I 
make a generic function caller. There's no such thing in C, so I compensate.

> As for function pointers and the need for different numbers and types
> of arguments, you can either pass a pointer to a structure that
> contains all of the argument data (thereby always having the same
> function signature taking a single void * argument) or have a separate
> type field and cast the function pointer to the right function type
> and make the call with the right parameters based on the stored type.

That just dislocates above, and puts it into the function to be called 
with the arg pointer (and, don't forget, the function identifier). I can 
go to IRC if you want to see what the generator output is/should be, and 
based on what input.
Luka


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: cluts weekly reports
  2011-08-03 18:03               ` Luka Marčetić
@ 2011-08-03 18:19                 ` Rich Felker
  2011-08-03 18:38                   ` Luka Marčetić
  2011-08-03 21:59                   ` Luka Marčetić
  0 siblings, 2 replies; 16+ messages in thread
From: Rich Felker @ 2011-08-03 18:19 UTC (permalink / raw)
  To: musl

On Wed, Aug 03, 2011 at 08:03:06PM +0200, Luka Marčetić wrote:
> Ideally what I'd want is:
> 
>     fp(args)
> 
> where fp is a function pointer to functions with different
> prototypes, and args are a number of arguments, each of an arbitrary
> type. Or at least:
> 
>     if (nr_args == 1)
>         fp (*(type[0] *) arg[0]);
>     else if (nr_args == 2)
>         fp (*(type[0] *) arg[0], *(type[1] *) arg[1]);
> 
> What I'm doing instead essentially is:
> 
>     if (fp == specific_function)
>         specific_function(*(int*)arg[0], *(char **)arg[1]);
>     else if (fp == another_function)
>         another_function(*(size_t *)arg[0]);

There's definitely a better way to do this. If nothing else, you could
write one-line wrappers for each function you want to test and put a
pointer to the wrapper rather than the function itself in the table.

> That just dislocates above, and puts it into the function to be
> called with the arg pointer (and, don't forget, the function
> identifier). I can go to IRC if you want to see what the generator
> output is/should be, and based on what input.

Could you include some here?

Rich


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: cluts weekly reports
  2011-08-03 18:19                 ` Rich Felker
@ 2011-08-03 18:38                   ` Luka Marčetić
  2011-08-03 21:59                   ` Luka Marčetić
  1 sibling, 0 replies; 16+ messages in thread
From: Luka Marčetić @ 2011-08-03 18:38 UTC (permalink / raw)
  To: musl

On 08/03/2011 08:19 PM, Rich Felker wrote:
> There's definitely a better way to do this. If nothing else, you could
> write one-line wrappers for each function you want to test and put a
> pointer to the wrapper rather than the function itself in the table.
>

That really doesn't help me.

>> That just dislocates above, and puts it into the function to be
>> called with the arg pointer (and, don't forget, the function
>> identifier). I can go to IRC if you want to see what the generator
>> output is/should be, and based on what input.
> Could you include some here?
>
> Rich

Ok, let me write one json input file, and what the corresponding output 
should be (but still isn't).



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: cluts weekly reports
  2011-08-03 18:19                 ` Rich Felker
  2011-08-03 18:38                   ` Luka Marčetić
@ 2011-08-03 21:59                   ` Luka Marčetić
  2011-08-03 22:45                     ` Solar Designer
  2011-08-03 22:53                     ` Rich Felker
  1 sibling, 2 replies; 16+ messages in thread
From: Luka Marčetić @ 2011-08-03 21:59 UTC (permalink / raw)
  To: musl; +Cc: Solar Designer

[-- Attachment #1: Type: text/plain, Size: 283 bytes --]

On 08/03/2011 08:19 PM, Rich Felker wrote:
> Could you include some here?
> Rich

Attached are example files for the generator:

  input.json - the input of the generator
  output.c   - (to be) the output of the generator
  testgen.c  - an additional header that output.c uses

Luka

[-- Attachment #2: input.json --]
[-- Type: application/json, Size: 402 bytes --]

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: output.c --]
[-- Type: text/x-csrc; name="output.c", Size: 3373 bytes --]

#include <errno.h>
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <setjmp.h>
#include <string.h>
#include "common/common.h"
#include <stdlib.h>

/*
 * Copyright (c) 2011 Luka Marčetić<paxcoder@gmail.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted.
 *
 * There's ABSOLUTELY NO WARRANTY, express or implied.
 */

jmp_buf env;
static void bridge_sig_jmp(int sig)
{
    longjmp(env, sig);
}

int main()
{
    union ret ret;
    int sig, err;
    unsigned int d, f, failed;
    char *call, *more;
    size_t i = 0;
    struct arguments *arg;
    struct sigaction oldact, act;
    struct {
        unsigned int
            ret:1,
            err:1,
            sig:1;
    } error, no_error;
    
    memset(&no_error, 0, sizeof(no_error));
    act.sa_handler = bridge_sig_jmp;
    act.sa_flags   = SA_NODEFER;

    struct test t[] =
    {
        {
            "realpath", 2,
            1, (struct data[])
            {
                {//data
                    (struct arguments[])
                    {//arg
                        {2, (char *[]) {".", "./123456789"}},
                        {1, (char *[]) {NULL}},
                    },
                    (char *[]){NULL},
                    ENAMETOOLONG,
                },
            }
        },
    };
    failed = 0;
    for (f=0; f<sizeof(t)/sizeof(t[0]); ++f) {
        memset(&error, 0, sizeof(error));
        sigaction(SIGSEGV, &act, &oldact);
        sig = 0;
        for (d=0; !(sig = setjmp(env)) && !memcmp(&error, &no_error, sizeof(error)) &&  d<t[f].ndata; ++d) {
            arg = t[f].data[d].arg; //shorthand args
            for (i=0; !memcmp(&error, &no_error, sizeof(error)) && i<iters(t[f],d); ++i) {
                switch (f) {
                        case 0:
                            if ((ret.s = realpath(ARGV(char *, 0), ARGV(char *, 1))) != *(char **)t[f].data[d].ret) {
                                call = sreturnf("%s(\"%s\", %d)", t[f].fn_name, ARGV(char *, 0), ARGV(int, 1));
                                error.ret=1;
                                more = sreturnf("%d instead of %d", ret.s, *(char *)t[f].data[d].ret);
                            }
                            if (t[f].data[d].err!=-1  &&  (err=errno) != t[f].data[d].err) {
                                call = sreturnf("%s(\"%s\", %d)", t[f].fn_name, ARGV(char *, 0), ARGV(int, 1));
                                error.err=1;
                            }
                        break;
                }
            }
        }
        error.sig = !(!sig);
        sigaction(SIGSEGV, &oldact, NULL);
        
        if (memcmp(&error, &no_error, sizeof(error))) {
            if (error.sig)
                fprintf(stderr, "Test %s caused a SIGSEGV (iteration %zu)\n",
                    t[f].fn_name, i
                );
            else {
                --d;
                --i;
            }
            if (error.ret) {
                fprintf(stderr, "%s returned %s \n", call, more);
                free(more);
            }
            if (error.err)
                fprintf(stderr, "%s set errno to %s instead of %s \n",
                    call, e_name(err), e_name(t[f].data[d].err)
                );
            
            free(call);
            ++failed;
        }
    }
    return failed;
}

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #4: testgen.c --]
[-- Type: text/x-csrc; name="testgen.c", Size: 2106 bytes --]

/*
 * Copyright (c) 2011 Luka Marčetić<paxcoder@gmail.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted.
 *
 * There's ABSOLUTELY NO WARRANTY, express or implied.
 */

//A union for return values of functions
union ret {
    char  c;
    char* s;
    int   i;
    void* vp;
};

///Atrucutre designed to hold test data
struct test
{
    char         *fn_name; //function name for the output
    unsigned int narg;     //number of arguments that the function takes
    unsigned int ndata;    //number of test datasets
    struct data {
        struct arguments {unsigned int nr; void *vp;} *arg;
        void   *ret;
        int    err;
    } *data;
};

///Handy macro to get a certain value from an element via the arg void pointer
///Note: it requires arg and i to be a pointer to struct arguments & an iterator
//       hint: see iter and arg arguments for index()
#define ARGV(TYPE, INDEX) ((TYPE *) arg[INDEX].vp)[index(i, arg, INDEX)]

/**
 ** \returns the cardinality of a cartesian product of sets of arguments
 **  ie the number of iterations required to cover all argument values
 ** \param t a test to which the arguments belong
 ** \param d an index of the dataset from t to be taken into consideration
 **/
size_t iters(struct test t, unsigned int d)
{
    size_t i, product=1;
    for (i=0; i<t.narg; ++i)
        product *= t.data[d].arg[i].nr;
    return product;
}

/**
 ** Given an iteration, returns the index of an argument value. That is,
 ** if iter is the number of a certain tuple from the cartesian product, and
 ** i the nr of an element from the tuple, the function returns its index in
 ** the original set - ie the (i-th) factor set to the cartesian product)
 ** \param iter current iteration
 ** \param arg a struct arguments pointer from struct test
 ** \param i index of the arguments for which the element index is requried
 **/
size_t index(size_t iter, struct arguments *arg, int i)
{
    size_t x = iter;
    for(int j=0; j<i; ++j)
        x /= arg[j].nr; //an integer value
    x %= arg[i].nr;
    return x;
}

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: cluts weekly reports
  2011-08-03 21:59                   ` Luka Marčetić
@ 2011-08-03 22:45                     ` Solar Designer
  2011-08-03 22:53                     ` Rich Felker
  1 sibling, 0 replies; 16+ messages in thread
From: Solar Designer @ 2011-08-03 22:45 UTC (permalink / raw)
  To: musl

On Wed, Aug 03, 2011 at 11:59:52PM +0200, Luka Mar??eti?? wrote:
> Attached are example files for the generator:
> 
>  input.json - the input of the generator
>  output.c   - (to be) the output of the generator
>  testgen.c  - an additional header that output.c uses

Thanks!  Rich is to comment on this.  (I am busy with something else.)

Alexander


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: cluts weekly reports
  2011-08-03 21:59                   ` Luka Marčetić
  2011-08-03 22:45                     ` Solar Designer
@ 2011-08-03 22:53                     ` Rich Felker
  2011-08-04 11:43                       ` Luka Marčetić
  1 sibling, 1 reply; 16+ messages in thread
From: Rich Felker @ 2011-08-03 22:53 UTC (permalink / raw)
  To: musl

On Wed, Aug 03, 2011 at 11:59:52PM +0200, Luka Marčetić wrote:
> [
>     {
>         "include" : "stdlib.h",
>         "function": "char *realpath(const char *restrict file_name, char *restrict resolved_name);",
>         "data" : [
>             {
>                 "file_name":     ["\".\"", "\"./123456789\""],
>                 "resolved_name": "NULL",
>                 
>                 "return": "NULL",
>                 "errno" : "ENAMETOOLONG"
>             }
>         ]
>     }
> ]

OK, I'm imagining something like this:

void test_realpath(const struct test *test, void *res, char *buf, size_t len)
{
	*(char *)res = realpath(test->arg[0].ptr, buf);
}

struct test tests[] = {
{ .function = test_realpath, .arg[0].ptr = ".", ... },
{ .function = test_realpath, .arg[0].ptr = "./123456789", ... },
...};

With some extra fields to indicate the return type and how the caller
should validate the result. Actually I would make a function (called
do_test or something) that would do all that work. Note that here I
hard-coded the fact that tests will take a buffer/length pair
(despite the fact that realpath ignores the length), but you could
just as easily have encapsulated the args that the caller might vary
into a separate void * argument to test_xxxxxxx() (which it would know
how to cast back and extract data from.

The result handling could also be better. Actually you might want to
consider having the test structure include a "validate" function
pointer that would be used to validate the results. A couple reusable
validator functions would be one that strcmp's the contents of a
buffer (and checks for overwrite at the end), one that compares an
integer or floating point result stored at the result pointer, etc..
In addition, the generic code could always check errno unless you have
a flag not to check it, or you could make a system where you provide
an *array* of validator functions to choose the ones you want, thereby
being able to include an errno check and something else.

This is all very general stuff I whipped up in 30 minutes or so. I
could elaborate on it if this isn't giving you enough ideas.

Also, if you think this isn't helpful, please expand on the example
you sent me. Seeing ONE TEST doesn't give me any idea of the type of
generality you're trying to achieve.

Also..

>     for (f=0; f<sizeof(t)/sizeof(t[0]); ++f) {
>         memset(&error, 0, sizeof(error));
>         sigaction(SIGSEGV, &act, &oldact);
>         sig = 0;
>         for (d=0; !(sig = setjmp(env)) && !memcmp(&error, &no_error, sizeof(error)) &&  d<t[f].ndata; ++d) {
>             arg = t[f].data[d].arg; //shorthand args
>             for (i=0; !memcmp(&error, &no_error, sizeof(error)) && i<iters(t[f],d); ++i) {
>                 switch (f) {
>                         case 0:
>                             if ((ret.s = realpath(ARGV(char *, 0), ARGV(char *, 1))) != *(char **)t[f].data[d].ret) {

This is certainly wrong, in general. You can't use equality operators
to compare strings, but perhaps you're just looking for null pointers
here? Also the second arg needs to be a caller-provided buffer, but
part of the test structure, I think.. I'm a bit confused how this code
is supposed to work.

Rich


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: cluts weekly reports
  2011-08-03 22:53                     ` Rich Felker
@ 2011-08-04 11:43                       ` Luka Marčetić
  0 siblings, 0 replies; 16+ messages in thread
From: Luka Marčetić @ 2011-08-04 11:43 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 4918 bytes --]

On 08/04/2011 12:53 AM, Rich Felker wrote:
>
> OK, I'm imagining something like this:
>
> void test_realpath(const struct test *test, void *res, char *buf, size_t len)
> {
> 	*(char *)res = realpath(test->arg[0].ptr, buf);
> }
>
> struct test tests[] = {
> { .function = test_realpath, .arg[0].ptr = ".", ... },
> { .function = test_realpath, .arg[0].ptr = "./123456789", ... },
> ...};

That's even more syntax (though I did use this/similar approach in 
numeric.c). It may be a bit more readable, but it introduces more 
repetitive work, whereas the generator is designed so that it would be 
reduced. In the above example you also suppose the arg member of struct 
test to have a determined, maximal possible length (overhead). I'm 
guessing .ptr should be a void pointer, in which case you'll need (type 
[]) wherever the type of the argument is not char *, and you'd need 
casting back at where you call the function.
Anyway, I do understand where you're coming from, but this is no news to 
me, and it really does nothing to eliminate the need I feel for a code 
generator.

> With some extra fields to indicate the return type and how the caller
> should validate the result. Actually I would make a function (called
> do_test or something) that would do all that work.

Exactly, but this wouldn't help at all. If anything, it'd introduce more 
code. As I've said before, what main does would just go into that new 
function. This is what happens with numeric.c, but it would be even 
worse, since the functions tested may differ greatly which would make 
do_test even larger.

> [...]

> The result handling could also be better. Actually you might want to
> consider having the test structure include a "validate" function
> pointer that would be used to validate the results.

Another function which would do main's work, and introduce an overhead 
of having to be called only to have more code written (type casting, 
return, etc).

> [...]
> In addition, the generic code could always check errno unless you have
> a flag not to check it,

In numeric.c I do that by setting expected errno to -1

> This is all very general stuff I whipped up in 30 minutes or so. I
> could elaborate on it if this isn't giving you enough ideas.

Nothing that I already haven't come up with.
I did use function pointers once too, but compiler complained, so I went 
back to switch-cases.

> Also, if you think this isn't helpful, please expand on the example
> you sent me. Seeing ONE TEST doesn't give me any idea of the type of
> generality you're trying to achieve.

I thought it was obvious: You write test data into a nice, clean little 
json structure (and include a function prototype). The generator parses 
the prototype, and generates most/all of the code needed for the test to 
go through.
To understand how you could expand the example, you can imagine you add 
another dataset for the same function into the json file (which requires 
a different return result for eg.). This would have an effect of 
generator adding to (struct data []). Likewise, if you add a whole new 
testset and specify a different function prototype altogether, a new 
element to t[] would be added, as well as a new case with correct 
comparisons etc.

> Also..
>
>>      for (f=0; f<sizeof(t)/sizeof(t[0]); ++f) {
>>          memset(&error, 0, sizeof(error));
>>          sigaction(SIGSEGV,&act,&oldact);
>>          sig = 0;
>>          for (d=0; !(sig = setjmp(env))&&  !memcmp(&error,&no_error, sizeof(error))&&   d<t[f].ndata; ++d) {
>>              arg = t[f].data[d].arg; //shorthand args
>>              for (i=0; !memcmp(&error,&no_error, sizeof(error))&&  i<iters(t[f],d); ++i) {
>>                  switch (f) {
>>                          case 0:
>>                              if ((ret.s = realpath(ARGV(char *, 0), ARGV(char *, 1))) != *(char **)t[f].data[d].ret) {
> This is certainly wrong, in general. You can't use equality operators
> to compare strings, but perhaps you're just looking for null pointers
> here?

Don't be so certain. The generator would use strcmp if the expected 
return value is not NULL (and in case of error would print it with 
\"%s\" rather than %d which it does there).

> Also the second arg needs to be a caller-provided buffer, but

"If the/resolved_name/argument is a null pointer, the pointer returned 
by/realpath/() can be passed to/free/()."
Granted, where caller-provided buffers are required, a need would arise 
to modify the generated code manually (and that's not the only occasion).


> part of the test structure, I think.. I'm a bit confused how this code
> is supposed to work.

This code would actually require a chdir() to be added to it to change 
into a directory so deep that when resolved_name is called, PATH_MAX is 
exceeded, and errno should be set to ENAMETOOLONG. It's one of the tests 
for the task nr. 7.

Luka.
P.S. I guess I'll go with signals test for now?

[-- Attachment #2: Type: text/html, Size: 9279 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2011-08-04 11:43 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-07-18 17:10 cluts weekly reports Luka M.
2011-07-25 23:04 ` Luka M.
2011-08-03  0:56   ` Solar Designer
2011-08-03  1:21     ` Rich Felker
2011-08-03 13:15       ` Luka Marčetić
2011-08-03 13:31         ` Rich Felker
2011-08-03 14:51           ` Solar Designer
2011-08-03 17:08           ` Luka Marčetić
2011-08-03 17:22             ` Rich Felker
2011-08-03 18:03               ` Luka Marčetić
2011-08-03 18:19                 ` Rich Felker
2011-08-03 18:38                   ` Luka Marčetić
2011-08-03 21:59                   ` Luka Marčetić
2011-08-03 22:45                     ` Solar Designer
2011-08-03 22:53                     ` Rich Felker
2011-08-04 11:43                       ` Luka Marčetić

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).