Restricting pointer access to zero offset?

D

David Mathog

Normally in a case like this:

char *string=NULL;
....
string=malloc(ALLOCSIZE);

it is fine and proper to later access string with these
string
string++

However, these are situations where one would like to forbid nonzero
offset access to a pointer. Is there a way to tell a compiler that
this should be an error? For instance, in a structure situation like
this:

typedef struct is_inner INNER;
typedef struct is_outer OUTER;
struct is_outer {
INNER *list;
int blah;
/*etc.*/
};
struct is_inner{
char *string;
int length;
}

OUTER *ohandle;
ohandle=malloc(sizeof(OUTER));
ohandle->list=malloc(sizeof(INNER)*N);

These operations:

ohandle++
ohandle

are mistakes, at least in the intended use of this code, since ohandle
is a single struct. However, the compiler does not issue a warning
since they are valid pointer operations. Where they occur the
programmer probably meant

ohandle->list++;
ohandle->list;

Is there any standard way to tell a compiler that "accessing this
pointer with any nonzero offset is illegal?" This isn't static and it
isn't const. The closest words II can think of for the desired
behavior are "pinned" and "locked", but there are no such keywords.

I know the situation can be avoided by passing the structure and not a
pointer to the structure, but that isn't going to be good, performance
wise, when the structure in question is large and complex.

Thanks,

David Mathog
 
I

Ike Naar

Normally in a case like this:

char *string=NULL;
...
string=malloc(ALLOCSIZE);

it is fine and proper to later access string with these
string
string++

However, these are situations where one would like to forbid nonzero
offset access to a pointer. Is there a way to tell a compiler that
this should be an error?


Would this be an option:

char * const string = malloc(ALLOCSIZE);
 
D

David Mathog

Normally in a case like this:
  char *string=NULL;
...
  string=malloc(ALLOCSIZE);
it is fine and proper to later access string with these
  string
  string++

However, these are situations where one would like to forbid nonzero
offset access to a pointer. Is there a way to tell a compiler that
this should be an error?

Would this be an option:

    char * const string = malloc(ALLOCSIZE);


Unfortunately no, because that breaks normal structure usage like:

outer->blah=value;

which needs to still work. For the same reason an opaque type isn't
quite what I am after. The idea is to catch the use of a pointer to a
struct in an unintended manner, not to make it impossible to use the
pointer to a struct to access that pointers structure elements.

If outer is "const", then when gcc tries to compile that the line
above, it leads to this:

error: assignment of read-only location

Restating the goal another way:

1. dereference pointer to reach structure elements = OK
2. dereference pointer any other way = NOT OK
3. copy pointer = OK
4. free pointer = OK

I can see why this would be hard well into the compilation, at which
point 1 & 2 both look like ptr+offset, but earlier on the compiler
should, in theory, be able to make this distinction.

Thanks,

David Mathog
 
B

Ben Bacarisse

David Mathog said:
Normally in a case like this:
  char *string=NULL;
...
  string=malloc(ALLOCSIZE);
it is fine and proper to later access string with these
  string
  string++

However, these are situations where one would like to forbid nonzero
offset access to a pointer. Is there a way to tell a compiler that
this should be an error?

Would this be an option:

    char * const string = malloc(ALLOCSIZE);


Unfortunately no, because that breaks normal structure usage like:

outer->blah=value;

which needs to still work.


No, you can assign to a member through a const pointer. It's only when
the pointer is to a const object that the assignment is a constraint
violation. I.e.

const struct S *outer;
/* or struct S const *outer; */

is not the same as

struct S *const outer;
For the same reason an opaque type isn't
quite what I am after. The idea is to catch the use of a pointer to a
struct in an unintended manner, not to make it impossible to use the
pointer to a struct to access that pointers structure elements.

If outer is "const", then when gcc tries to compile that the line
above, it leads to this:

error: assignment of read-only location

I suspect you have a pointer to const rather than a const pointer.
Restating the goal another way:

1. dereference pointer to reach structure elements = OK
2. dereference pointer any other way = NOT OK
3. copy pointer = OK
4. free pointer = OK

I can see why this would be hard well into the compilation, at which
point 1 & 2 both look like ptr+offset, but earlier on the compiler
should, in theory, be able to make this distinction.

Many languages can do what you want, but I don't think it's possible in
C. Making the pointer const does rule out one of cases you wanted to
rule out (ptr++) but it has no effect on ptr[1].
 
D

David Mathog

