C++: Application crashes with abort() on logging function - c++

here is my code which is run on windows:
Log.h
#include <iostream>
#include <sstream>
#include <fstream>
#include <shared_mutex>
#include <thread>
#include <iomanip>
class Log {
public:
static std::ofstream myfile;
static std::shared_mutex m_smutex;
static bool isLogEnabled();
static void close() {
Log::myfile.close();
}
template< typename... Args >
static void debug(const char* format, Args... args) {
std::unique_lock<std::shared_mutex> lock(Log::m_smutex);
if (isLogEnabled()) {
if (!Log::myfile.is_open()) {
Log::myfile.open("C:\\tmp\\log.txt", std::ios_base::app);
}
...
Log::myfile.close();
}
else {
if (Log::myfile.is_open()) {
Log::myfile.flush();
Log::myfile.close();
}
}
}
};
You can see I've deleted most of the code(...) because I narrowed down the problem.
Log.cpp
#include <Windows.h>
#include "Log.h"
std::ofstream LogLine::myfile;
std::shared_mutex LogLine::m_smutex;
bool LogLine::isLogEnabled() {
CHAR regeditPath[MAX_PATH] = { 0 };
CHAR variable[] = "DEBUG_LOGS";
GetEnvironmentVariableA(variable, regeditPath, MAX_PATH);
return GetLastError() == ERROR_ENVVAR_NOT_FOUND ? false : true;
}
The process needs to be run always, that's why I open and close the file everytime I log something. I want to be able to delete logs even when the process is still running. Maybe this is silly because there might be a flag which would allow me to delete the logs while file is open by some process.
Example usage:
Log::debug("little test %d", 10);
As you can see I use mutex because I want to call debug function from different threads. The problem is that after some time I get error code Abort() has been called but I can't understand why.
P.S
I created this code inside custom Credential Provider to enable debugging, but I'm checking in the internet and it seems like nobody is using logging there. Is it because it's forbidden? Maybe this is reason of the crash?

Related

Factory for threads in C++

I am currently trying to create a sort of "factory" pattern in a class, whose instances should be Threads that have their own certain operation procedure. I have currently declared a global variable isFinished in order to end the operation of the worker thread, however, somehow the operation does not stop after the variable state is changed, and the worker thread does not do the std::thread::join() operation in order to finish working. I am new to threads, and in C++ in general and I don't really know what is wrong so any help would be greatly appreciated.
Here is the code:
\\main.cpp
#include <iostream>
#include <thread>
#include <atomic>
#include "Sender.h"
int main()
{
isFinished = false; //set false for worker thread
Sender mSender; //Create thread object for worker
std::cin.get(); //Trigger by pressing enter
isFinished = true; //exit worker while loop
mSender.join(); //wait for the worker thread to finish execution
}
\\sender.cpp
#include <iostream>
#include <thread>
#include <atomic>
#include "Sender.h"
void Sender::SenderWorkflow()
{
while (!isFinished)
{
std::cout << "Working... \n";
}
}
\\sender.h
#include <iostream>
#include <thread>
#include <atomic>
static std::atomic<bool> isFinished;
class Sender {
public:
std::thread worker;
Sender()
: worker(&Sender::SenderWorkflow, this)
{
}
void SenderWorkflow();
void join() {
worker.join(); \\std::thread::join()
}
};
The problem is that you are using a static variable in the global scope. static in a namespace scope is used to hide the variable or function in the object file so that the linker can't see it while linking another object file for another cpp file. In practice static is used only inside the cpp file itself. Since you declared it inside the header each translation unit that includes it will get a different instance of the variable because the linker can't see the same variable across objects file. To solve this :
1- move the declaration of the static variable to the cpp file and make an accessor function in the header file:
\\sender.h
#include <atomic>
const std::atomic<bool>& checkIsFinished();
void setFinished();
\\sender.cpp
static std::atomic<bool> isFinished;
const std::atomic<bool>& checkIsFinished() { return isFinished; }
void setFinished() { isFinished = true; }
2- or use inline variable (since c++17) in the header file:
\\sender.h
#include <atomic>
inline std::atomic<bool> isFinished;
3 - or better and the correct design : make the variable local as member of the class, the less global variables the better !
\\sender.h
#include <atomic>
class Sender {
public:
std::thread worker;
Sender()
: worker(&Sender::SenderWorkflow, this)
{
}
void SenderWorkflow();
void join() {
isFinished = true;
worker.join(); \\std::thread::join()
}
private:
std::atomic<bool> isFinished = false;
};

