boost::python::objects::iterator_range::next::operator() might return reference to temporary object
- Linguagem predominante
- C++
- Estrelas
- 537
- Forks
- 223
- Merge médio
- 11h 22min
- PRs com merge (30d)
- 2
Descrição
`iterator_range` in boost/python/object/iterator.hpp defines an inner class called `next` which defines `operator()` (see https://github.com/boostorg/python/blob/develop/include/boost/python/object/iterator.hpp#L44). Here is the implementation:
```
result_type
operator()(iterator_range& self)
{
if (self.m_start == self.m_finish)
stop_iteration_error();
return *self.m_start++;
}
```
The last line is a potential problem as a temporary object (the return value of `self.m_start++`) is dereferenced. If `result_type` is a reference (meaning `operator()` returns a reference) and the dereferenced temporary object returns a reference to something within the temporary object, you get a dangling reference.
Here is how `result_type` is determined:
```
typedef boost::detail::iterator_traits traits_t;
typedef typename mpl::if_<
is_reference<
typename traits_t::reference
>
, typename traits_t::reference
, typename traits_t::value_type
>::type result_type;
```
In general this code looks good. However it implies that if a reference is returned, the reference does not refer to something in the iterator (as with the current implementation the iterator is a temporary object).
Here is an attempt to fix `operator()`:
```
result_type
operator()(iterator_range& self)
{
if (self.m_start == self.m_finish)
stop_iteration_error();
self.m_current = self.m_start++;
return *self.m_current;
}
```
Here an additional member variable called `m_current` is used to turn the temporary object returned by `self.m_start++` into something which lives longer. I tested this fix, and it seems to work. However I didn't test it thoroughly (for example, I don't know when and where Boost.Python creates copies of `iterator_range`; if you have a reference to something within a member variable, the member variable better doesn't change its location in memory :).
A valid question is of course whether this is a Boost.Python issue. First, I'm opening this ticket to document this issue (for others and also for myself ;). Secondly, I would be already happy if Boost.Python somehow supports me detecting this issue at compile-time (I'm fine if I get a compiler error and know I need to work around something). Thirdly, I'm working with a third-party library where iterators return references to something within iterators - it's easier for me to fix Boost.Python than all the iterators in the third-party library.
Guia de contribuição
Nenhum guia de contribuição indexado para este repositório
Direção de pesquisa
Comece em include/boost/python/object/iterator.hpp, em iterator_range::next::operator(), e inspecione como result_type, o pós-incremento e as cópias do iterador afetam o tempo de vida das referências. Reproduza o caso com um iterador cujo pós-incremento retorna um temporário e determine então se o comportamento suportado deve impedir referências pendentes ou expor uma limitação em tempo de compilação; considera-se concluído quando houver uma resolução documentada e cobertura de regressão.
Escrita pelo modelo de indexação a partir do texto da issue.
Avaliação
- Stack de tecnologia
- cpp
- Domínio
- api
- Tipo de issue
- Bug
- Dificuldade
- 5/5
- Tempo estimado
- Mais de uma semana
- Status de atividade
- Estagnada
- Clareza
- Razoavelmente clara
- Facilidade para iniciantes
- 35/100