Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Wed, 3 Aug 2011 18:53:57 -0400
From: Rich Felker <dalias@...ifal.cx>
To: musl@...ts.openwall.com
Subject: Re: cluts weekly reports

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

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.