On thinking about this a little more I think the issue is that there
are pointer properties which have no corresponding keywords to control
them. Here is a list of pointer properties and associated control
options in C (probably incomplete, definitely not written by a
language specialist, so please forgive incorrect terminology). In
some instances there are keywords to control the property, in others,
not.

1. Pointer may be changed. Examples:

char *ptr;
ptr++;
ptr--;
ptr += offset;

Keyword "const" prevents these operations.

2. Pointer may be used to reference memory at an offset by
sizeof(type). Example:

int *var;
*(var + offset) = var[offset + 1];

No keyword prevents these actions. Stopping these actions comes up in
the context of "single vs. multiple". That is:

int *var;

may reference one int, or it may reference many, and there is
currently no way to tell the compiler which is desired. A keyword to
prevent this action: might be "single". As in:

int single *var;
...
/* compiler throws errors on the next two lines, which would
otherwise be legal */
foo = var;
foo = *(var + i);

3. Pointer is used to reference structure elements. Example:

var->element1;

Current keyword - none. Compilers throw errors if var is not a
pointer to a structure with a member named "element1". Additionally
there is opaque typing via typedef. A keyword to prevent this sort of
reference might be "opaque". Possibly useful in a situation where an
opaque type is used in the same file where the non-opaque definitions/
actions are coded. Otherwise, I cannot think of a situation where it
would be used.

4. memory allocation/free/reallocation via (void *).
Current keyword - const. But const doesn't really do much for the
situations where more than one pointer is used to reference an
allocated region, which can lead to "memory confusion". Example:

int *array=malloc(BIGNUMBER*sizeof(int));
int *oneptr;
int *twoptr;
oneptr=array;
twoptr=array;
...
/* far away in the code */
free(oneptr);
...
/* and later */
free(twoptr);

The first free() may or may not be an error, but the second one
certainly is. Const really doesn't get us out of this because we
might have assigned two pointers as in this case. A keyword "primary"
could clarify this situation (and should probably additionally have
the same effect as "const"), like:

int *array=NULL;
int primary *oneptr=NULL; /* an "official" memory reference */
int *twoptr=NULL;
array=malloc(BIGNUMBER*sizeof(int)); /* still works! */
oneptr=(int primary *)array; /* official reference filled */
/* forbidden: two primary pointers for the same memory
int primary *threeptr = oneptr;
*/
twoptr=array; /* no problem, neither is a primary */
...
/* far away in the code we run into this, which is fine,
because oneptr is a primary */
pfree(oneptr);
...
/* and later this, which is an error */
pfree(twoptr);

where

void pfree(void primary *address){}

similarly:

void primary *pmalloc(size);
/*etc.*/

Here adding the keyword would require new functions, because
currently
C treats all pointers as if they were "primary", and so free() etc.
cannot be easily modified in a backwards compatible manner to
implement this. Well, we could define "secondary", and have the
compiler flag calls to free() with secondary pointers, but "secondary"
would have to be applied to pretty much every pointer, which would be
awful. Primary, on the other hand, would affect fewer pointers.

5. reference at different scope, specifically, allowing a reference
outside of its defined scope. Example:

void function(int **var){
int localvar;
*var = &localvar;
}
...

int *var;
function(&var);
/* var points to nothing useful here, prepare to segfault */

Current keyword to control this - none. Current keyword to mediate
the effect (by changing the scope of the memory) is "static". A
keyword to disable this might be "local". Where

void function(int **var){
int localvar;
local int *ptr;
ptr=&localvar; /* this is OK, local references in scope */

function1(localvar); /* still good */

function2(ptr); /* <- here is where it gets complicated!!! */

/* compiler throws an error at the next line with something like:
"out of scope reference forbidden by local keyword"
*/
*var = &localvar;
}

and of course this would still be fine:

void function(int **var){
static int localvar;
*var = &localvar;
}

The logic cannot be inverted with "global" instead of "local", as it
won't be backwards compatible, because currently all pointers are
"global", and they would have to default to "local" for "global" to be
the keyword.

6. casting of pointers. Some of the situations above can reappear
when pointers are dereferenced. Example:

function(STRUCTDEF *holder){
}

STRUCTDEF **holder; /* an array of holder pointers */
...
/* in this instance, a pointer to a single STRUCTDEF, not
to an array of STRUCTDEFs */
function( &(holder) );

this is back to the many vs. single issue from (2). So to fully
specify
what is intended this would become:

function(STRUCTDEF single *holder){
}

STRUCTDEF **holder; /* an array of holder pointers */
...
function( (STRUCTDEF single *)(&(holder) );

which suggests that this type of keyword could be applied in the "more
restrictive" direction in casts, as is "const" now.

Regards,

David Mathog
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top