在分析第 3 方代码时,我遇到了一个 hack,它假设基类中的变量存储在与从它派生的类的另一个变量相邻的位置。派生类添加一个校验和变量和一个函数,该函数计算来自基类的数据的散列值与派生类中的校验和连接。
这个 hack 有效,但似乎不能依赖它所做的假设。 下面列出了说明这一点的删节代码(请参阅评论:“UGLY HACK!”):
template<unsigned int BYTES>
class BaseClass {
protected:
unsigned char xdata[BYTES];
public:
BaseClass() { memset(&xdata[0], 0, sizeof(xdata)); };
void FooFn() {};
unsigned char* BigFn() {};
};
template<unsigned int BYTES>
class DerivedClass : public BaseClass<BYTES> {
protected:
__int64 checksum;
__int64 CalcChecksum(unsigned char* pBegin, unsigned char* pEnd);
public:
DerivedClass();
void HashOfDataAndChecksum(unsigned __int64* outputhash);
};
//-----------------------------------------------------------------------
template<unsigned int BYTES>
__int64 DerivedClass<BYTES>::CalcChecksum(unsigned char* pBegin, unsigned char* pEnd) {
__int64 sum = 0;
while (pBegin++ < pEnd)
sum += *pBegin;
return ~sum;
}
template<unsigned int BYTES>
DerivedClass<BYTES>::DerivedClass() {
checksum = CalcChecksum(&BaseClass<BYTES>::xdata[0], &BaseClass<BYTES>::xdata[sizeof(BaseClass<BYTES>::xdata)]);
}
template<unsigned int BYTES>
void DerivedClass<BYTES>::HashOfDataAndChecksum(unsigned __int64* outputhash) {
int i;
unsigned char* pBegin = &BaseClass<BYTES>::xdata[0];
unsigned char* pEnd = (unsigned char*)(&checksum) + sizeof(checksum); //UGLY HACK! Works only if the checksum immediately follows xdata[] in memory.
unsigned char* x = pBegin;
while (x < pBegin + ( (pEnd-pBegin) & 0xFFFFFFFFFFFFFFC0) )
{
for (i = 0; i < 29; i++)
{
XCOMPRESS(x[0], x[8], x[16], x[24], x[32], x[40], x[48], x[56]);
XCOMPRESS(x[24], x[16], x[8], x[0], x[56], x[48], x[40], x[32]);
XCOMPRESS(x[32], x[48], x[0], x[16], x[24], x[40], x[56], x[8]);
XCOMPRESS(x[8], x[32], x[56], x[48], x[40], x[0], x[24], x[16]);
XCOMPRESS(x[48], x[40], x[56], x[0], x[32], x[24], x[16], x[8]);
XCOMPRESS(x[16], x[40], x[8], x[48], x[24], x[56], x[0], x[16]);
XCOMPRESS(x[56], x[48], x[24], x[16], x[8], x[0], x[32], x[40]);
XCOMPRESS(x[8], x[24], x[40], x[56], x[0], x[16], x[32], x[48]);
CROSS_NORMALIZE(&x[0]);
}
x += 64;
}
for (i=0; i < ((pEnd-pBegin) & (size_t)0x3f); i++ )
{
//A lot more hashing code
}
};
int main()
{
BaseClass<1048576> b;
assert(sizeof(b) == 1048576); //This must be true because the code that uses the BaseClass relies on sizeof() this way a lot.
DerivedClass<1048576> d;
assert( sizeof(d) == 1048576 + sizeof(__int64) ); //This must be true because the code that uses the DerivedClass relies on sizeof() to be the sum of the BaseClass and DerivedClass storages.
unsigned __int64 h[8];
d.FooFn(); //This function operates only on the xdata of the BaseClass
d.HashOfDataAndChecksum(&h[0]); //This function calculates a hash of the xdata in the BaseClass concatenated with the checksum in the DerivedClass
}
如何在不将扩展数据和校验和复制到相邻的第三个变量的情况下使这种黑客行为合法化? ...并且不修改散列算法或基类的大小?
最佳答案
我会使用 offsetof
并断言 checksum
的偏移量在预期的位置。您的代码可能会在任何地方按原样工作,但如果有人破坏了基类,您的代码可能不再工作。最安全的方法是艰难的。
关于c++ - 如何使假定派生类变量的相邻存储的黑客合法化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49656161/