编译器:让我们和编译器一起做游戏吧



搞挂编译器是件很有趣事情编译死循环便是其中的让我们和编译器起做游戏吧~

1、Preprocess

a、Self Include(GCC _disibledevent=>};


不过利用VC某个bug(或者说特性)可以很容易写出O(na)编译时间模版:

# <cstddef>

# INNER(A3,N3,A2,N2) \
template<size_t N3>\
struct A3\
{\
enum {N=A3<N3-1>::N+1};\
};\
template<>\
struct A3<0>\
{\
enum {N=A2<N2-1>::N};\
};

# OUTER(A2,N2,A1,N1,A3,CONTENT) \
template<size_t N2>\
struct A2\
{\
CONTENT\
\
enum {N=A3<N2>::N};\
};\
template<>\
struct A2<0>\
{\
enum {N=A1<N1-1>::N};\
};

# LEVEL2(a,b,c) INNER(A##b,N##b,A##a,N##a)
# LEVEL3(a,b,c) OUTER(A##b,N##b,A##a,N##a,A##c,LEVEL2(a##1,b##1,c##1))
# LEVEL4(a,b,c) OUTER(A##b,N##b,A##a,N##a,A##c,LEVEL3(a##1,b##1,c##1))
# LEVEL5(a,b,c) OUTER(A##b,N##b,A##a,N##a,A##c,LEVEL4(a##1,b##1,c##1))

template<size_t N1>
struct A1
{
LEVEL5(1,11,111)
enum {N=A11<N1>::N};
};
template<>
struct A1<0>
{
enum {N=0};
};


{
Evil<100> evil;
}


这里比较有趣点是标准并不允许这样在模版类里特化不知道这个算VCbug呢还是扩展呢?

A member or a member template may be nested within many enclosing templates. In an explicit specialization for such a member, the member declaration shall be preceded by a template<> for each enclosing template that is explicitly specialized

基于类似思想GCC&VC通用版本也不难写出

# INNER(A3,N3) \
template< N3>\
struct A3\
{\
void f {}\
};

# OUTER(A2,N2,A1,CONTENT) \
template< N2>\
struct A2\
{\
CONTENT\
\
void f {\
A1<char>::f;\
A1<>::f;\
A1<>::f;\
A1<long>::f;\
A1<unsigned char>::f;\
A1<unsigned >::f;\
A1<unsigned >::f;\
A1<unsigned long>::f;\
}\
};

# LEVEL2(a,b) INNER(A##a,T##a)
# LEVEL3(a,b) OUTER(A##a,T##a,A##b,LEVEL2(a##1,b##1))
# LEVEL4(a,b) OUTER(A##a,T##a,A##b,LEVEL3(a##1,b##1))
# LEVEL5(a,b) OUTER(A##a,T##a,A##b,LEVEL4(a##1,b##1))
# LEVEL6(a,b) OUTER(A##a,T##a,A##b,LEVEL5(a##1,b##1))
# LEVEL7(a,b) OUTER(A##a,T##a,A##b,LEVEL6(a##1,b##1))
# LEVEL8(a,b) OUTER(A##a,T##a,A##b,LEVEL7(a##1,b##1))

LEVEL8(1,11)


{
A1<>::f;
}


b、多重继承

C中允许多重继承因此结合模板可以轻松搞挂编译器比如下面Fibonacci继承

template<size_t N>
Evil:virtual public Evil<N-1>,virtual public Evil<N-2>
{
public:
virtual ~Evil {}
};

template<>
Evil<1>
{
};
template<>
Evil<0>
{
};


{
Evil<100> evil;
}


c、OLE

虽然通常模版编译时间都是O(n)不过很多编译器信息输出却是O(n2)利用这点+很长类名很容易造成信息Output Limit Exceed比如:



# ClassName A

template < N>
ClassName
{
enum {Value=ClassName<N-1>::Value};
};


{
n=ClassName<0>::Value;
}


如果我把ClassName改成某个很长名称(现代编译器都支持很长变量名)那么输出就很容易OLE

PS:上面代码在VC8里会直接出ICE不过这是VC8bugVC2008没有这样问题

Tags:  c编译器 c语言编译器 java编译器 编译器

延伸阅读

最新评论

发表评论