07 Jun, 2007, Exodus wrote in the 1st comment:
Votes: 0
I've been running into some difficulty with seemingly innocent checks in my code trying to access bad data. What I think would be pretty damned neat is a function that validates data when checking a pointer, even if it's going through several different structures.

Take this for example:

struct some_struct
{
int blah;
};

struct pc_data
{
struct some_struct whatever;
};

struct char_data
{
struct pc_data *pcdata;
};


With those structures in mind, doing a nonchalant function such as:

void do_whatever( struct char_data *ch )
{
if( ch->pcdata->whatever->blah == 1 )
do_something();
return;
}



Now, normally this wouldn't be any big issue, but consider, for whatever reason, 'ch' is a valid address in memory, but 'pcdata' is NULL, or better yet, both 'ch' and 'pcdata' are valid, but 'whatever' is NULL. When that's the case, if( ch->pcdata->whatever->blah == 1 ) is going to crash and burn.

What I'm getting at, is does anyone know how I might create a function to check for things like this?

Something like safe_if( ch->pcdata->whatever->blah == 1 ) that would check to see if each pointer it checks along the way and halts the execution of the function if it runs into a problem, rather than crashing the program.

I'm trying to avoid a bunch of checks that look like this:

if( ch && ch->pcdata && ch->pcdata->whatever )
{
if( ch->pcdata->whatever->blah == 1 )
do_something();
}

Maybe I'm going about this all wrong. I suppose it would be better in the long run to figure out how the data ended up invalid in the first place before the attempt to access it, but that's often difficult and time-consuming. Maybe there's a more fault-tolerant compilation options that I'm not aware of. Any ideas would be greatly appreciated.
07 Jun, 2007, kiasyn wrote in the 2nd comment:
Votes: 0
Exodus said:
if( ch->pcdata->whatever->blah == 1 )


Should be:

if( ch->pcdata->whatever.blah == 1 )
07 Jun, 2007, Luriel wrote in the 3rd comment:
Votes: 0
I can't think of any easy way to solve this, at least directly in C. However I may just be taking the wrong approach! Anyway my original idea was to convert the first half of the if check into a string. Then split the string up into substrings using '->' as the split point. Kind of like string.split("->"); in Java. Then convert the strings back to variables and starting with the first check it isn't null and then first->second != NULL, etc. The problem is that you can't convert a string to a variable name in C. You could still use this method, but you'd have to put it in a shellscript or something. It'd look for all safe_ifs in the source code, and make temp files with the correct version in. You'd have to edit you Makefile to run the script and then compile the temp files.

To do it directly in C I could only think of two ways. The first is that you make a symbol table for all variables, storing name, scope and memory address. Then you can use the method above to convert strings back to variables. This would require loads of effort though so probably just isn't worth it.

Otherwise you could use several macros with increasing number of args, e.g.
#define SAFE_IF2( struct1, struct2, condition ) \
if ( struct1 \
&& struct1->struct2 \
&& struct1->struct2->condition )

#define SAFE_IF3( struct1, struct2, struct3, condition ) \
if ( struct1 \
&& struct1->struct2 \
&& struct1->struct2->struct3 \
&& struct1->struct2->struct3->condition )


etc. Using them like SAFE_IF3( ch, pcdata, whatever, blah == 1 ).

These methods are pretty lame, which makes me think there's could be a better way to do it, but I can't think of it!
07 Jun, 2007, Davion wrote in the 4th comment:
Votes: 0
#define VALID_PCHAR(ch) ( (ch) && (ch)->pcdata )
void do_something(struct char_data *ch)
{ if( VALID_PCHAR(ch) && ch->pcdata->whatever.bleh = =1 )
//dostuff;
return;
}
0.0/4