encrypt/decrypt 的 Firebird 数据库 UDF 未释放内存
Firebird database UDF for encrypt/decrypt not freeing memory
我正在 Firebird 3 数据库中测试 UDF 外部函数,我制作了一个 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] = '[=11=]';
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] = '[=11=]';
try {
if ((str == NULL) || (str[0] == '[=11=]')) {
return NULL;
}
else {
try {
if ((key != NULL) && (key[0] == '[=11=]')) {
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] = '[=11=]';
try {
if ((str == NULL) || (str[0] == '[=11=]')) {
return NULL;
}
else {
try {
if ((key != NULL) && (key[0] == '[=11=]')) {
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';
在SQL select 命令中使用此UDF 时,firebird 服务器使用的ram 会不断增加。当使用嵌入式时,RAM 会快速增加,而在服务器模式下,RAM 会增加但缓慢且更受控制。
请大家帮忙看看哪里出错了
经过一些调查,我决定更改代码中复制字符串的部分:
strncpy(output, str, dataLen);
与:
strncpy_s(output, dataLen, str, dataLen);
并且经过这次改动后,无论是在嵌入式firebird还是在服务器模式下,内存都处于正常水平。
似乎是在释放或管理这些字符串副本时发生内存泄漏。
我正在 Firebird 3 数据库中测试 UDF 外部函数,我制作了一个 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] = '[=11=]';
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] = '[=11=]';
try {
if ((str == NULL) || (str[0] == '[=11=]')) {
return NULL;
}
else {
try {
if ((key != NULL) && (key[0] == '[=11=]')) {
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] = '[=11=]';
try {
if ((str == NULL) || (str[0] == '[=11=]')) {
return NULL;
}
else {
try {
if ((key != NULL) && (key[0] == '[=11=]')) {
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';
在SQL select 命令中使用此UDF 时,firebird 服务器使用的ram 会不断增加。当使用嵌入式时,RAM 会快速增加,而在服务器模式下,RAM 会增加但缓慢且更受控制。
请大家帮忙看看哪里出错了
经过一些调查,我决定更改代码中复制字符串的部分:
strncpy(output, str, dataLen);
与:
strncpy_s(output, dataLen, str, dataLen);
并且经过这次改动后,无论是在嵌入式firebird还是在服务器模式下,内存都处于正常水平。
似乎是在释放或管理这些字符串副本时发生内存泄漏。