Есть ли плохое взаимодействие между gtest и cstdarg, или я действительно пропускаю разбивку стека здесь?

Мой код ниже предназначен для простой системы регистрации ошибок, которая ведет себя так же, как printf.

Весь мой код работал нормально в среде gtest, но теперь, когда я выхожу из детерминированной точки в программе (один из моих тестов), она ломается. Мой код работал нормально, пока я не написал это, и это мой первый набег на cstdarg, так что это наиболее подозрительно.

MyMutex error_lock;

#define MAX_ERR_MSG_SIZE 128
#define MAX_ERRORS 3
class ErrorQueue
{
std::queue<char*> errors;
std::list<char*> old_errors;
public:
void push(char * msg)
{
if (errors.size() >= MAX_ERRORS)
{
pop();
}
errors.push(msg);
}

void pop()
{
if (old_errors.size() >= MAX_ERRORS)
{
delete [] old_errors.front();
old_errors.pop_front();
}
old_errors.push_back(errors.front());
errors.pop();
}

char * front()
{
return errors.front();
}

size_t size()
{
return errors.size();
}

~ErrorQueue()
{
while(!errors.empty())
{
delete [] errors.front();
errors.pop();
}

while (!old_errors.empty())
{
delete [] old_errors.front();
old_errors.pop_front();
}

}

};

static ErrorQueue errors;void WriteCallError(const char * error_message, ...)
{
char err_buffer[MAX_ERR_MSG_SIZE];

va_list args;
va_start(args,error_message);
std::vsnprintf(err_buffer,MAX_ERR_MSG_SIZE,error_message,args);
va_end(args);

char * err_string = new char[MAX_ERR_MSG_SIZE];
memcpy(err_string,err_buffer,MAX_ERR_MSG_SIZE);
{
error_lock.Lock();
errors.push(err_string);
error_lock.Unlock();
}
}

Я вызываю WriteCallError много раз в другом месте кода, и через определенное количество раз он рвется и сообщает мне, что стек разбит.

Где моя вина? Есть ли какое-то забавное взаимодействие между cstdarg и gtest? Здесь достаточно информации?

Редактировать:
Используя простое основное, я попытался выделить его:

int main (int argc, char ** argv)
{
int i = 0;
while (1)
{
WriteCallError("Breaks on %d",i++);
}

}

Это не приведет к разрушению стека.

0

Решение

Я думаю, что ваша проблема в том, что vsnprintf не записывает завершающий нулевой символ в массив, если данные, которые вы пишете, выходят за указанный вами предел. Когда вы позже получите доступ к этой C-строке, так как терминатора нет, она будет читать за пределами допустимых данных и в неизвестную память.

Вы не заметили это в своем тесте, потому что не превышаете ограничение в 128 символов.

Быстрое исправление состоит в том, чтобы гарантировать правильное завершение массива после использования vsnprintf:

void WriteCallError(const char * error_message, ...)
{
char err_buffer[MAX_ERR_MSG_SIZE];

va_list args;
va_start(args,error_message);
std::vsnprintf(err_buffer,MAX_ERR_MSG_SIZE,error_message,args);
va_end(args);

// Fix here
err_buffer[MAX_ERR_MSG_SIZE - 1] = 0;

char * err_string = new char[MAX_ERR_MSG_SIZE];
memcpy(err_string,err_buffer,MAX_ERR_MSG_SIZE);
{
error_lock.Lock();
errors.push(err_string);
error_lock.Unlock();
}
}
2

Другие решения

Отвечая, чтобы я мог закрыть вопрос, так как я решил ошибку:

Это произошло в коде, похожем на это:

TEST(MyTest,Case1)
{
MyStruct1 object1;
memset(&object1,0,sizeof(object1));

MyStruct2 object2[1];
memset(&object2[0],0,sizeof(object1));

object1.object2_ptr = object2;// DO SOME TESTING

}

Так как object1 & object2 — переменные стека, а object1 больше, чем object2. Я слишком долго выделял память, когда записывал memset. Когда я оставил часть этой функции в стеке, указатель стека закричал, что происходит что-то сумасшедшее, и сказал, что я разбиваю стек.

Простое исправление:

TEST(MyTest,Case1)
{
MyStruct1 object1;
memset(&object1,0,sizeof(MyStruct1));

MyStruct2 object2[1];
memset(&object2[0],0,sizeof(MyStruct2));

object1.object2_ptr = object2;// DO SOME TESTING

}
0

По вопросам рекламы [email protected]