Opened 18 years ago

Closed 18 years ago

Last modified 15 years ago

#31 closed bug (fixed)

std::list iterator not dereferencable bug in the QgsUniqueValueDialog

Reported by: mloskot Owned by: gsherman
Priority: minor: annoyance Milestone:
Component: Map Legend Version: Trunk
Keywords: Cc:
Must Fix for Release: No Platform: Windows
Platform Version: XP Professional (SP2) Awaiting user input: no

Description

The Background:

The QgsUniqueValueRenderer::classificationAttributes() call returns a copy of the std::list<int> list:

std::list<int> QgsUniqueValueRenderer::classificationAttributes() const
{
    std::list<int> list;
    list.push_back(mClassificationField);
    return list;
}

There is no bug so far.

The constructor of QgsUniqueValueDialog class uses the classificationAttributes() in the following way:

std::list<int>::iterator iter = renderer->classificationAttributes().begin();
int classattr = *iter;

The Bug:

The serious bug occurs in the second line, where the iterator returned by the classificationAttributes() function is dereferenced:

int classattr = *iter;

According to the current ISO C++ Standard (draft), iter iterator is not dereferencable in that place, because the object of std::list<int> returned from the classificationAttributes() function is not available anymore. Simply, the usage of such iterator, after its parent object does not exist, causes undefined behaviour.

Where is this undefined behaviour?

std::list<int>::iterator iter = renderer->classificationAttributes().begin(); //<- [1]
int classattr = *iter; //<- [2]

In line (1), classificationAttributes() returns a list and this list is a temporary object. This object lives only untill the end of the full-expression in which the object was created. So, it lives only till the end of the line (1). After the semicolon ending the expression in line (1), the list object is destroyed. The iterator returned by begin() call in line (1) becomes referencing to not existing object. Next, in line (2) this iterator is dereferenced what causes undefined behaviour.

Here is what ISO C++ Standard says about temporary objects. This paragraph explains also why the list returned in the line (1) is destroyed.

12.2 Temporary objects

Temporary objects are destroyed as the last step in evaluating the full-expression (1.9) that (lexically) contains the point where they were created.

The statement undefined behaviour is very important here, because it explains why that buggy construction works with some compilers (like GCC) but with some it does not work (like VC++). Here is explanation of from ISO C++ Standard:

1.3.13 undefined behavior

(...)[Note: permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message). Many erroneous program constructs do not engender undefined behavior; they are required to be diagnosed. —end note]

There is no doubt this construction present in the constructor of QgsUniqueValueDialog causes undefined behaviuor.

Note: I grepped through all QGIS' .cpp files and then scanned all places where .begin() and .end() are used and I found two places where similar bug may occur, but I've not checked it yet. Here they are:

./plugins/gps_importer/qgsgpsplugin.cpp: iter != mQGisInterface->getLayerRegistry()->mapLayers().end(); ++iter) {
./plugins/gps_importer/qgsgpsplugin.cpp:  for (iter = mQGisInterface->getLayerRegistry()->mapLayers().begin();

Shortly, all places with so called chain access are suspicious and should be checked.

Attachments (1)

qgsuniguevaluedialog.cpp-undefined-behaviour-fix-mloskot-20060329.patch (671 bytes ) - added by mloskot 18 years ago.
Fix for std::list iterator not dereferencable bug

Download all attachments as: .zip

Change History (4)

by mloskot, 18 years ago

Fix for std::list iterator not dereferencable bug

comment:1 by timlinux, 18 years ago

Priority: blockerminor
Resolution: fixed
Status: newclosed

Fixed in Trunk version r5105

Thanks!

Tim

comment:2 by anonymous, 17 years ago

Awaiting user input: unset
Must Fix for Release: No

comment:3 by (none), 15 years ago

Milestone: Version 0.8

Milestone Version 0.8 deleted

Note: See TracTickets for help on using tickets.