Reference to object with std::async

I have a small solution in visual studio 2012. The solution consists of two projects (Scanner and TestApp), Scanner is a dll and TestApp is a small application using the dll.
I would like a function in the dll to run in a thread and to report its result back via a queue to the TestApp.
To test this I wrote a minimal application, but depending on how I launch the thread I get different results and I would like to understand why.
The Scanner.h file looks like this:
#pragma once
#include <iostream>
#include <string>
#include <stdint.h>
#include <atomic>
#include <future>
#include <thread>
#include "version.h"
#include "threadsafe_queue.h"
#include "capture_data.h"
#include "process_data.h"
#ifdef SCANNER_EXPORTS
#define SCANNER_API __declspec(dllexport)
#else
#define SCANNER_API __declspec(dllimport)
#endif
class Scanner
{
public:
static SCANNER_API void run();
static SCANNER_API void stop();
};
Scanner.cpp:
#include "stdafx.h"
#include "Scanner.h"
std::vector<std::future<int>> my_futures;
void Scanner::run()
{
CaptureData capture_data(1234);
auto t = std::async(std::launch::async, &CaptureData::get_data, capture_data);
my_futures.push_back(std::move(t));
}
void Scanner::stop()
{
for(int n=0; n<my_futures.size(); n++) {
auto e = std::move(my_futures.back());
e.get();
my_futures.pop_back();
}
}
The class CaptureData is defined in capture_data.h and capture_data.cpp.
capture_data.h:
#pragma once
#include <atomic>
#include <thread>
#include "iq_data.h"
#include "threadsafe_queue.h"
class CaptureData
{
public:
CaptureData(double freq_start);
void configure();
void get_data();
private:
double m_test;
};
capture_data.cpp
#include "stdafx.h"
#include "capture_data.h"
#include "Scanner.h"
ThreadsafeQueue<int> g_queue_1;
SCANNER_API ThreadsafeQueue<int> g_queue_2;
CaptureData::CaptureData(double test)
: m_test(test) {}
void CaptureData::get_data()
{
cout << "1: " << m_test << std::endl;
Sleep(5000);
cout << "2: " << m_test << std::endl;
g_queue_2.push(3);
cout << "Capture has now pushed data" << std::endl;
}
And finally the TestApp.cpp:
#include "stdafx.h"
#include "tchar.h"
#include <stdint.h>
#include <string>
#include "Scanner.h"
SCANNER_API extern ThreadsafeQueue<int> g_queue_2;
int _tmain(int argc, _TCHAR* argv[])
{
Scanner scanner;
scanner.run();
cout << "TestApp waiting for data..." << std::endl;
int data;
g_queue_2.wait_and_pop(data);
cout << "TestApp got data: " << data << std::endl;
scanner.stop();
return 0;
}
In Scanner.cpp I have tried to launch the thread in two different ways, the first way:
auto t = std::async(std::launch::async, &CaptureData::get_data, capture_data);
Second way is with a reference to the object "capture_data":
auto t = std::async(std::launch::async, &CaptureData::get_data, &capture_data);
The first way seems to work as I intended the application to work and I get the following printouts in my terminal:
TestApp waiting for data...
1: 1234
2: 1234
Capture has now pushed data
TestApp got data: 3
Press any key to continue...
If I use the second way I get:
TestApp waiting for data...
1: 6.95166e-310
2: 6.95166e-310
Capture has now pushed data
TestApp got data: 3
Press any key to continue...
So, what I do not understand is why the variable "m_test" get messed up in the second case.
I would very much appreciate if anyone could shed a light on this.
/M
In the following code:
void Scanner::run()
{
CaptureData capture_data(1234);
auto t = std::async(std::launch::async, &CaptureData::get_data, capture_data);
my_futures.push_back(std::move(t));
}
capture_data is a local variable that goes out of scope and gets destroyed when the function returns. If you pass a pointer to that variable into async that pointer becomes a dangling pointer causing undefined behaviour. That does not happen if you pass it by value, as you do in the above snippet.
You are trying to pass a pointer to a stack allocated object. This object is destructed at the end of the Scanner::run() method. Thus, the pointer is now pointing to invalid memory when the async function runs.
The first method works, because the capture_data variable is move constructed when it is passed to the function, therefore it still retains it's structure.
I recommend using lambda functions than passing the raw member function:
void Scanner::run()
{
CaptureData capture_data(1234);
auto t = std::async(std::launch::async, [capture=std::move(capture_data)]() { capture.get_data(); });
my_futures.emplace_back(t);
}
Even better is to construct the object inside the lambda function:
void Scanner::run()
{
auto t = std::async(std::launch::async, []() {
CaptureData capture_data(1234);
capture_data.get_data();
});
my_futures.emplace_back(t);
}

