Is argv array modifiable ?

N

Netocrat

[within an arbitrary function, it can't be determined whether the
pointed-to objects of any non-const-qualified pointer parameters were
originally declared const]

Jordan said:
But there's no reason to think that this has been done by whatever calls
main.

Irrelevant unless you can point to a specific prohibition against it or
something similar (i.e. analogous to string literals) for argv.
 
J

Jordan Abel

[within an arbitrary function, it can't be determined whether the
pointed-to objects of any non-const-qualified pointer parameters were
originally declared const]

Jordan said:
But there's no reason to think that this has been done by whatever calls
main.

Irrelevant unless you can point to a specific prohibition against it or
something similar (i.e. analogous to string literals) for argv.


Eh? I was asserting that you _can_ modify the array [as there is no
specific prohibition against doing so - as far as i can tell you are the
one who who needs to find a specific prohibition analogous to string
literals]
 
N

Netocrat

[within an arbitrary function, it can't be determined whether the
pointed-to objects of any non-const-qualified pointer parameters were
originally declared const]

Jordan said:
But there's no reason to think that this has been done by whatever calls
main.

Irrelevant unless you can point to a specific prohibition against it or
something similar (i.e. analogous to string literals) for argv.


Eh?


For "it", substitute "passing a pointer to an object originally defined
with a const qualifier". I'm guessing as to where the misunderstanding
lies - that may clarify it. I interpreted the sentence to which I was
responding in a way that the same fragment could (inelegantly) also
substitute for "this".
I was asserting that you _can_ modify the array [as there is no
specific prohibition against doing so - as far as i can tell you are the
one who who needs to find a specific prohibition analogous to string
literals]

Try this code snippet for a thought experiment:

/* allocates memory and assigns argument strings and count */
char *const *init_new_args(int *new_argc);

int main(int argc, char **argv) {
int new_argc;
char *const *new_argv = init_new_args(&new_argc);
static int first_time = 1;
if (first_time--)
main(new_argc, (char **)new_argv);
/* else argv[0] = a_char_pointer; */ /* illegal attempt
to write to an object that was
defined with a const qualifier */
return 0;
}

On the internal call, main is passed an argv parameter that was defined
with const-qualified members (i.e. argv is non-modifiable). This const
qualifier has been (legally) cast away; nevertheless as commented in the
code it is illegal to write to the originally const-qualified pointer
objects.

The rules of the Standard allow this situation for an internal call. I
see nothing to indicate that the function main() is conceptually unique,
other than that it's the program entry point. So there's nothing to
prevent an equivalent situation for an external call; hence without a
mention otherwise by the Standard, modifying argv is UB.
 
J

Jordan Abel

[within an arbitrary function, it can't be determined whether the
pointed-to objects of any non-const-qualified pointer parameters were
originally declared const]

Jordan Abel wrote:
But there's no reason to think that this has been done by whatever calls
main.

Irrelevant unless you can point to a specific prohibition against it or
something similar (i.e. analogous to string literals) for argv.


Eh?


For "it", substitute "passing a pointer to an object originally defined
with a const qualifier". I'm guessing as to where the misunderstanding
lies - that may clarify it. I interpreted the sentence to which I was
responding in a way that the same fragment could (inelegantly) also
substitute for "this".
I was asserting that you _can_ modify the array [as there is no
specific prohibition against doing so - as far as i can tell you are the
one who who needs to find a specific prohibition analogous to string
literals]

Try this code snippet for a thought experiment:

/* allocates memory and assigns argument strings and count */
char *const *init_new_args(int *new_argc);

int main(int argc, char **argv) {
int new_argc;
char *const *new_argv = init_new_args(&new_argc);
static int first_time = 1;
if (first_time--)
main(new_argc, (char **)new_argv);
/* else argv[0] = a_char_pointer; */ /* illegal attempt
to write to an object that was
defined with a const qualifier */
return 0;
}

On the internal call, main is passed an argv parameter that was defined
with const-qualified members (i.e. argv is non-modifiable). This const
qualifier has been (legally) cast away; nevertheless as commented in the
code it is illegal to write to the originally const-qualified pointer
objects.

The rules of the Standard allow this situation for an internal call.


