Ir al contenido principal

Ralsina.Me — El sitio web de Roberto Alsina

RaSPF on its way to release

I have been able to work some more on RaSPF and the re­sults are en­cour­ag­ing.

Thanks to val­grind and test suites, I am pret­ty con­fi­dent it does­n't leak mem­o­ry, or at least, that it does­n't leak ex­cept on very rare cas­es.

I think I found a neat way to sim­pli­fy mem­o­ry man­age­men­t, though, and that's what I want­ed to men­tion.

This is prob­a­bly triv­ial for ev­ery­one read­ing, but I am a lim­it­ed C pro­gram­mer, so when­ev­er some­thing works un­ex­pect­ed­ly right, I am hap­py ;-)

One prob­lem with C mem­o­ry man­age­ment is that if you have many ex­it points for your func­tion­s, re­leas­ing ev­ery­thing you al­lo­cate is rather an­noy­ing, since you may have to do it in sev­er­al dif­fer­ent lo­ca­tion­s.

I com­pound­ed this prob­lem be­cause I am us­ing ex­cep­tions (yeah, C does­n't have them. I used this).

Now not on­ly do I have my re­turns but al­so my throws and what­ev­er un­caught throw some­thing I called has!

Hel­l, right?

Nope: what ex­cep­tions com­pli­cat­ed, ex­cep­tions fixed. Look at this func­tion:

bstring spf_query_get_explanation(spf_query *q, bstring spec)
{
    bstring txt=0;
    struct bstrList *l=0;
    bstring expanded=0;
    bstring result=0;
    struct tagbstring s=bsStatic("");

    try
    {
        // Expand an explanation
        if (spec && spec->slen)
        {
            expanded=spf_query_expand(q,spec,1);
            l=spf_query_dns_txt(q,expanded);

            if (l)
            {
                txt=bjoin(l,&s);
            }
            else
            {
                txt=bfromcstr("");
            }
            result=spf_query_expand(q,txt,0);
            throw(EXC_OK,0);
        }
        else
        {
            result=bfromcstr("explanation: Required option is missing");
            throw(EXC_OK,0);
        }
    }
    except
    {
        if(expanded) bdestroy(expanded);
        if(txt) bdestroy(txt);
        if(l) bstrListDestroy(l);
        on (EXC_OK)
        {
            return result;
        }
        if(result) bdestroy(result);
        throw(EXCEPTION.type,EXCEPTION.param1);
    }
}

It does­n't mat­ter if spf_­query_­ex­pand or spf_­query_dns_txt throw an ex­cep­tion, this will not leak.

Nice, I think :-)

Tomaz Canabrava / 2007-03-13 20:36:

I don't get the point. if try -> cath is the way to dont leak memory, why don't you use C++ , since it has build in try / catch instead of a c hack?

mix / 2007-03-13 20:46:

Exceptions seem a bit unC-ish to me... and it looks to me that the implementation you are using is not thread-safe.

Why don't you just use the "standard" approach:

int func(int a, int b)
{
int ret = SPF_ERROR;
resource *xa = make_res(a);
if(xa) {
resource *xb = make_y(b);
if(xb) {
... do something with xa and xb
if(everything ok) ret = SPF_OK;
destroy_y(xb);
}
destroy_res(xa);
}
return ret;
}

You can also add more specific error codes SPF_ERROR_{reason}.

jstaniek / 2007-03-13 20:53:

Hello, your web sidebar looks broken on Seamonkey...

Roberto Alsina / 2007-03-13 21:27:

mix: because it's an unreadable mess, and doesn't handle propagation of errors up the call chain, so you have to think of any error anything you call can ever produce?

Gotos are cleaner than that.

Tomaz: It would make even more sense to use D which has exceptions **and** garbage collection. But I wanted to do this particular project in C.

jstaniek: It should look ok if you make your window wider. That's a bug in my CSS but I haven't had time to hack around it.

mix / 2007-03-14 00:17:

It is the same thing as c++ destructors, just rewritten into c. When I "switch down" to c from c++, I continue using the same approach, it's probably a habit :).

I dislike jmpbuf based c hacks, I remember using libpng - now that is a mess. You have to create artificial barriers between APIs as an API user, because exception implementations differ. It is simpler to just handle ints, IMO. Pthread API is a good example of what I'm trying to say here.

Roberto Alsina / 2007-03-14 01:38:

Well, the idea here is that exceptions don't cross the boundaries of my library, and the underlying libraries don't use them (or at least I am not seing them ;-)

I suppose just like you can write Fortran on every language, I am writing some sort of perverse python in C ;-)

Tomaz Canabrava / 2007-03-14 02:49:

sure... but perverse python in c is not c. it's perverse python in c. and if you use try // catch in your 'c' code, anyone that get's the code and start looking at it will not see that's c, they will think that's c++. if you wish to do in c, do in c. also you should use try / catch only when it's really necessary, because it overloads the code, and make the program a little more bloated. but, still, this is just my humble opnion.

Roberto Alsina / 2007-03-14 11:23:

Tomaz: That's like the old argument about how Qt is not "real C++" because of moc.

I didn't buy it then and don't buy it now.

"Perverse python" is only a statement about style.


Contents © 2000-2024 Roberto Alsina