Re: Q about passing data as a const array



On Thu, 15 Jan 2009 09:41:17 -0800, Keith Thompson
<kst-u@xxxxxxx> wrote:

cri@xxxxxxxx (Richard Harter) writes:
On Wed, 14 Jan 2009 00:31:50 -0800, Keith Thompson
<kst-u@xxxxxxx> wrote:
cri@xxxxxxxx (Richard Harter) writes:
Here is a simple question. I have data that I want to pass to a
function; I don't want the function to scribble on it. Does
something like this work?

void func(const size_t len,const char data[]);
...
char * data;
size_t len;
/* code creating data and giving it content */
...
func(len,data);

It should. The const on the len parameter is superfluous; it
prevents func from modifying its own local copy, but it can't
modify the argument anyway. As for "const char data[]", that's
exactly equivalent to "const char *data", which means that func
can't modify the stuff that the pointer points to.

Thanks; I thought that was how it would be interepreted, but I
thought I would check. Now take the next step:

struct mydata {
size_t len;
char * data;
};

void func(const struct mydata foo);
...
struct mydata bar;
...
func(bar);

Now the question is, does the const qualifier forbid altering the
contents of foo.data? What is the actual rule here?

Yes, the const qualifier forbids func() from altering the contents of
foo.data. It doesn't forbid altering the contents of bar.data; that's
forbidden by the fact that C passes arguments by value. Applying a
const qualifier directly to an argument declaration, as you've done
here, is not very useful; all it does is prevent the function from
modifying the value of its own local copy of the argument value.
Applying const to a pointer parameter can be quite useful, as it
prevents modification of what the pointer points to (e.g., "const char
*param", which is useful, as opposed to "char *const param", which is
much less useful).

But I don't think you asked the question that you meant to ask. The
"contents of foo.data" are a pointer value; func() cannot alter that
pointer value. But I think what you're concerned about is the
contents of what foo.data points to. And the answer is no, applying
"const" to the declaration of the parameter "foo" doesn't prevent
modifying what foo.data points to.

Yes, that was what I was meant. I (faintly) hoped that, so to
speak, there was some way to pass the constness down the
declaration.

To do that, you'd have to declare
it as "const char *data;" -- but that requires modifying the type
declaration, which affects all uses of the type.

I suppose you could declare two different structures:

struct var_mydata {
size_t len;
char *data;
};
struct const_mydata {
size_t len;
const char *data;
};

and use some kind of type-punning to choose, for each particular
usage, whether you want to allow modification of the pointed-to data
or not. But that's ugly, and I'm not sure it's even guaranteed to
work.

It's not something that I would want to use.


Or you could pass len and data as separate arguments, which lets you
declare data as "const char *data", but that loses the advantage of
putting them together into a struct.

That was the original option.


Of course func can always cast its argument to a non-const type,
or do any of several other nasty things, but if it doesn't cheat
you should be ok.

What it comes down to is that there is no way to create immutable
data that is guaranteed to survive being passed through a
function a call. The implication is that you can't rigorously do
message passing by passing references; the only safe thing to do
in C is to copy data to the message.
[...]

I think there's a better approach. Make your "mydata" an opaque type,
and define all allowed operations on it in the same module where you
define the type itself. Code that uses your module will never modify
the pointed-to data unless you let it do so, simply because you
haven't written the code that modifies it. You'll still have to make
sure the code in your module doesn't incorrectly modify anything it's
not supposed to, but that issue is limited to a single, probably
fairly small, source file. See type FILE in <stdio.h> for an example
of this.

Using opaque types is an orthogonal consideration - it doesn't
resolve the security problem, it merely provides "security by
obscurity". Copying provides security because the receiver of
"mydata" doesn't have access to the original data.

No matter what you do, a malicious programmer could always read your
source code, figure out how "mydata" is defined, and do whatever
pointer casting is necessary to clobber your data. There's no way to
guard against that, at least not within a single program (if there
were, we probably wouldn't have malware). If you want to avoid even
that possibility, you best bet is to run all the code that manages
"mydata" on a separate computer, with communication via a network --
and then unplug the network cable and fill the ethernet port with
epoxy. And unplug the power cord. And erase the hard drive. And go
back in time and prevent the invention of the computer. And ...

This isn't quite right if we are copying the data to be sent.
Our malicious programmer can read the source code and figure out
how "mydata" is defined but she wouldn't know the location of the
original of "mydata". To get it she needs knowledge of the
compiler, linker, loader, and OS version in the computer(s) that
do not have proper hardware security.




Richard Harter, cri@xxxxxxxx
http://home.tiac.net/~cri, http://www.varinoma.com
Save the Earth now!!
It's the only planet with chocolate.
.



Relevant Pages

  • Re: Q about passing data as a const array
    ... The const on the len parameter is superfluous; ... exactly equivalent to "const char *data", ... void func(const struct mydata foo); ... Applying const to a pointer parameter can be quite useful, ...
    (comp.lang.c)
  • Re: Whats the deal with const?
    ... specify the const part. ... The definition of a function parameter as "const char *x" defines that ... argument as a pointer to one or more constant characters. ... int some_func ...
    (comp.lang.c)
  • Re: Implicit addition of const qualifiers
    ... > A lot of functions use const pointer arguments. ... function that takes a const char* parameter (points to chars that cannot ... All that happens is that the function cannot easily modify ...
    (comp.lang.c)
  • Re: General method for dynamically allocating memory for a string
    ... to char * variable that I want to assign the substring that I found ... char const *CreateSubstring(char const *const p, ... other than int. ... A pointer value compares equal to 0 only if it's a null pointer. ...
    (comp.lang.c)
  • Re: dh, the daemon helper
    ... some type is a special case, while const ordinarily binds to the ... ie char const * is a pointer to a constant ... no point in returning memory to the malloc heap. ... 2004 is the UNIX standard. ...
    (comp.unix.programmer)