0

I'm trying to make a simple logger to log to a file to give me debug information about my program. I want to avoid using a library so I'm making one myself.

logging.cpp

#include <string.h> // String stuff
#include <time.h>   // Time

#include "logging.hpp"

// Cathooks main logging util
CatLogger g_CatLogging("/tmp/nekohook.log");
//CatLogger g_CatLogging;

CatLogger::CatLogger(const char* _file_path, bool _ptime) : ptime(_ptime) {
     file_path = _file_path;
}
CatLogger::~CatLogger() {   fclose(log_handle); }

void CatLogger::log(const char* fmt, ...) {

    // Basicly an init, because this cant be done on construct
    if (log_handle == nullptr) {
        log_handle = fopen(file_path, "w");
    }

    // Print our time if needed
    if (ptime) {
        // Get our time
        time_t current_time = time(0);
        struct tm* time_info = localtime(&current_time);

        // print it to a string
        char timeString[10];
        strftime(timeString, sizeof(timeString), "%H:%M:%S", time_info);

        // Print the time into the log
        fprintf(log_handle, "%% [%s] ", timeString);
    }

    // Get the string we want to log
    char buffer[1024];
    va_list list;
    va_start(list, fmt);
    vsprintf(buffer, fmt, list);
    va_end(list);

    // Write our log to the file
    fprintf(log_handle, "%s\n", file_path, buffer);
    fflush(log_handle);

    // Push result var to a console here, if i ever make a console api
}

logging.hpp

#include <stdarg.h> // ... arg
#include <stdio.h> // fopen(), fprint(), fputs()

class CatLogger {
public:
  CatLogger(const char* _file_path, bool _ptime = false);
  ~CatLogger();
  void log(const char* fmt, ...); // Use to log with
private:
  FILE* log_handle = 0; // Handle used to log to files with
  const char* file_path; // Path to log file
  const bool ptime; // Whether to print time
};

// Use this to log
extern CatLogger g_CatLogging;

When I use the log function, it fails. I have no idea why. I made a dummy function that crashes when ran to get info from gdb of the input. I input the file_path variable into it and it returns 0x0. I'm not sure why this happens, I've made a sample executable separate from the library I'm using this in and it works flawlessly. Could this be due to the way I'm linking libraries or the lack of?

Here is the library I am working on with a link directly to the logging file. https://github.com/oneechanhax/nekohook/blob/master/src/util/logging.cpp

It crashes on fprintf() on both due to fopen not returning a file handle, which is in turn because const char* isn't being passes for some reason.

Please tell me a way to debug this or point out where this went wrong as I'm at a loss trying for myself.

EDIT: If i replace the following in CatLogger::log

if (log_handle == nullptr) {
    log_handle = fopen(file_path, "w");
}

With the following

if (log_handle == nullptr) {
    log_handle = fopen("/tmp/nekohook.log", "w");
}

It now works but i cant change the log location for other log classes now...

EDIT2: Here is some debug info. Somehow the const char* doesnt get saved into the class. Thats the main issue that i have...

example

Maybe the string becomes null after constructing...

  • 3
    Sounds like a possible static initialization order fiasco, if the `fopen` implementation has its own static data it needs to be initialized in order to work. Your report makes it sounds like it fails for something like that. – StoryTeller - Unslander Monica Dec 10 '17 at 17:11
  • 1
    Suggestion. If you are using C++, use the C++ header files instead of the C header files. `#include `, `#include `, and `#include `.' – Eljay Dec 10 '17 at 17:27
  • It's likely that your g_CatLogging global has not been initialized yet when it is being called. Are you trying to do logging before `main` has been called? – Eljay Dec 10 '17 at 17:31
  • 1
    Use the singleton design pattern for the CatLogger class : https://stackoverflow.com/questions/1008019/c-singleton-design-pattern#1008289 – Robert Andrzejuk Dec 10 '17 at 17:36
  • @Eljay The first call is after the library has been opened by something else. I make a new thread here. https://github.com/oneechanhax/nekohook/blob/master/src/entry.cpp `Attaching...` is the first thing that gets logged and thats where it crashes. Everything should be initialized. @RobertAndrzejuk its a class that can be used for other logging classes through inheritance. I don't think it should be a singleton. – Julianacat Dec 10 '17 at 17:39
  • Then why do you declare a global variable? ```CatLogger g_CatLogging("/tmp/cathook.log", true)``` – Robert Andrzejuk Dec 10 '17 at 17:44
  • 1
    To see what is happening add many trace comments to std::cout or better to std::cerr. – Robert Andrzejuk Dec 10 '17 at 17:47
  • I have ptime as a option that i can disable for other logging instances. for example. class ClassDumper : private CatLogger { public: ClassDumper() : CatLogger("/tmp/classdump.txt") {} void SaveDump() { ClientClass* cc = g_IBaseClient->GetAllClasses(); while (cc) { log("[%d] %s\n", cc->m_ClassID, cc->GetName()); cc = cc->m_pNext; } } }; Code formatting... – Julianacat Dec 10 '17 at 17:48
  • @RobertAndrzejuk any way I can get the output from gdb or some other way. Im using this within another process that I don't have console output from. – Julianacat Dec 10 '17 at 17:50
  • @RobertAndrzejuk • you are saying that the logger... needs... a logger. ;-) – Eljay Dec 10 '17 at 18:19
  • Why aren't you checking the `log_handle` pointer *after* `fopen` too? – Bob__ Dec 10 '17 at 19:08
  • I edited the main post. I included some info with it. The issue is that the class wont take in the file_path for some reason. – Julianacat Dec 11 '17 at 04:45

2 Answers2

0

There are a lot of potential bugs.

if (log_handle == nullptr) {
    log_handle = fopen(file_path, "w");
    if(!log_handle) {
        perror("File opening failed"); // check your console output.
        return EXIT_FAILURE;
    }
}


// Get the string we want to log
char buffer[1024];
va_list list;
va_start(list, fmt);
vsprintf(buffer, fmt, list); // potential segmentation fault
va_end(list);

use this instead

int vsnprintf( char* buffer, std::size_t buf_size, const char* format, va_list vlist ); //  (since C++11)

And more it the program is multithreaded.

Surt
  • 15,501
  • 3
  • 23
  • 39
-1

This was a case of static init order fiasco where the const char* wouldn't get initialized before the function was called. The solution was to make the file link first compared to other files and the object works now.