Monday, January 10, 2011

Pantheios 1.0.1 beta 210 released: closing a vulnerability to badly written third-party libraries

The latest release of Pantheios - version 1.0.1 beta 210 - closes a vulnerability to implicit conversion of instances of fundamental types in the presence of badly-written third-party C++ libraries.

For reasons of robustness, Pantheios log statements do not accept instances of fundamental types - integers, floating-points, bool, char, and so on. Instead, users are advised to select from the set of stock inserter classes and functions provided with the library, or to define their own.

Consequently, and by design, statements such as the following will result in compilation errors:

  #include <pantheios/pantheios.hpp>

  pantheios::log_NOTICE("int: ", 10);

  pantheios::log_INFORMATIONAL("float: ", 1.23);

  pantheios::log_INFORMATIONAL("bool: ", true);

Instead, inserters should be used:

  #include <pantheios/pantheios.hpp>
  #include <pantheios/inserters/integer.hpp>
  #include <pantheios/inserters/real.hpp>
  #include <pantheios/inserters/boolean.hpp>

  pantheios::log_NOTICE("int: ", pantheios::integer(10));

  pantheios::log_INFORMATIONAL("float: ", pantheios::real(1.23));

  pantheios::log_INFORMATIONAL("bool: ", pantheios::boolean(true));

This can be expressed more succinctly by using namespace and inserter aliases:

  #include <pantheios/pan.hpp>
  #include <pantheios/inserters/i.hpp>
  #include <pantheios/inserters/real.hpp>
  #include <pantheios/inserters/b.hpp>

  pan::log_NOTICE("int: ", pan::i(10));

  pan::log_INFORMATIONAL("float: ", pan::real(1.23));

  pan::log_INFORMATIONAL("bool: ", pan::b(true));

Unfortunately, in the presence of ATL or MFC - or any other library that has conversion constructors and for which string access shims are defined - the former statements will compile and execute, but will not produce the expected output. Consider the following code:

#include <afx.h>
#include <pantheios/pan.hpp>

  pan::log_NOTICE("int: ", 10);

In a wide-string build in the presence of MFC, then rather than causing a compilation error, the 10 will actually be converted to an instance of CString, via the conversion constructor taking a TCHAR argument!

Obviously this is not desirable, particularly not for a diagnotic logging library! As of 1.0.1 beta 210, there are compile-time constraints in the application layer function templates - log(), log_DEBUG(), etc. - that cause a compile error if any argument is of fundamental type.


  1. I'm trying to circumvent this change in the latest code, and I tried defining PANTHEIOS_FORCE_ALLOW_FUNDAMENTAL_ARGUMENTS during compilation. (I'm using gcc 4.4 on Ubuntu server). But I'm afraid this hasn't worked for me. There are still many compile-time errors. I tried backing up to older versions of Pantheios (beta 209) and STLSoft (beta 105) and surprisingly that didn't work either.

    /var/pantheios/pantheios-1.0.1-beta209/include/pantheios/./internal/generated/log_functions.hpp: In function "int pantheios::log(pantheios::pan_sev_t, const T0&) [with T0 = int]":
    testpan.cpp:84: instantiated from here
    /var/pantheios/pantheios-1.0.1-beta209/include/pantheios/./internal/generated/log_functions.hpp:41: error: call of overloaded "c_str_len_a(const int&)" is ambiguous

    The same error is given for all versions I've tried, and it appears there is no c_str_len_a (or data counterpart) that accepts fundemental types. How can this be?

  2. By design, Pantheios does not allow fundamental type arguments: this is because (i) there is no clear agreed format that should be used as a default for some types, and, more importantly, (ii) the implicit conversions supported by C++ mean that there are ambiguities between different fundamental types and between user-defined types with implicit conversion operators and fundamental types.

    This is "by design" because it is imperative that a diagnostic logging library does not facilitate the writing of failing or unpredictable log statements.

    As a consequence, fundamental types are not supported directly, by virtue of there being no Pantheios (or STLSoft) string access shims. Furthermore, the use is proscribed by the Pantheios application layer via the mechanism suppressed by the PANTHEIOS_FORCE_... symbol you've defined.

    This allows you to define and use your own string access shims, but the *strong* recommendation is that you use the inserters for the particular fundamental types you want to use, e.g.


    int v = 42;

    pan::log_DEBUG("i = ", pan::i(v));