From mboxrd@z Thu Jan 1 00:00:00 1970 X-Msuck: nntp://news.gmane.org/gmane.linux.lib.musl.general/240 Path: news.gmane.org!not-for-mail From: =?UTF-8?B?THVrYSBNYXLEjWV0acSH?= Newsgroups: gmane.linux.lib.musl.general Subject: Re: cluts weekly reports Date: Thu, 04 Aug 2011 13:43:29 +0200 Message-ID: <4E3A85E1.6010008@gmail.com> References: <20110803005619.GA2378@openwall.com> <20110803012112.GT132@brightrain.aerifal.cx> <4E3949E3.4090008@gmail.com> <20110803133155.GV132@brightrain.aerifal.cx> <4E398092.8070907@gmail.com> <20110803172227.GX132@brightrain.aerifal.cx> <4E398D5A.6080207@gmail.com> <20110803181908.GZ132@brightrain.aerifal.cx> <4E39C4D8.7040403@gmail.com> <20110803225357.GC132@brightrain.aerifal.cx> Reply-To: musl@lists.openwall.com NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: multipart/alternative; boundary="------------050507000302080508020303" X-Trace: dough.gmane.org 1312458339 23300 80.91.229.12 (4 Aug 2011 11:45:39 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Thu, 4 Aug 2011 11:45:39 +0000 (UTC) To: musl@lists.openwall.com Original-X-From: musl-return-324-gllmg-musl=m.gmane.org@lists.openwall.com Thu Aug 04 13:45:35 2011 Return-path: Envelope-to: gllmg-musl@lo.gmane.org Original-Received: from mother.openwall.net ([195.42.179.200]) by lo.gmane.org with smtp (Exim 4.69) (envelope-from ) id 1QowMo-00041j-1c for gllmg-musl@lo.gmane.org; Thu, 04 Aug 2011 13:45:34 +0200 Original-Received: (qmail 3934 invoked by uid 550); 4 Aug 2011 11:45:33 -0000 Mailing-List: contact musl-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: Original-Received: (qmail 3923 invoked from network); 4 Aug 2011 11:45:33 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=message-id:date:from:user-agent:mime-version:to:subject:references :in-reply-to:content-type; bh=jBnjm8YZrU1y7ZT70+H1j4XWxOP1a1cb69H/wwgMMPg=; b=qKiVkdYyX5UQMHsqUbtAxLtGnezNoSa8ANAgIi3nEjb1lkV78D4KcHuTh5Wv9hIyB9 FvMcWU1+8ufUeAmMvq3NcY3tkfDUju6jK+eNijIKLgeU7tDYMkOA+3BU6K82r8GgOB9+ Hx4CpeFQUjTVWaiG2x5shPF6GRlbHwV9QJlpI= User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.18) Gecko/20110626 Icedove/3.1.11 In-Reply-To: <20110803225357.GC132@brightrain.aerifal.cx> Xref: news.gmane.org gmane.linux.lib.musl.general:240 Archived-At: This is a multi-part message in MIME format. --------------050507000302080508020303 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit 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> memset(&error, 0, sizeof(error)); >> sigaction(SIGSEGV,&act,&oldact); >> sig = 0; >> for (d=0; !(sig = setjmp(env))&& !memcmp(&error,&no_error, sizeof(error))&& d> arg = t[f].data[d].arg; //shorthand args >> for (i=0; !memcmp(&error,&no_error, sizeof(error))&& 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? --------------050507000302080508020303 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: 8bit 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?
--------------050507000302080508020303--