[devel] [APT PATCH] rpmSingle{Pkg, Src}Index::ArchiveURI(): avoid cases with undefined behavior

Ivan Zakharyaschev imz на altlinux.org
Пн Фев 17 03:39:34 MSK 2020


On Sun, 16 Feb 2020, Dmitry V. Levin wrote:

> On Sun, Feb 16, 2020 at 04:09:14AM +0300, Ivan Zakharyaschev wrote:

> > * File.length() < 2. Since File was a non-const string,
> >   File[File.length()] might be UB before C++11. Now, File is const, and
> >   it is guaranteed that File[File.length()] == 0.
> 
> We can safely assume C++11, but I don't think we have an UB here even
> before C++11.

FWIW, after thinkng over the corresponding piece[1] which you cited (a 
third time):

[1]: https://en.cppreference.com/w/cpp/string/basic_string/operator_at

> reference       operator[]( size_type pos );(1)
> const_reference operator[]( size_type pos ) const;(2)
> 
> Returns a reference to the character at specified location pos. [...]
> 
> 1) If pos == size(), the behavior is undefined.
> 2) If pos == size(), a reference to the character with value CharT() 
> (the null character) is returned.
> 
> (until C++11)

I can see a reason to agree with you: whether the object is const might 
not be the thing that determines which variant of the method is used.

The question was whether variant (1) or (2) was used here in
(File[1] == '/') if File was not const.

(If (1) is used, it is stated that it would be UB until C++11; if (2), 
then not.)

I doubt I'm able remember all the details of how the choice is done 
between overloaded methods, but common sense gives a hint: only methods 
labelled "const" can be invoked on a const object whereas all methods 
(both labelled "const" and not) can be invoked on a non-const object.

Under this view, we see that the methods labelled "const" are equally well 
available for non-const objects. So, another factor must make the choice 
between (1) and (2).

And here the only remaining factor seems to be the expected result 
type/constness in the expression where it is used (although that might 
seem weird because of its "implicitness"): a const reference will do for 
(_ == '/'), so (2) is probably inferred under the hood as the variant to 
use here.

Of course, I might be wrong in my reasoning, and it's not quite important 
for this place in APT's code anymore anyway (as there was another reason 
to rewrite it), but I wished to share this curiosity regarding how the 
meaning of C++ code can be non-obvious to mere mortals (like me).

-- 
Best regards,
Ivan


Подробная информация о списке рассылки Devel