I believe that for this to be allowed for values that "come from" the
depths of the library requires explicit permission [that is, for the
standard to say that the result, though a char *, may not be modified] -
there is such an explicit statement on getenv, for example. Anywhere
that a pointer non-const object of unknown origin is permitted to have
been cast from a const one, the standard has explicit language that
says this may be the case.
I see nothing to indicate that the function main() is conceptually
unique, other than that it's the program entry point. So there's
nothing to prevent an equivalent situation for an external call; hence
without a mention otherwise by the Standard, modifying argv is UB.
 
N

Netocrat

]
I believe that for this to be allowed for values that "come from" the
depths of the library requires explicit permission [that is, for the
standard to say that the result, though a char *, may not be modified] -
there is such an explicit statement on getenv, for example.

That's definitely a useful statement. If it weren't present though, then
modifying the string returned by getenv would be (implicit) UB anyway,
because the Standard would not be prohibiting an implementation from
returning an immutable string, therefore portable programs couldn't rely
on the string's mutability.

This doesn't apply to most other char* returning library functions (e.g.
in string.h) since the returned pointer points within an object whose
definition is under the programmer's control - or that was at least
provided to the function by the programmer.
 
J

Jordan Abel

]
I believe that for this to be allowed for values that "come from" the
depths of the library requires explicit permission [that is, for the
standard to say that the result, though a char *, may not be modified] -
there is such an explicit statement on getenv, for example.

That's definitely a useful statement. If it weren't present though, then
modifying the string returned by getenv would be (implicit) UB anyway,
because the Standard would not be prohibiting an implementation from
returning an immutable string, therefore portable programs couldn't rely
on the string's mutability.

But it only has to explicitly state it because itdoesn't return const
 
S

Stan Milam

bluejack said:
Naturally, with that mentality, I tend to code defensively. It would
never
even occur to me to *want* to change argv (or use gets). Still I do
find
these conversations fascinating, and I always enjoy the cranky
attitude found on usenet!

-bluejack

I code defensively too. However, the client I am working for is
implementing many C programs that access a database. The vendor
designed these programs to accept the database user login and password
on the command line. This is unfortunate because using the UNIX (it's a
UNIX operating system) ps command you can see the arguments, and the
client is security concious. As an experiment I wrote a function that
allocated a replacement array of pointers. To each element of the array
I allocated memory and copied the string, with the exception of argv[0].
I then went through the original array an null terminated each string
pointed to by argv with the exception of argv[0]. I then overlayed argv
with the copy of that I had made. Presto, all of the command line
arguments disappear when using the ps command, and the program still has
its own private copy of the arguments. Management was estatic.
However, I warned that this technique might not work on other UNIXes or
work with later releases of the UNIX they are using now. They didn't
care. Their immediate problem was solved.

Regards,
Stan Milam.
 
N

Netocrat

]
I believe that for this to be allowed for values that "come from" the
depths of the library requires explicit permission [that is, for the
standard to say that the result, though a char *, may not be modified]
- there is such an explicit statement on getenv, for example.

That's definitely a useful statement. If it weren't present though,
then modifying the string returned by getenv would be (implicit) UB
anyway, because the Standard would not be prohibiting an implementation
from returning an immutable string, therefore portable programs
couldn't rely on the string's mutability.

But it only has to explicitly state it because itdoesn't return const

It doesn't have to explicitly state it in either case, although it would
be more visibly redundant to state it if getenv() did return const.
Probably it doesn't return const for historical reasons and/or to make it
easy for an implementation to define the returned string as mutable if it
wants to.

You seem to genuinely object to the concept of implicit UB in general and
I can't see us finding mutual understanding without something more than
the brief back-and-forths thus far. So here's a "from first principles"
view of mutability which you may be able to use to identify your objection
more clearly:

Firstly we have 6.3.2.1#1 - which defines a "modifiable lvalue" as any
non-const-qualified object expression - and 6.5.16#2 - which defines the
assignment operators to require a modifiable lvalue as a target. The
other Standard-defined method of writing to an object is by passing its
address to a library function.

At this point[*], the programmer can without restriction write to
(almost[**]) any object by legally casting away any constness - there is
nothing to prevent the write methods from doing their (well-defined) jobs.
So if you were here to raise your claim that argv is modifiable in the
absence of other mention by the Standard, I'd say you'd have an arguable
point: the concept that an object may be immutable is thus far not even a
part of the universe of discourse.

Let's then discover 6.7.3#5 which makes it explicit UB to attempt to write
to an object whose definition is const-qualified, even if done through a
modifiable lvalue, and 6.4.5#6 which does the same for string literals.