Boost ASIO socket io_service.run blocking

Before I start, I just was trying something out. I don't know yet if I want to do a big project.
I tried making a TCP Socket Server with Boost as it's much easier than winsock. At least, so I thought, but it doesn't work how I want it. What should happen:
Read configuration
Start TCP Socket Server
Run _acceptor.async_accept
Run io_service.run
Now, I got to the point my socket server works and accepts connections. However, I cannot do user input anymore as io_service.run blocks the rest of my server. I must be doing something wrong.
tcp_listener.h:
#pragma once
#include <boost/asio.hpp>
class tcp_listener
{
public:
tcp_listener(boost::asio::io_service& io_service, std::string ip, short port);
static void start(tcp_listener* ptr);
void start_accepting();
private:
boost::asio::ip::tcp::acceptor _acceptor;
boost::asio::ip::tcp::socket _socket;
};
tcp_listener.cpp:
#include "tcp_listener.h"
#include "logger.h"
#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <memory>
tcp_listener::tcp_listener(boost::asio::io_service& io_service, std::string ip, short port)
: _acceptor(io_service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address_v4::from_string(ip), port)),
_socket(io_service)
{
logger::log_main("Network bound on %s.%d", _acceptor.local_endpoint().address().to_string().data(), _acceptor.local_endpoint().port());
start_accepting();
io_service.run();
}
void tcp_listener::start(tcp_listener* ptr)
{
ptr->start_accepting();
}
void tcp_listener::start_accepting()
{
_acceptor.async_accept(_socket, [this](boost::system::error_code ec)
{
if (!ec)
{
logger::log_main("New connection %s", _socket.remote_endpoint().address().to_string().data());
//std::make_shared<tcp_client>(std::move(socket_))->start_receiving();
}
else
{
_acceptor.close();
}
start_accepting();
});
}
engine.h:
#pragma once
#include "configuration.h"
class engine
{
public:
static void boot();
static void destroy();
static configuration* get_config();
private:
static configuration* config;
};
engine.cpp:
#include "engine.h"
#include "tcp_listener.h"
#include <boost/thread.hpp>
#include <boost/bind.hpp>
configuration* engine::config;
void engine::boot()
{
engine::config = new configuration("config.cnf");
boost::asio::io_service io_service;
tcp_listener& list = tcp_listener(io_service, engine::config->get_value("network.ip"), atoi(engine::config->get_value("network.port").data()));
}
void engine::destroy()
{
delete engine::config;
}
configuration* engine::get_config()
{
return engine::config;
}
Main.cpp:
#include "engine.h"
#include <iostream>
int main()
{
engine::boot();
for (;;)
{
std::string input;
std::cin >> input;
if (input == "exit")
{
engine::destroy();
break;
}
}
return 0;
}
I have searched for more than 5 hours, I tried a million things, nothing work. I tried putting it in a thread, resulting me in an exception. Or the socket server itself didn't work.
The user input is useful to reload certain cached data or close the application or something like that.
This is by design.
Just run the service on a separate thread.
std::thread th([&] { io_service.run(); }); // example
Beware of thread synchronization on shared resources then.
io_service is thread safe (except for special operations like construction, destruction, reset). So, if you must perform tasks that need synchronization it would be easiest to post() it to the service.
As long as you have only 1 thread run-ning the particular io_service instance, you don't need additional synchronization (what is known as a logical or implicit strand¹).
¹ Why do I need strand per connection when using boost::asio?

