该代码中 std::bad_alloc 的原因是什么?
What is the reason of std::bad_alloc in that code?
最近我写了那个代码,我注意到这里某处导致
terminate called after throwing an instance of 'std::bad_alloc' what(): std::bad_alloc
这是我的代码:
namespace logger {
set<string> pendingLogs;
bool isDebugEnabled = false;
mutex logMutex;
inline void add_log_to_pending(const string &text) {
lock_guard<mutex> guard(logMutex);
cout << "[Logger] Adding: " << text << endl;
pendingLogs.insert(text);
}
inline string grab_logs() {
string collector;
lock_guard<mutex> guard(logMutex);
if (pendingLogs.empty()) return collector;
for (const auto& item: pendingLogs) {
collector += item + "\n";
}
pendingLogs.clear();
return collector;
}
}
起始线程代码:
std::thread log_composer_thread(&log_composer_callable);
log_composer_thread.detach();
函数线程代码:
[[noreturn]] void log_composer_callable() {
logger::log_debug("Log composer thread started..");
while (true) {
const string &logs = logger::grab_logs();
if (logs.empty()) {
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
continue;
}
//send logic
}
}
是什么导致了这里的错误?我虽然它与 curl 库有关但是当我 禁用 整个日志记录逻辑时,所有错误都消失了所以这就是为什么我认为错误在记录器代码中的某个地方
编辑 1:
inline std::vector<unsigned char>
rsa_encrypt_pubkey(EVP_PKEY *pubKey, unsigned char *toEncrypt, size_t toEncryptLength, bool eraseInputArray) {
size_t outlen;
if (toEncryptLength > 256) {
logger::add_log_to_pending("Error: rsa_encrypt_pubkey: toEncryptLength > 256");
return {};
}
//init the cipher context for encryption using the public key
EVP_PKEY_CTX *enc_ctx = EVP_PKEY_CTX_new(pubKey, nullptr);
EVP_PKEY_encrypt_init(enc_ctx);
EVP_PKEY_CTX_set_rsa_padding(enc_ctx, RSA_PKCS1_OAEP_PADDING);
EVP_PKEY_CTX_set_rsa_oaep_md(enc_ctx, EVP_sha256());
//determine output length
if (!EVP_PKEY_encrypt(enc_ctx, nullptr, &outlen, toEncrypt, toEncryptLength)) {
logger::add_log_to_pending("Error: EVP_PKEY_encrypt | " + string(ERR_error_string(ERR_get_error(), nullptr)));
return {};
}
std::vector<unsigned char> encrypted(outlen);
#if debug_mode_advanced == 1
cout << "Output length: " << outlen << " toEncryptLenght: " << toEncryptLength << endl;
cout << ERR_error_string(ERR_get_error(), nullptr) << endl;
#endif
//final encrypt call
if (!EVP_PKEY_encrypt(enc_ctx, &encrypted[0], &outlen, toEncrypt, toEncryptLength)) {
logger::add_log_to_pending("Error: EVP_PKEY_encrypt | " + string(ERR_error_string(ERR_get_error(), nullptr)));
return {};
}
//clean up
EVP_PKEY_CTX_free(enc_ctx);
if (eraseInputArray) free(toEncrypt);
return encrypted;
}
那个代码导致了问题,这里可能是什么问题?
编辑 2:
inline vector<unsigned char>
rsa_encrypt_rewrite(unsigned char *in, size_t inlen, EVP_PKEY *key, bool eraseInputArray) {
try {
EVP_PKEY_CTX *ctx;
ENGINE *eng;
unsigned char *out;
size_t outlen;
if (inlen > 256) {
logger::add_log_to_pending("Error: rsa_encrypt_pubkey: toEncryptLength > 256");
return {};
}
ctx = EVP_PKEY_CTX_new(key, eng);
if (!ctx) {
logger::add_log_to_pending(
"Error: EVP_PKEY_CTX_new | " + string(ERR_error_string(ERR_get_error(), nullptr)));
return {};
}
/* Error occurred */
if (EVP_PKEY_encrypt_init(ctx) <= 0) {
logger::add_log_to_pending(
"Error: EVP_PKEY_encrypt_init | " + string(ERR_error_string(ERR_get_error(), nullptr)));
return {};
}
/* Error */
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0) {
logger::add_log_to_pending(
"Error: EVP_PKEY_CTX_set_rsa_padding | " + string(ERR_error_string(ERR_get_error(), nullptr)));
return {};
}
/* Error */
/* Determine buffer length */
if (EVP_PKEY_encrypt(ctx, nullptr, &outlen, in, inlen) <= 0) {
logger::add_log_to_pending(
"Error: EVP_PKEY_encrypt | " + string(ERR_error_string(ERR_get_error(), nullptr)));
return {};
}
/* Error */
out = (unsigned char *) OPENSSL_malloc(outlen);
if (!out) {
logger::add_log_to_pending("Error: OPENSSL_malloc");
return {};
}
/* malloc failure */
if (EVP_PKEY_encrypt(ctx, out, &outlen, in, inlen) <= 0) {
logger::add_log_to_pending(
"Error: EVP_PKEY_encrypt | " + string(ERR_error_string(ERR_get_error(), nullptr)));
return {};
}
EVP_PKEY_CTX_free(ctx);
if (eraseInputArray) free(in);
vector<unsigned char> encrypted(out, out + outlen);
OPENSSL_free(out);
return encrypted;
} catch (const std::exception &e) {
logger::add_log_to_pending("Error: rsa_encrypt_rewrite general exception: " + string(e.what()));
return {};
}
}
那个代码好像没问题吧?而且bad_alloc不应该出现?
看起来问题出在这部分代码中:
if (!EVP_PKEY_encrypt(enc_ctx, nullptr, &outlen, toEncrypt, toEncryptLength)) {
logger::add_log_to_pending("Error: EVP_PKEY_encrypt | " + string(ERR_error_string(ERR_get_error(), nullptr)));
return {};
}
std::vector<unsigned char> encrypted(outlen);
考虑到 EVP_PKEY_encrypt()
也可能 return 一个 负值 错误值。你把所有不为零的都视为成功。然而,如果它失败了,outlen
可能没有正确初始化,在这种情况下它可能持有一个巨大的数字,导致 encrypted
的构造函数 运行 内存不足,抛出 std::bad_alloc
.
最近我写了那个代码,我注意到这里某处导致
terminate called after throwing an instance of 'std::bad_alloc' what(): std::bad_alloc
这是我的代码:
namespace logger {
set<string> pendingLogs;
bool isDebugEnabled = false;
mutex logMutex;
inline void add_log_to_pending(const string &text) {
lock_guard<mutex> guard(logMutex);
cout << "[Logger] Adding: " << text << endl;
pendingLogs.insert(text);
}
inline string grab_logs() {
string collector;
lock_guard<mutex> guard(logMutex);
if (pendingLogs.empty()) return collector;
for (const auto& item: pendingLogs) {
collector += item + "\n";
}
pendingLogs.clear();
return collector;
}
}
起始线程代码:
std::thread log_composer_thread(&log_composer_callable);
log_composer_thread.detach();
函数线程代码:
[[noreturn]] void log_composer_callable() {
logger::log_debug("Log composer thread started..");
while (true) {
const string &logs = logger::grab_logs();
if (logs.empty()) {
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
continue;
}
//send logic
}
}
是什么导致了这里的错误?我虽然它与 curl 库有关但是当我 禁用 整个日志记录逻辑时,所有错误都消失了所以这就是为什么我认为错误在记录器代码中的某个地方
编辑 1:
inline std::vector<unsigned char>
rsa_encrypt_pubkey(EVP_PKEY *pubKey, unsigned char *toEncrypt, size_t toEncryptLength, bool eraseInputArray) {
size_t outlen;
if (toEncryptLength > 256) {
logger::add_log_to_pending("Error: rsa_encrypt_pubkey: toEncryptLength > 256");
return {};
}
//init the cipher context for encryption using the public key
EVP_PKEY_CTX *enc_ctx = EVP_PKEY_CTX_new(pubKey, nullptr);
EVP_PKEY_encrypt_init(enc_ctx);
EVP_PKEY_CTX_set_rsa_padding(enc_ctx, RSA_PKCS1_OAEP_PADDING);
EVP_PKEY_CTX_set_rsa_oaep_md(enc_ctx, EVP_sha256());
//determine output length
if (!EVP_PKEY_encrypt(enc_ctx, nullptr, &outlen, toEncrypt, toEncryptLength)) {
logger::add_log_to_pending("Error: EVP_PKEY_encrypt | " + string(ERR_error_string(ERR_get_error(), nullptr)));
return {};
}
std::vector<unsigned char> encrypted(outlen);
#if debug_mode_advanced == 1
cout << "Output length: " << outlen << " toEncryptLenght: " << toEncryptLength << endl;
cout << ERR_error_string(ERR_get_error(), nullptr) << endl;
#endif
//final encrypt call
if (!EVP_PKEY_encrypt(enc_ctx, &encrypted[0], &outlen, toEncrypt, toEncryptLength)) {
logger::add_log_to_pending("Error: EVP_PKEY_encrypt | " + string(ERR_error_string(ERR_get_error(), nullptr)));
return {};
}
//clean up
EVP_PKEY_CTX_free(enc_ctx);
if (eraseInputArray) free(toEncrypt);
return encrypted;
}
那个代码导致了问题,这里可能是什么问题?
编辑 2:
inline vector<unsigned char>
rsa_encrypt_rewrite(unsigned char *in, size_t inlen, EVP_PKEY *key, bool eraseInputArray) {
try {
EVP_PKEY_CTX *ctx;
ENGINE *eng;
unsigned char *out;
size_t outlen;
if (inlen > 256) {
logger::add_log_to_pending("Error: rsa_encrypt_pubkey: toEncryptLength > 256");
return {};
}
ctx = EVP_PKEY_CTX_new(key, eng);
if (!ctx) {
logger::add_log_to_pending(
"Error: EVP_PKEY_CTX_new | " + string(ERR_error_string(ERR_get_error(), nullptr)));
return {};
}
/* Error occurred */
if (EVP_PKEY_encrypt_init(ctx) <= 0) {
logger::add_log_to_pending(
"Error: EVP_PKEY_encrypt_init | " + string(ERR_error_string(ERR_get_error(), nullptr)));
return {};
}
/* Error */
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0) {
logger::add_log_to_pending(
"Error: EVP_PKEY_CTX_set_rsa_padding | " + string(ERR_error_string(ERR_get_error(), nullptr)));
return {};
}
/* Error */
/* Determine buffer length */
if (EVP_PKEY_encrypt(ctx, nullptr, &outlen, in, inlen) <= 0) {
logger::add_log_to_pending(
"Error: EVP_PKEY_encrypt | " + string(ERR_error_string(ERR_get_error(), nullptr)));
return {};
}
/* Error */
out = (unsigned char *) OPENSSL_malloc(outlen);
if (!out) {
logger::add_log_to_pending("Error: OPENSSL_malloc");
return {};
}
/* malloc failure */
if (EVP_PKEY_encrypt(ctx, out, &outlen, in, inlen) <= 0) {
logger::add_log_to_pending(
"Error: EVP_PKEY_encrypt | " + string(ERR_error_string(ERR_get_error(), nullptr)));
return {};
}
EVP_PKEY_CTX_free(ctx);
if (eraseInputArray) free(in);
vector<unsigned char> encrypted(out, out + outlen);
OPENSSL_free(out);
return encrypted;
} catch (const std::exception &e) {
logger::add_log_to_pending("Error: rsa_encrypt_rewrite general exception: " + string(e.what()));
return {};
}
}
那个代码好像没问题吧?而且bad_alloc不应该出现?
看起来问题出在这部分代码中:
if (!EVP_PKEY_encrypt(enc_ctx, nullptr, &outlen, toEncrypt, toEncryptLength)) {
logger::add_log_to_pending("Error: EVP_PKEY_encrypt | " + string(ERR_error_string(ERR_get_error(), nullptr)));
return {};
}
std::vector<unsigned char> encrypted(outlen);
考虑到 EVP_PKEY_encrypt()
也可能 return 一个 负值 错误值。你把所有不为零的都视为成功。然而,如果它失败了,outlen
可能没有正确初始化,在这种情况下它可能持有一个巨大的数字,导致 encrypted
的构造函数 运行 内存不足,抛出 std::bad_alloc
.