Записать в файл имя функции, версию и параметр. Если с того момента исходный код функции изменился, вернуть сообщение что "версия функций не совпадают".
Например есть 100 функций. Для проверки имен и версии я думаю воспользоваться классом typeid
(в первый раз). Поэтому из функций делаю классы.
Пример как я думаю реализовать:
class Base { void f(int seed) = 0; }
class C1 : public Base { void f(int seed) override; }
class C2 : public Base { void f(int seed) override; }
// ...
class C100 : public Base { void f(int seed) override; }
void saveToFile(Base *b, int seed) {
// псевдокод. Открываю и записываю в файл
auto t = typeid(*b);
Fout << t.name() // имя функции
<< t.hash_code() // версия функции
<< seed; // параметр функции
}
void readFromFile(Base *b, int seed) {
// тут не знаю еще как делать.
}
Вопросы:
typeid()
для сохранения и сравнения типов классов?readFromFile
?UDP: ответ - нельзя использовать typeid()
. А как лучше сделать, что бы особо не запариваться. Что бы автоматически посчитать хеш функции/класса и сравнить имеются ли изменения. И желательно (но не обязательно) мультиплатформенность/на разных компиляторах
По моим тестам, в Visual C++ результат вывода type_info.hash_code()
не меняется при внесении изменений в код функций класса (он меняется только при изменении его имени). Так что идея уже сомнительная.
Хэш самого тела функции можно получить, скажем, как-то так:
#include <stdio.h>
#include <stdint.h>
#include <tchar.h>
#include <Windows.h>
#include <DbgHelp.h>
#pragma comment(lib, "Dbghelp.lib")
struct Function {
const char* name;
uint64_t addr;
unsigned int size;
bool success;
};
BOOL CALLBACK EnumSymProc(PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID context) {
Function* pfstruct = (Function*)context;
if (strcmp(pSymInfo->Name, pfstruct->name) == 0) {
pfstruct->addr = pSymInfo->Address;
pfstruct->size = SymbolSize;
pfstruct->success = true;
return FALSE; //закончить поиск
}
return TRUE; //продолжить поиск
}
bool GetFuncBounds(const char* fname, uint64_t& addr, unsigned int& size) {
bool ret;
Function fstruct;
fstruct.name = fname;
fstruct.size = 0;
fstruct.success = false;
HANDLE hProcess = GetCurrentProcess(); //текущий процесс
char Mask[] = "*!*";
BOOL status;
status = SymInitialize(hProcess, NULL, TRUE); //загрузка символов
if (status == FALSE)
{
printf("SymInitialize failed. Error code: 0x%x\n", (UINT)GetLastError());
return false;
}
//поиск символов
if (SymEnumSymbols(hProcess, 0, Mask, &EnumSymProc, (void*)&fstruct))
{
if (fstruct.success != false) {
//возвращаем адрес и размер функции
addr = fstruct.addr;
size = fstruct.size;
ret = true;
}
else {
printf("Symbol [%s] not found\n", fname);
ret = false;
}
}
else
{
printf("SymEnumSymbols failed. Error code: 0x%x\n", (UINT)GetLastError());
ret = false;
}
SymCleanup(hProcess);
return ret;
}
uint32_t GetMemHash(uint64_t addr, int size) {
uint32_t hash = 1234;
uint32_t k = 9870;
for (int i=0; i < size; i+=sizeof(uint32_t)) {
uint32_t* p = (uint32_t*)((char*)addr + i);
hash = hash * k + (*p);
}
hash += size;
return hash;
}
//**********************************
void Func() {
printf("Hello, World!\n");
}
int _tmain(int argc, _TCHAR* argv[])
{
uint64_t addr = 0;
unsigned int size = 0;
UINT hash;
if (GetFuncBounds("Func", addr, size)) {
hash = GetMemHash(addr, size);
printf("Hash: 0x%x\n", (UINT)hash);
}
else {
printf("Cannot calculate hash!\n");
}
getchar();
return 0;
}
Но я не думаю, что это поможет решить задачу. Значение этого хэша в большинстве случаев будет меняться даже при простой пересборке проекта без изменений, так как компилятор каждый раз генерирует новые адреса объектов, что приводит к различиям в машинном коде.
Как же решить задачу? Если вам нужно отслеживать изменения в исходном коде, то и зайти логичнее со стороны исходного кода. Сделайте, чтобы тело всех функций, изменения в которых надо отслеживать, было вынесено в отдельный файл, подключаемый через include. Напишите программу, которая будет считать хэши от содержимого этих файлов, и записывать результат в XML-файл. Прикрутите ее к вашим инструментам сборки (например, в Visual Studio - Custom build step), и распространяйте получаемый XML-файл с хэшами функций вместе с программой, тогда вы всегда можете определить, какая функция изменилась. Для проверки, что XML-файл действительно соответствует текущему бинарнику, можно включить в него и хэш от бинарника.
Насколько я понимаю typeid()
вычисляется на этапе компиляции, поэтому:
auto t = typeid(*b);
t
- будет всегда хранить данные о типе Base
.
Метод name
может возвращать разные имена при использование разных компиляторов.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Скажите пожалуйста, почему не появляется alert после заполнения формы и нажатия на кнопку
У меня есть элемент