Boost test setup error: memory access violation

I am getting the above error while running the executable after compiling and running the following file.
#define BOOST_TEST_MAIN
#define BOOST_TEST_DYN_LINK
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/bind.hpp>
#include <boost/test/unit_test_log.hpp>
#include <boost/filesystem/fstream.hpp>
#include "index/DatabaseGroup.hpp"
using namespace boost::unit_test;
namespace indexing {
class ForwardDBTest {
/// A pointer to the database group object.
DatabaseGroup& databaseGroup;
std::string databaseName;
public:
~ForwardDBTest() {
}
;
ForwardDBTest(DatabaseGroup& databaseGroup_, std::string dbName) :
databaseGroup(databaseGroup_), databaseName(dbName) {
}
void boostTestCreateDB() {
databaseGroup.createDatabase(databaseName, databaseName);
}
};
class testSuites: public test_suite {
public:
testSuites() :
test_suite("test_suite") {
std::string db_location = "home/girijag/ripe/ripe_db";
std::cout << "hello" << std::endl;
int concurrency = 0;
std::string db_cache_policy = "AllMem";
boost::shared_ptr<DatabaseGroup> db = boost::shared_ptr<DatabaseGroup>(
new DatabaseGroup(db_location, concurrency, db_cache_policy));
std::string dbName = "DB1";
boost::shared_ptr<ForwardDBTest> instance(
new ForwardDBTest(*db, dbName));
test_case* boostTestCreateDB_test_case = BOOST_CLASS_TEST_CASE(
&ForwardDBTest::boostTestCreateDB, instance);
add(boostTestCreateDB_test_case);
}
~testSuites() {
}
;
};
test_suite* init_unit_test_suite(int argc, char** argv) {
test_suite* suite(BOOST_TEST_SUITE("Master Suite"));
suite->add(new testSuites());
return suite;
}
}'
Please let me know how should i resolve this?
i am getting errors as below:-
Test setup error: memory access violation at address: 0x00000021: no mapping at fault address
I have been struggling from past 2 days to figure out whats my issue
There are a number of disturbing things in the code, and some formatting seems have to been lost when posting the question, otherwise there is no chance it compiles. (For example, }’ ?!)
For starters, you shouldn’t place init_unit_test_suite(int, char**) in the indexing namespace, and subsequently there is no point in defining BOOST_TEST_MAIN - you will end up with multiple definition of the said init_unit_test_suite(int, char**) method.
In your case, the suite should be simply registered in the master test suite, there is no need to return a pointer to it from the method.
Here’s a minimal example that you can work with an extend for your purpose. It follows your structure, but omits non-relevant details:
#include <boost/test/included/unit_test.hpp>
#include <iostream>
using namespace boost::unit_test;
namespace indexing {
class ForwardDBTest {
public:
void boostTestCreateDB() { std::cout << __FUNCTION__ << std::endl; }
};
class TestSuite : public test_suite {
public:
TestSuite() : test_suite("test_suite") {
boost::shared_ptr<ForwardDBTest> instance(new ForwardDBTest);
add(BOOST_CLASS_TEST_CASE(&ForwardDBTest::boostTestCreateDB, instance));
}
};
} // namespace indexing
test_suite* init_unit_test_suite(int, char**) {
framework::master_test_suite().add(new indexing::TestSuite);
return 0;
}
/* Output:
Running 1 test case...
boostTestCreateDB
*** No errors detected
*/

