You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 53 Next »

Associative containers place a strict weak ordering requirement on their key comparison predicates [ISO/IEC 14882-2014]. A strict weak ordering has the following properties:

  • For all xx < x == false (irreflexivity)
  • For all x, y: if x < y then !(y < x) (asymmetry)
  • For all xyz: if x < y && y < z then x < z (transitivity)

Providing an invalid ordering predicate for an associative container, or as a comparison criterion with the sorting algorithms, can result in erratic behavior or infinite loops [Meyers 01]. When an ordering predicate is required for an associative container or a generic standard template library algorithm, the predicate must meet the requirements for inducing a strict weak ordering.

Noncompliant Code Example

In this noncompliant code example, the std::set object is created with a comparator that does not adhere to the strict weak ordering requirement. Specifically, it fails to return false for equivalent values. As a result, the behavior of iterating over the results from std::set::equal_range results in unspecified behavior:

#include <functional>
#include <iostream>
#include <set>

void f() {
  std::set<int, std::less_equal<int>> S{5, 10, 20};  
  for (auto R = S.equal_range(10); R.first != R.second; ++R.first) {
    std::cout << *R.first << std::endl;
  }
}

Compliant Solution

This compliant solution uses the default comparator with std::set instead of providing an invalid one:

#include <iostream>
#include <set>

void f() {
  std::set<int> S{5, 10, 20};  
  for (auto R = S.equal_range(10); R.first != R.second; ++R.first) {
    std::cout << *R.first << std::endl;
  }
}

Noncompliant Code Example

In this noncompliant code example, the objects stored in the std::set have an overloaded operator< implementation, allowing the objects to be compared with std::less. However, the comparison operation does not provide a strict weak ordering. Specifically, the values 1, N and 1, M can result in a situation where comp(x, y) == comp(y, x), failing the asymmetry requirements.

#include <iostream>
#include <set>

class S {
  int I, J;

public:
  S(int I, int J) : I(I), J(J) {}
  
  friend bool operator<(const S &LHS, const S &RHS) {
    return LHS.I < RHS.I && LHS.J < RHS.J;
  }
  
  friend std::ostream &operator<<(std::ostream &OS, const S& O) {
    OS << "I: " << O.I << ", J: " << O.J;
    return OS;
  }
};

void f() {
  std::set<S> T{S(1, 1), S(1, 2), S(2, 1)};
  for (auto V : T) {
    std::cout << V << std::endl;
  }
}

Compliant Solution

This compliant solution uses std::tie() to properly implement the strict weak ordering operator< predicate:

#include <iostream>
#include <set>
#include <tuple>
 
class S {
  int I, J;
 
public:
  S(int I, int J) : I(I), J(J) {}
  
  friend bool operator<(const S &LHS, const S &RHS) {
    return std::tie(LHS.I, LHS.J) < std::tie(RHS.I, RHS.J);
  }
  
  friend std::ostream &operator<<(std::ostream &OS, const S& O) {
    OS << "I: " << O.I << ", J: " << O.J;
    return OS;
  }
};

void f() {
  std::set<S> T{S(1, 1), S(1, 2), S(2, 1)};  
  for (auto V : T) {
    std::cout << V << std::endl;
  }
}

Risk Assessment

Using an invalid ordering rule can lead to erratic behavior or infinite loops.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

CTR57-CPP

Low

Probable

High

P2

L3

Automated Detection

Tool

Version

Checker

Description

    

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Related Guidelines

Bibliography

[ISO/IEC 14882-2014]

Subclause 23.2.4, "Associative Containers"

[Meyers 01]Item 21, "Always Have Comparison Functions Return False for Equal Values"
[Sutter 05]Item 83, "Use a Checked STL Implementation"

 


  • No labels