Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions libr/include/r_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,9 @@ typedef enum {
R_EVENT_CORE_TASK_FINISHED,
R_EVENT_CORE_TASK_INTERRUPTED,

// util
R_EVENT_LOG,

R_EVENT_LAST,
} REventType;

Expand Down Expand Up @@ -271,6 +274,14 @@ typedef struct r_event_msg_t {
size_t data_len;
} REventMessage;

typedef struct r_event_log_t {
int level;
const char *origin;
const char *func;
int line;
const char *msg;
} REventLog;

typedef struct r_event_t REvent;
typedef void (*REventCallback)(REvent *ev, int type, void *user, void *data);
typedef struct r_event_hook_t {
Expand Down
3 changes: 3 additions & 0 deletions libr/include/r_util/r_log.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,16 @@ typedef struct r_log_source_t {
const char *source;
} RLogSource;

typedef struct r_event_t REvent;

R_API bool r_log_init(void);
R_API void r_log_fini(void);
R_API bool r_log_match(int level, const char *origin);
R_API void r_log_message(RLogLevel level, const char *origin, const char *func, int line, const char *fmt, ...);
R_API void r_log_vmessage(RLogLevel level, const char *origin, const char *func, int line, const char *fmt, va_list ap);
R_API void r_log_add_callback(RLogCallback cb, void *user);
R_API void r_log_del_callback(RLogCallback cb);
R_API REvent *r_log_event(void);

#if R_LOG_DISABLE
#define R_LOG(f,...) do {} while(0)
Expand Down
23 changes: 23 additions & 0 deletions libr/util/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <stdarg.h>

static R_TH_LOCAL RLog *rlog = NULL;
static R_TH_LOCAL REvent *rlogev = NULL;
typedef struct r_log_cbuser_t {
void *user;
RLogCallback cb;
Expand Down Expand Up @@ -78,13 +79,25 @@ R_API void r_log_fini(void) {
if (rlog) {
RLog *log = rlog;
rlog = NULL;
r_event_free (rlogev);
rlogev = NULL;
r_list_free (log->cbs);
free (log->file);
free (log->filter);
free (log);
}
}

R_API REvent *r_log_event(void) {
if (!r_log_init ()) {
return NULL;
}
if (!rlogev) {
rlogev = r_event_new (NULL);
}
return rlogev;
}

R_API void r_log_show_ts(bool ts) {
if (r_log_init ()) {
rlog->show_ts = ts;
Expand Down Expand Up @@ -178,6 +191,16 @@ R_API void r_log_vmessage(RLogLevel level, const char *origin, const char *func,
return;
}
vsnprintf (out, sizeof (out), fmt, ap);
if (rlogev) {
REventLog logev = {
.level = level,
.origin = origin,
.func = func,
.line = line,
.msg = out,
};
r_event_send (rlogev, R_EVENT_LOG, &logev);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid re-entering event lock from log callbacks

When r_log_vmessage emits R_EVENT_LOG, it calls r_event_send directly; r_event_send takes ev->lock (created as non-recursive in r_event_new (false)) and executes callbacks while holding that lock. If a R_EVENT_LOG callback logs again via R_LOG_*, r_log_vmessage re-enters r_event_send on the same bus and blocks on the mutex in pthread builds, so enabling log-event hooks can hang the process in a common callback pattern.

Useful? React with 👍 / 👎.

}
if (rlog->cbs) {
RListIter *iter;
RLogCallbackUser *cbu;
Expand Down
21 changes: 21 additions & 0 deletions test/unit/test_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,18 @@ static Sdb *setup_sdb(void) {
return res;
}

typedef struct {
int count;
} LogEventAcc;

static void log_event_cb(REvent *ev, int type, void *user, void *data) {
(void)ev;
(void)type;
(void)data;
LogEventAcc *acc = (LogEventAcc *)user;
acc->count++;
}

bool test_dll_names(void) {
Sdb *TDB = setup_sdb ();
char *s;
Expand Down Expand Up @@ -237,6 +249,15 @@ bool test_log(void) {
// https://github.com/radareorg/radare2/issues/22468
R_LOG_INFO ("%s", "");

REvent *ev = r_log_event ();
mu_assert_notnull (ev, "r_log_event ()");
LogEventAcc acc = { 0 };
r_event_hook (ev, R_EVENT_LOG, log_event_cb, &acc);
R_LOG_INFO ("log-event-test");
r_event_unhook (ev, R_EVENT_LOG, log_event_cb);
R_LOG_INFO ("log-event-test-2");
mu_assert_eq (acc.count, 1, "R_EVENT_LOG should be sent once");

r_core_free (core);
mu_end;
}
Expand Down
Loading