/Now/ there exists the concept that "some objects are guaranteed to be
mutable, and others are not guaranteed (but may be anyway on any given
implementation)". At this point, we can only be assured that the write
methods will work portably for objects whose definition was neither
const-qualified nor a string literal. So we cannot be sure that it is
safe to write to any object whose definition we do not have access to, or
whose definition we are not supplied with - if the Standard doesn't
explicitly make it clear what applies for such objects then writing to
them is implicit UB.

Two such (Standard-mandated) objects are the elements argv and the
string returned as getenv()'s result, although as you've noted the
Standard helpfully makes the undefinedness of writing to the latter
explicit. It is, as stated earlier in the thread, curious that the
Standard does not do the same for argv - even though it wouldn't affect
the end result.

[*] meaning in reference to a version of the Standard with the clauses
later "discovered" excised

[**] the exception is register-qualified objects, whose address may not be
taken, so that:
*(T *)&const_register_object_of_type_T
will not work as it will for any non-register qualified object.
 
C

Chris Torek

... the client [wanted the arguments not to show up in "ps" output,
and saving-then-overwriting the argv data accomplished that].
Management was estatic. However, I warned that this technique
might not work on other UNIXes or work with later releases
of the UNIX they are using now. They didn't care. Their
immediate problem was solved.

For what it is worth (not all that much perhaps), your warning is
well-taken: it does not in fact work on some Unix variants. (There
is also a more subtle problem: even where it works, there is still
a race condition. The arguments can be captured by a "ps" command
at the right time.)

Still, for non-portable problems, non-portable solutions are
often appropriate.
 
D

DAGwyn

The answer to the original question is that of course the elements
of the array (of length equal to the value of main's int parameter)
pointed to by main's char** parameter can be modified. If we had
intended otherwise we would have used const qualification at the
appropriate position (between the *s) when specifying the interface.
 
K

Keith Thompson

DAGwyn said:
The answer to the original question is that of course the elements
of the array (of length equal to the value of main's int parameter)
pointed to by main's char** parameter can be modified. If we had
intended otherwise we would have used const qualification at the
appropriate position (between the *s) when specifying the interface.

Then why does 5.1.2.2.1p2 explicitly state that the program can modify
argc, argv, and the strings pointed to by the argv array, but not make
the same statement about the elements of the argv array? Was it just
an oversight?

There is precedent (string literals) for making something not
explicitly const, but not allowing it to be modified.

If you're correct, than an implementation that makes argv a pointer to
an array (of char*) in read-only memory (or at least memory that can't
be modified by the program) would be non-conforming, but it's not
quite obvious (to me) from the standard.

And Doug, if you're going to post through Google Groups, please read
<http://cfaj.freeshell.org/google/>. Thanks, and Merry Christmas.
 
D

David R Tribble

Keith said:
Then why does 5.1.2.2.1p2 explicitly state that the program can modify
argc, argv, and the strings pointed to by the argv array, but not make
the same statement about the elements of the argv array? Was it just
an oversight?

If you're correct, than an implementation that makes argv a pointer to
an array (of char*) in read-only memory (or at least memory that can't
be modified by the program) would be non-conforming, but it's not
quite obvious (to me) from the standard.

FWIW, I submitted a public comment on this issue (Feb 1998):
http://david.tribble.com/text/c9xc004.txt

I suggested that since no mention of the argv elements was made,
to add a sentence making it implementation-defined whether they
are modifiable or not.

At the time I submitted the comment, I believe there were systems
that did not allow argv to be modified, and it was not clear that
such systems were or were not conforming.

My comment was rejected, IIRC, because such verbiage was "not
necessary".

-drt
 
D

David R Tribble

Keith said:
Then why does 5.1.2.2.1p2 explicitly state that the program can modify
argc, argv, and the strings pointed to by the argv array, but not make
the same statement about the elements of the argv array? Was it just
an oversight?

FWIW, I submitted a public comment about that very issue
(Feb 1998):
http://david.tribble.com/text/c9xc004.txt

I suggested that it be deemed implementation-defined whether
or not argv is modifiable. My comment was rejected, IIRC,
because the extra verbiage was not necessary.

If you're correct, than an implementation that makes argv a pointer to
an array (of char*) in read-only memory (or at least memory that can't
be modified by the program) would be non-conforming, but it's not
quite obvious (to me) from the standard.

At the time I sumbitted my comment, there did exist systems that
did not allow modifying argv, and it was not clear whether or not
those systems were conforming.

-drt
 

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

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top