Cpp Pantheios Log Library, Debug Assertion Failed Error

I have a cpp project, a cpp cli project and a c# win forms project.
I use pantheios log library in my cpp native project. When i try to write log, i take this error :
Here is my codes :
Log.hpp
#ifndef INCLUDE_LOG_HPP
#define INCLUDE_LOG_HPP
#define PANTHEIOS_NO_INCLUDE_OS_AND_3PTYLIB_STRING_ACCESS // Faster compilation
/* Pantheios Header Files */
#include <pantheios/pantheios.hpp> // Pantheios C++ main header
#include <pantheios/inserters/args.hpp> // for pantheios::args
#include <pantheios/backends/bec.file.h> // be.file header
#include "Include/utility.hpp"
/* Standard C/C++ Header Files */
#include <exception> // for std::exception
#include <new> // for std::bad_alloc
#include <string> // for std::string
#include <stdlib.h>
#include <sstream>
#define PSTR(x) PANTHEIOS_LITERAL_STRING(x)
namespace Mtx
{
namespace log
{
class MTXMANAGER Logger
{
public:
void WriteLogIn(const std::string & log_text);
Logger();
~Logger();
};
}
}
#endif
Log.cpp
#include "Log.hpp"
namespace Mtx
{
namespace log
{
PANTHEIOS_EXTERN_C const PAN_CHAR_T PANTHEIOS_FE_PROCESS_IDENTITY[] = PANTHEIOS_LITERAL_STRING("mtx");//
Logger::Logger()
{
char path[MAX_PATH];
GetModuleFileName( NULL, path, MAX_PATH );
std::string::size_type pos = std::string( path ).find_last_of( "\\" );
strcpy(path,std::string( path ).substr( 0, pos).c_str());
std::strcat (path,"\\mtx-%D__.log");
/////
pantheios_be_file_setFilePath(PSTR(path), PANTHEIOS_BE_FILE_F_TRUNCATE, PANTHEIOS_BE_FILE_F_SHARE_ON_WINDOWS, PANTHEIOS_BEID_ALL);
}
Logger::~Logger()
{
}
void Logger::WriteLogIn(const std::string & log_text)
{
pantheios::log_INFORMATIONAL(PSTR(" [1] "),PSTR(log_text));
}
}
}
I take the error at this line :
pantheios::log_INFORMATIONAL(PSTR(" [1] "),PSTR(log_text));
How can i fix this error?
I am afraid I don't have a direct answer for you, but comparing what I have in my solution (which is similar in many aspects with your setup - .NET DLL calling a C++-native DLL, which has Pantheios-logging), here is what I have:
I have a project LOG, which has an InitInstance() and ExitInstance() (and ctors for the CWinApp-derived class - CLogApp)
CLogApp ctor/dtor are empty
The code in InitInstance() and ExitInstance():
BOOL CLogApp::InitInstance()
{
CWinApp::InitInstance();
int panres = pantheios::pantheios_init();
if( panres < 0 )
{
OutputDebugStringA("Could not initialise the Pantheios logging libraries!\n");
util::onBailOut(pantheios::emergency, "Failed to initialise the Pantheios libraries", PANTHEIOS_FE_PROCESS_IDENTITY, /*pantheios::*/pantheios_getInitCodeString(panres));
return FALSE;
}
else
{
pantheios_be_file_setFilePath(CErrorHandler::getLogPath().c_str(), PANTHEIOS_BE_FILE_F_TRUNCATE, PANTHEIOS_BE_FILE_F_TRUNCATE, PANTHEIOS_BEID_LOCAL);
PANTHEIOS_TRACE_NOTICE("STARTING LOGGING");
}
return TRUE;
}
int CLogApp::ExitInstance()
{
PANTHEIOS_TRACE_NOTICE("STOPPING LOGGING");
pantheios_uninit();
return 0;
}
I am not sure if this will help, but this code has been working for me for many years now.