Handling argc==0 in the kernel
Handling argc==0 in the kernel
Posted Jan 31, 2022 19:10 UTC (Mon) by marcH (subscriber, #57642)In reply to: Handling argc==0 in the kernel by jem
Parent article: Handling argc==0 in the kernel
Yes and that would be very ironic in an article about a pkexec security issue caused by not using argc as termination and fixed by looking at it :-)
Anyway comparing termination in C versus all other programming languages was not my point. Using _both_ argc and NULL at the same time is idiomatic in exactly zero programming language, so that's confusing. So I'm merely suggesting adding one short sentence about that.
Posted Jan 31, 2022 19:42 UTC (Mon)
by nybble41 (subscriber, #55106)
[Link] (4 responses)
One could equally well cast this issue as "caused by not checking the first element of the array for the NULL terminator". It's exactly the same error as if you received a NUL-terminated string and started iterating over it from the second element, assuming the string to be non-empty.
I'm in the Pascal-style string/list camp myself—lengths should be explicit—but using argc instead of checking for NULL is neither necessary nor sufficient to avoid this problem. (To illustrate the latter, consider the case of a program making the same non-empty argv assumption and using a loop of the form "int i = 1; do { ... } while (i++ < argc)" to shave off a "redundant" bounds check.)
Posted Jan 31, 2022 19:57 UTC (Mon)
by marcH (subscriber, #57642)
[Link] (3 responses)
It's "exactly the same" only if your termination looks like "i != argc" but no one ever does that. Everyone does "i < argc" or something like it. I mean no one writes:
for (int i; i++; i!=argc)
> but using argc instead of checking for NULL is neither necessary nor sufficient to avoid this problem.
I haven't looked at the actual code but if pkexec's loop had used an argc-based termination then the loop would have not run at all.
> int i = 1; do { ... } while (i++ < argc)" to shave off a "redundant" bounds check.)
That's bending over backwards to avoid a simpler for loop. I'm sure you can find some real world and valid cases for this but most of the time people just write a simpler for loop.
Posted Jan 31, 2022 22:19 UTC (Mon)
by marcH (subscriber, #57642)
[Link]
Of course I meant no one writes this:
for (int i=start; i!=argc; i++)
Sorry for the noise.
Posted Feb 1, 2022 1:58 UTC (Tue)
by NYKevin (subscriber, #129325)
[Link] (1 responses)
Maybe not in C, but C++ tacitly encourages this sort of nonsense because iterators are not, strictly speaking, required to be ordered (for example, a linked-list iterator may only be comparable for equality, because there is no O(1) way of ordering two iterators). So if you're taking C++ code and porting it to straight C, the most straightforward translation of a foreach loop is to use an inequality comparison instead of a less-than comparison, and it's possible that some programmers who started out as C++ programmers and later learned C may have picked this up as an idiom.
(Incidentally, these people also tend to favor the preincrement operator over the postincrement operator in contexts where there's no semantic difference, because in C++, postincrement can be significantly costlier due to the need to make a copy.)
Posted Feb 1, 2022 12:59 UTC (Tue)
by madscientist (subscriber, #16861)
[Link]
Also even in C, old-school programmers preferred pre-increment because post-increment was less efficient. Of course it was hard to detect that inefficiency, but it was a peg to hang one's preferential hat on and that's all that's needed when faced with two essentially equivalent choices. In C++ with operator overloading it can be measurably less efficient, of course, depending on the type implementation.
Handling argc==0 in the kernel
Handling argc==0 in the kernel
Handling argc==0 in the kernel
Handling argc==0 in the kernel
>
> for (int i; i++; i!=argc)
Handling argc==0 in the kernel