UDF базы данных Firebird для шифрования / дешифрования, не освобождая память - PullRequest
3 голосов
/ 08 ноября 2019

Я тестирую внешнюю функцию UDF в базе данных Firebird 3, я создал C ++ DLL, которая выполняет простое XOR для заданной строки, используя заданный ключ.

Это код:

#include <windows.h>
#include <iostream>
#include <string>
#include <stdio.h>
#include <vector>
#include <math.h>

#include "../FirebirdLib/src/include/ibase.h"
#include "ib_util.h"


using namespace std;

//------------------------------------------------------------------------------------
typedef void (__stdcall * FCallback)(const char * message);
FCallback g_messageCallback = 0;
FCallback g_errorCallback = 0;
//------------------------------------------------------------------------------------
#define ON_MESSAGE(mess) { if(g_messageCallback) g_messageCallback(mess); }
#define ON_ERROR(mess) { if(g_errorCallback) g_errorCallback(mess); }
//------------------------------------------------------------------------------------
extern "C" __declspec(dllexport) void RegisterCallbacks(FCallback messageCallback, FCallback errorCallback)
{
    g_messageCallback = messageCallback;
    g_errorCallback = errorCallback;
}
//------------------------------------------------------------------------------------
class EncryptionUDF
{
public:
    EncryptionUDF()
    {

        //ON_MESSAGE("--EncryptionUDF created--")
    }
    ~EncryptionUDF()
    {
        //ON_MESSAGE("--EncryptionUDF destroyed--")
    }

    char* XORCipher(const char* data, const char* key, int dataLen, int keyLen) {
        char* output = (char*)ib_util_malloc(2000 + 1L);
        output[dataLen] = '\0';
        for (int i = 0; i < dataLen; ++i) {
            if (data[i] != key[i % keyLen])
                output[i] = data[i] ^ key[i % keyLen];
            else 
                output[i] = data[i];
        }       

        return output;
    }

    char * Encrypt(const char * str, const char * key) {
        int dataLen = strlen(str);
        int keyLen = strlen(key);
        char* output = (char*)ib_util_malloc(2000 + 1L);
        output[dataLen] = '\0';

        try {
            if ((str == NULL) || (str[0] == '\0')) {
                return NULL;
            }
            else {
                try {
                    if ((key != NULL) && (key[0] == '\0')) {
                        strncpy(output, str, dataLen);
                    }
                    else if (key != NULL) {
                        output = XORCipher(str, key, dataLen, keyLen);
                    }
                    else strncpy(output, str, dataLen);
                }
                catch (...) { strncpy(output, str, dataLen); }

                return output;
            }
        }
        catch (...) { strncpy(output, str, dataLen); }

        return output;
    }

    char * Decrypt(const char * str, const char * key) {
        int dataLen = strlen(str);
        int keyLen = strlen(key);
        char* output = (char*)ib_util_malloc(2000 + 1L);
        output[dataLen] = '\0';

        try {
            if ((str == NULL) || (str[0] == '\0')) {
                return NULL;
            }
            else {
                try {
                    if ((key != NULL) && (key[0] == '\0')) {
                        strncpy(output, str, dataLen);
                    }
                    else if (key != NULL) {
                        output = XORCipher(str, key, dataLen, keyLen);
                    }
                    else strncpy(output, str, dataLen);
                }
                catch (...) { strncpy(output, str, dataLen); }

                return output;
            }
        }
        catch (...) { strncpy(output, str, dataLen); }

        return output;
    }
};
//------------------------------------------------------------------------------------
extern "C" __declspec(dllexport) char * EncryptUDF_DesEncrypt(const char *str, const char *key)
{
    try
    {
        EncryptionUDF self = EncryptionUDF();
        return self.Encrypt(str, key);
    }
    catch (std::exception & ex)
    {
        ON_ERROR(ex.what());
    }
    catch (...)
    {
        ON_ERROR("Unknown error");
    }
    return 0;
}
//------------------------------------------------------------------------------------
extern "C" __declspec(dllexport) char * EncryptUDF_DesDecrypt(const char *str, const char *key)
{
    try
    {
        EncryptionUDF self = EncryptionUDF();
        return self.Decrypt(str, key);
    }
    catch (std::exception & ex)
    {
        ON_ERROR(ex.what());
    }
    catch (...)
    {
        ON_ERROR("Unknown error");
    }
    return 0;
}
//------------------------------------------------------------------------------------
BOOL APIENTRY DllMain( HMODULE hModule,
                      DWORD  ul_reason_for_call,
                      LPVOID lpReserved
                      )
{
    return TRUE;
}
//------------------------------------------------------------------------------------

UDF определяется в базе данных как:

DECLARE EXTERNAL FUNCTION X_DECRYPT
  CSTRING(2000),
  CSTRING(64)
RETURNS CSTRING(2000) FREE_IT
ENTRY_POINT 'EncryptUDF_DesDecrypt' MODULE_NAME 'EncryptUDF';

DECLARE EXTERNAL FUNCTION X_ENCRYPT
  CSTRING(2000),
  CSTRING(64)
RETURNS CSTRING(2000) FREE_IT
ENTRY_POINT 'EncryptUDF_DesEncrypt' MODULE_NAME 'EncryptUDF';

При использовании этого UDF в командах выбора SQL число оперативной памяти, используемое сервером firebird, имеет тенденцию к непрерывному увеличению. При использовании встроенного ОЗУ быстро увеличивается, а в режиме сервера ОЗУ увеличивается, но медленно и каким-то образом более управляемым.

Пожалуйста, помогите понять, где ошибка.

1 Ответ

2 голосов
/ 09 ноября 2019

После некоторого исследования я решил изменить части кода, куда копируется строка, используя:

strncpy(output, str, dataLen);

с:

strncpy_s(output, dataLen, str, dataLen);

, и после этого изменения памятьбыл на нормальном уровне, либо во встроенном Firebird, либо в режиме сервера.

Кажется, что произошла утечка памяти при выпуске или управлении этими строковыми копиями.

...