jacob navia wrote On 12/19/05 17:01,:
> Many compilers check printf for errors, lcc-win32 too. But there are
> other functions that would be worth to check, specially memset.
>
> Memset is used mainly to clear a memory zone, receiving a pointer to
> the start, the value (most of the time zero) and the size of the
> memory array to clear.
>
> Problems appear when the size given is not the size of the object
> given as its first argument. For instance
> void fn(void)
> {
> int array[128];
>
> memset(array,0,12
;
> }
>
> This will fail to clear the array entirely.
>
> The compiler can check this kind of things when the size of the object
> is known.
>
> When the pointer given points to a structure/union/or array with known
> size (i.e. its size is available at compilation time) I have added code
> to check for this. If the size given is bigger than the size of the
> object the compiler will now issue a warning. If the size is less, and
> the value to set is zero, the compiler will issue a warning too, saying
> that memset fails to clear completely the array.
YMMV, but I use memset() rather rarely and have a hard
time understanding why it's "specially" worthy of a check.
memcpy() and memmove() would seem more deserving candidates,
and the same machinery could probably be used.
Pursuing the size-checking theme a little further might
be helpful. qsort(), fread(), ... offer opportunities to
sanity-check as many as two arguments. It might be even
more beneficial to sanity-check the argument of malloc() and
the second arguments of calloc() and realloc(). This would
be harder because some of the information is "outside" the
function call itself and would need to be derived from the
wider context: `malloc(3)' in isolation could be right or
wrong, but `char **p = malloc(3)' is almost certainly wrong.
> Borderline cases:
>
> What to do with unions?
>
> You can use memset to clear a member of the union, without clearing the
> whole union. I have choosen not to complain in this case. What do you think?
To fill one element of a struct or union, one would normally
write memset(&s.x, 42, sizeof s.x). To fill the whole thing,
you'd typically write memset(&s, 42, sizeof s). If you're going
to issue a warning for memset(&v, 42, unequal_to_sizeof_v), it
seems to me you could treat s or s.x the same way.
> Other interesting cases arise with clearing of an array:
>
> struct foo *p;
> p = malloc(sizeof(struct foo)*123);
> if (p) {
> memset(p,0,123);
> }
> Supposing sizeof(struct foo) is 64, the given size is not
> a multiple of the size of the structure.
> Would it be possible to issue a warning here? or would it lead to
> many "false positives" (unwarranted warnings) ?
You'd get false positives on the struct hack, even in its
C99-approved form. Too many? I have no idea, except that I
quite frequently write the related form
struct foo *p = malloc(sizeof *p + strlen(s) + 1);
if (p == NULL) die();
p->string = (char*)(p + 1);
strcpy(p->string, s);
.... and would not like to be scolded for it. (You might not
do so anyhow, being unable to determine strlen(s) at compile
time.)
Hmmm: Have you considered checking for malloc(strlen(s))?
> Of course when the memory points to a primitive type (int/double, etc)
> there is no way the compiler can check that the size given is
> correct, specially of course in the case of chars, where sizeof is 1.
>
> In other cases it should be a multiple of the element size, isn't it?
> I.e. the size when clearing a int * should be a multiple of sizeof(int)
> with a double * a multiple of sizeof double, etc.
>
> What do you think?
What I think is the usual load of baloney

How about
implementing your checks and running a few million lines of
source through it, counting up the false positives and the
actual hitherto-undetected errors that are caught, and then
making a judgement?
--