Re: [PATCH v1] man/man7/environ.7: Fix underspecification of "name=value" strings
Alejandro Colomar <[email protected]> Tue, 7 Jul 2026 13:23:08 +0200
| Newsgroups | org.kernel.vger.linux-man |
|---|---|
| Message-ID | <akzfCMes6DT-DFDj@devuan> |
Hi Jason,
On 2026-07-07T06:54:49-0400, Jason Yundt wrote:
> On Mon Jul 6, 2026 at 11:27 AM EDT, Alejandro Colomar wrote:
> > Hi Jason,
> >
> > On 2026-07-06T10:26:20-0400, Jason Yundt wrote:
> >> Before this change, environ(7) said this:
> >>
> >> > By convention, the strings in environ have the form "name=value". The
> >> > name is case-sensitive and may not contain the character "=". The
> >> > value can be anything that can be represented as a string. The name
> >> > and the value may not contain an embedded null byte ('\0'), since this
> >> > is assumed to terminate the string.
> >>
> >> That description has a few problems:
> >>
> >> 1. It talks about ‘the character "="’, but it doesn’t specify what
> >> character encoding would be used to represent that character. Two
> >> different character encodings could represent that same “=” character
> >> using two different bytes (or even sequences of bytes).
> >
> > POSIX says that '=' is part of the portable character set.
>
> I don’t really think that '=' being a part of the POSIX Portable
> Character Set matters here. For one thing, environ(7) doesn’t mention
> the POSIX Portable Character Set at all. Even if it did, the POSIX
> Portable Character Set does not specify that the character encoding of
> '=' is 0x3D so it wouldn’t really help us.
Oh, I thought POSIX required ASCII-compatible encoding, but it seems I
was likely wrong.
> > Do we really need to care about the value of '='?
>
> There needs to be a specification somewhere that says what the character
> encoding would be. You can’t represent any characters on a computer
> without choosing a character encoding.
After reading the POSIX specification of putenv(3), I have some doubts.
putenv(3) is specified to use '=', not 0x3D. Thus, if working on a
system that uses a different value for '=', it seems that the
specification says that environ will still contain '=' in that encoding,
regardless of the value it has. In fact, reading the musl and glibc
implementations, they use '=', not 0x3D (maybe those libc
implementations don't support encodings of '=' that don't use 0x3D;
I don't know).
Have a lovely day!
Alex
> > Is this really possible?
>
> Definitely. Anyone can create whatever character encoding that they
> want to. There’s nothing that would force people to always encode the
> “=” character as 0x3D in every character encoding that they create.
> There are already character encodings in existence where “=” is not
> encoded as a 0x3D byte. For example, “=” is encoded as a 0x7E byte in
> EBCDIC [1].
>
> >
> >> 2. It mentions that ‘The name is case-sensitive and may not contain the
> >> character "=".’ It doesn’t clearly say what what is allowed to be in
> >> a name. It only says that those two things are explicitly
> >> disallowed.
> >
> > Anything else is allowed, obviously.
>
> I don’t think that the current wording clearly specifies what is allowed
> to be in a name. It’s definitely not obvious to me.
>
> >
> >> This change fixes those two problems. For the first problem, this
> >> change makes it so that the description is all about bytes, not
> >> characters. Describing the format in terms of bytes allows us to
> >> sidestep the question of character encoding entirely. Additionally, it
> >> is more accurate to describe strings in environ as being sequences of
> >> bytes instead of sequences of characters. Both the name and value of an
> >> environment variable could be sequences of bytes that don’t contain any
> >> characters at all.
> >>
> >> For the second problem, this change clarifies that the name of an
> >> environment variable can contain any byte except for 0x3D. It also
> >> clarifies that while it’s OK for environment variable values to be
> >> empty, it’s not OK for environment variable names to be empty.
> >>
> >> Additionally, this change replaces "=" with '='. In the C programming
> >> language, "=" refers to two bytes: one for the equals character plus one
> >> for the terminating null byte. In the C programming language, '='
> >> refers to a single byte. In this particular instance, we’re talking
> >> about a single byte, so it’s better to use '='. Using '=' also makes
> >> environ(7) more internally consistent. Before this change, environ(7)
> >> used '\0' and "=". This change makes it so that environ(7) uses '\0'
> >> and '='.
> >>
> >> I was able to obtain obtain the information that I needed in order to
> >> create this change by writing a test program. You can find the test
> >> program here [1]. Additionally, I got the information about the setenv(3)
> >> and unsetenv(3) functions from their man pages (specifically, the parts
> >> of their man pages that talk about EINVAL).
> >>
> >> [1]: <https://codeberg.org/JasonYundt/environ-format-example-program>
> >
> > Please include the C program in the commit message so that it can be
> > compiled and run easily, without having to understand Nix stuff.
>
> OK. I created a shorter version of the test code that’s available at
> that link. I have embedded the new shorter version in the commit
> message for the second version of this patch.
>
> >
> >>
> >> Signed-off-by: Jason Yundt <[email protected]>
> >> ---
> >> man/man7/environ.7 | 23 +++++++++++++++++------
> >> 1 file changed, 17 insertions(+), 6 deletions(-)
> >>
> >> diff --git a/man/man7/environ.7 b/man/man7/environ.7
> >> index 31a69017cf75..bf5726e32429 100644
> >> --- a/man/man7/environ.7
> >> +++ b/man/man7/environ.7
> >> @@ -28,12 +28,23 @@ .SH DESCRIPTION
> >> .I environ
> >> have the form
> >> .RI \[dq] name\f[B]=\f[]value \[dq].
> >> -The name is case-sensitive and may not contain
> >> -the character
> >> -.RB \[dq] = \[dq].
> >> -The value can be anything that can be represented as a string.
> >> -The name and the value may not contain an embedded null byte (\[aq]\[rs]0\[aq]),
> >> -since this is assumed to terminate the string.
> >
> > I liked the old wording about the terminating null byte more.
>
> OK. In the second version of this patch, I brought back the old wording
> about the terminating null byte.
>
> >
> >> +The name is case-sensitive
> >> +and may contain any byte
> >> +other than null (\[aq]\[rs]0\[aq]) and 0x3D (the
> >> +.BR ascii (7)
> >> +.RB \[aq] = \[aq]
> >> +character).
> >> +The name must be at least one byte long,
> >> +or else programs will not be able to manipulate it using the
> >> +.BR setenv (3)
> >> +or
> >> +.BR unsetenv (3)
> >> +functions.
> >> +Immediately after the name, there should be a 0x3D byte.
> >
> > What should readers interpret of 'should'? Is it a recommendation or an
> > obligation? This is unclear wording.
>
> OK. In the second version of this patch, I replaced the word “should”
> with the word “must”.
>
> >
> >> +Immediately after the 0x3D byte is the value.
> >
> > This seems redundant with the sentence that shows the format
> > "name=value".
>
> OK. In the second version of this patch, I got rid of that sentence.
>
> >
> >> +The value may contain any byte except for null.
> >
> > What is the null value? You mean an empty string? Or you mean embedded
> > null bytes in the string? Please clarify.
>
> When I wrote “The value may contain any byte except for null.”, I meant
> “The value may contain any byte except for the null byte.” That being
> said, I have removed that sentence from the second version of this
> patch.
>
> >
> >> +The value may be zero bytes long.
> >
> > That's commonly known as an empty string.
> >
> > I think saying that the value can be anything that can be represented as
> > a string is fine (the old wording).
>
> OK. In the second version of this patch, I got rid of the sentence “The
> value may be zero bytes long.”
>
> >
> >> +Immediately after the value, there must be a terminating null byte.
> >
> > The fact that it's a string already implied this.
>
> OK. In the second version of this patch, I got rid of the sentence
> “Immediately after the value, there must be a terminating null byte.”
>
> >
> >
> > Have a lovely day!
> > Alex
> >
> >> .P
> >> Environment variables may be placed in the shell's environment by the
> >> .I export
> >>
> >> Range-diff against v0:
> >> -: ------------ > 1: d5b0d9b86029 man/man7/environ.7: Fix underspecification of "name=value" strings
> >> --
> >> 2.54.0
> >>
> >>
>
> [1]: <https://en.wikipedia.org/wiki/Ebcidic#Code_page_layout>
--
<https://www.alejandro-colomar.es>
signature.asc
(application/pgp-signature, 833 B)
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEES7Jt9u9GbmlWADAi64mZXMKQwqkFAmpM4ZYACgkQ64mZXMKQ wqmYKQ//YSDVgPNID2pF/F2xEivzjEHn+lxUl8IKdZ9/Tj5H/MJdGi3HIl7GoVFV T0GKzrxx8O0xtqLngNSalMd6B9/xRR1+SrsEAVkZhIqr37kZefOpVp+XeXiFsrsg lScFU4+zCs7lYMiDrR4EvQ6lPTJTDC5fjLwBkV3t8TqQe5XEMc19tnqVEV97jBpG SRCFHBOuaHabp2vHX07XB4hZ2sOb5DTdD3PPu7QWCiexEwpRb8vVlRpg7DruHMY4 gebYAswgK99KXH8x5Du6g3TePb/nxiNG4bds5NYxozNiKwUxx0jYcGxWYira7R4R BcTAWGIBsvmQ67uyhjnFautQU9NGNltTT/jbHACAcNpoDaHi3jd8dZOZ0bSqHXK7 8tQfAugi6qssMQ1lHXothxPS7nTOU1NlBM6uxMTFWqqUqHx+c02RafZxQqS2Nk1+ qZnsVauDGkZO4LXSYGlMjTt+QWaT8peX8d4K2+biyD0fser87Ij+snUs8kpRnHYX quTJQb+AEYeSPGu7x43VTxYFJ875u04AAWef+9fqhNV2LUbj4LAJEYESiA/ORk6p anix4cPYza3SQbzy1AlBij2yxWDN6U8kh34gZ+mc9imVixwYu1xYyvDyHEYUZfe7 v7w+/X4i7s+AvgFiEOH7m4YOAU43JtNnIhvYk21PZWo0uE5vi04= =MQe2 -----END PGP SIGNATURE-----