Skip to content
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

**Features**:

- Windows: add WER integration for syncing tags and attachments to WER. ([#1837](https://github.com/getsentry/sentry-native/pull/1837))
- Report `cache_overflow` discards due to `cache_max_items` or `cache_max_size`. ([#1884](https://github.com/getsentry/sentry-native/pull/1884))

**Fixes**:
Expand Down
8 changes: 8 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -963,6 +963,14 @@ if(SENTRY_INTEGRATION_QT)
target_link_libraries(sentry PRIVATE Qt${Qt_VERSION_MAJOR}::Core)
endif()

option(SENTRY_INTEGRATION_WER "Build WER (Windows Error Reporting) integration")
if(SENTRY_INTEGRATION_WER AND WIN32
AND (SENTRY_BACKEND_BREAKPAD OR SENTRY_BACKEND_CRASHPAD))
message(WARNING
"SENTRY_BACKEND=${SENTRY_BACKEND} is not compatible with WER. "
"Use SENTRY_BACKEND=none, inproc, or native with SENTRY_INTEGRATION_WER.")
endif()

include(CMakePackageConfigHelpers)
configure_package_config_file(sentry-config.cmake.in sentry-config.cmake
INSTALL_DESTINATION "${CMAKE_INSTALL_CMAKEDIR}")
Expand Down
7 changes: 7 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,13 @@ if(SENTRY_INTEGRATION_QT)
integrations/sentry_integration_qt.h
)
endif()
if(SENTRY_INTEGRATION_WER AND WIN32)
target_compile_definitions(sentry PRIVATE SENTRY_INTEGRATION_WER)
sentry_target_sources_cwd(sentry
integrations/sentry_integration_wer.c
integrations/sentry_integration_wer.h
)
endif()

# screenshot
if(SENTRY_SCREENSHOT_WINDOWS)
Expand Down
283 changes: 283 additions & 0 deletions src/integrations/sentry_integration_wer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
#include "sentry_integration_wer.h"

#include "sentry_alloc.h"
#include "sentry_attachment.h"
#include "sentry_core.h"
#include "sentry_logger.h"
#include "sentry_path.h"
#include "sentry_scope.h"
#include "sentry_string.h"

#include <string.h>
#include <wchar.h>
#include <werapi.h>

// Windows 8+ SDK
#ifndef WER_FILE_ANONYMOUS_DATA
# define WER_FILE_ANONYMOUS_DATA 0x2
#endif
#ifndef WER_MAX_PARAM_LENGTH
# define WER_MAX_PARAM_LENGTH (MAX_PATH)
#endif
#ifndef WER_MAX_MEM_BLOCK_SIZE
# define WER_MAX_MEM_BLOCK_SIZE (64 * 1024)
#endif
#ifndef WER_METADATA_KEY_MAX_LENGTH
# define WER_METADATA_KEY_MAX_LENGTH 64
#endif
#ifndef WER_METADATA_VALUE_MAX_LENGTH
# define WER_METADATA_VALUE_MAX_LENGTH 128
#endif

typedef struct sentry_integration_wer_data_s {
HRESULT(WINAPI *WerRegisterCustomMetadata)(PCWSTR, PCWSTR);
HRESULT(WINAPI *WerUnregisterCustomMetadata)(PCWSTR);
sentry_scope_t *scope;
sentry_scope_observer_t *observer;
} sentry_integration_wer_data_t;

static void
wer_init(sentry_integration_wer_data_t *wer_data)
{
if (wer_data->WerRegisterCustomMetadata) {
return;
}
HMODULE kernel32 = GetModuleHandleW(L"kernel32.dll");
if (kernel32) {
wer_data->WerRegisterCustomMetadata = (HRESULT(WINAPI *)(PCWSTR,
PCWSTR))GetProcAddress(kernel32, "WerRegisterCustomMetadata");
wer_data->WerUnregisterCustomMetadata = (HRESULT(WINAPI *)(
PCWSTR))GetProcAddress(kernel32, "WerUnregisterCustomMetadata");
}
if (!wer_data->WerRegisterCustomMetadata) {
SENTRY_DEBUG("WerRegisterCustomMetadata not available; "
"tag sync to WER will be skipped");
}
}

static void
sentry_integration_wer_free(void *data)
{
sentry_free(data);
}

static void
wer_set_tag(void *data, const char *key, const char *value)
{
sentry_integration_wer_data_t *wer_data
= (sentry_integration_wer_data_t *)data;
if (!wer_data->WerRegisterCustomMetadata) {
return;
}
if (!key || !value) {
return;
}

wchar_t *key_w = sentry__string_to_wstr(key);
wchar_t *value_w = sentry__string_to_wstr(value);
if (!key_w || !value_w || wcslen(key_w) > WER_METADATA_KEY_MAX_LENGTH
|| wcslen(value_w) > WER_METADATA_VALUE_MAX_LENGTH) {
sentry_free(key_w);
sentry_free(value_w);
return;
}

HRESULT hr = wer_data->WerRegisterCustomMetadata(key_w, value_w);
if (FAILED(hr)) {
SENTRY_WARNF(
"WerRegisterCustomMetadata failed: hr=0x%08lx", (unsigned long)hr);
}

sentry_free(key_w);
sentry_free(value_w);
}
Comment thread
jpnurmi marked this conversation as resolved.
Comment thread
cursor[bot] marked this conversation as resolved.

static void
wer_remove_tag(void *data, const char *key)
{
sentry_integration_wer_data_t *wer_data
= (sentry_integration_wer_data_t *)data;
if (!wer_data->WerUnregisterCustomMetadata) {
return;
}
if (!key) {
return;
}

wchar_t *key_w = sentry__string_to_wstr(key);
if (!key_w || wcslen(key_w) > WER_METADATA_KEY_MAX_LENGTH) {
sentry_free(key_w);
return;
}

HRESULT hr = wer_data->WerUnregisterCustomMetadata(key_w);
if (FAILED(hr)) {
SENTRY_WARNF("WerUnregisterCustomMetadata failed: hr=0x%08lx",
(unsigned long)hr);
}

sentry_free(key_w);
}
Comment thread
cursor[bot] marked this conversation as resolved.

static void
wer_add_attachment(void *UNUSED(data), sentry_attachment_t *attachment)
{
if (!attachment) {
return;
}

if (attachment->path) {
sentry_path_t *path = sentry__path_absolute(attachment->path);
if (!path || wcslen(path->path_w) > WER_MAX_PARAM_LENGTH) {
sentry__path_free(path);
return;
}
HRESULT hr = WerRegisterFile(
path->path_w, WerRegFileTypeOther, WER_FILE_ANONYMOUS_DATA);
if (FAILED(hr)) {
SENTRY_WARNF(
"WerRegisterFile failed: hr=0x%08lx", (unsigned long)hr);
}
sentry__path_free(path);
return;
Comment thread
cursor[bot] marked this conversation as resolved.
}

if (attachment->buf && attachment->buf_len > 0
&& attachment->buf_len <= WER_MAX_MEM_BLOCK_SIZE) {
HRESULT hr = WerRegisterMemoryBlock(
(PVOID)attachment->buf, (DWORD)attachment->buf_len);
Comment thread
cursor[bot] marked this conversation as resolved.
if (FAILED(hr)) {
SENTRY_WARNF(
"WerRegisterMemoryBlock failed: hr=0x%08lx", (unsigned long)hr);
}
return;
}
}

static void
wer_remove_attachment(void *UNUSED(data), sentry_attachment_t *attachment)
{
if (!attachment) {
return;
}

if (attachment->path) {
sentry_path_t *path = sentry__path_absolute(attachment->path);
if (!path || wcslen(path->path_w) > WER_MAX_PARAM_LENGTH) {
sentry__path_free(path);
return;
}
HRESULT hr = WerUnregisterFile(path->path_w);
if (FAILED(hr)) {
SENTRY_WARNF(
"WerUnregisterFile failed: hr=0x%08lx", (unsigned long)hr);
}
sentry__path_free(path);
return;
Comment thread
jpnurmi marked this conversation as resolved.
Comment thread
jpnurmi marked this conversation as resolved.
}

if (attachment->buf && attachment->buf_len > 0
&& attachment->buf_len <= WER_MAX_MEM_BLOCK_SIZE) {
HRESULT hr = WerUnregisterMemoryBlock((PVOID)attachment->buf);
if (FAILED(hr)) {
SENTRY_WARNF("WerUnregisterMemoryBlock failed: hr=0x%08lx",
(unsigned long)hr);
}
}
Comment thread
cursor[bot] marked this conversation as resolved.
}

static void
wer_cleanup_tag(const char *key, sentry_value_t UNUSED(value), void *data)
{
wer_remove_tag(data, key);
}
Comment thread
sentry[bot] marked this conversation as resolved.

static void
wer_clear(void *data)
{
sentry_integration_wer_data_t *wer_data
= (sentry_integration_wer_data_t *)data;
sentry_scope_t *scope = wer_data->scope;
if (!scope) {
return;
}

sentry__value_foreach_key_value(scope->tags, wer_cleanup_tag, wer_data);

for (sentry_attachment_t *attachment = scope->attachments; attachment;
attachment = attachment->next) {
wer_remove_attachment(wer_data, attachment);
}
}
Comment thread
jpnurmi marked this conversation as resolved.

static void
register_wer(
void *data, sentry_scope_t *scope, const sentry_options_t *UNUSED(options))
{
sentry_integration_wer_data_t *wer_data
= (sentry_integration_wer_data_t *)data;
wer_init(wer_data);

sentry_scope_observer_t *observer = sentry__scope_observer_new();
if (!observer) {
return;
}
observer->clear = wer_clear;
observer->set_tag = wer_set_tag;
observer->remove_tag = wer_remove_tag;
observer->add_attachment = wer_add_attachment;
observer->remove_attachment = wer_remove_attachment;
Comment thread
sentry[bot] marked this conversation as resolved.
observer->data = wer_data;
Comment thread
cursor[bot] marked this conversation as resolved.

if (sentry__scope_add_observer(scope, observer)) {
wer_data->scope = scope;
wer_data->observer = observer;
for (sentry_attachment_t *attachment = scope->attachments; attachment;
attachment = attachment->next) {
wer_add_attachment(wer_data, attachment);
}
}
Comment thread
jpnurmi marked this conversation as resolved.
}
Comment thread
cursor[bot] marked this conversation as resolved.
Comment thread
jpnurmi marked this conversation as resolved.
Comment thread
cursor[bot] marked this conversation as resolved.

static void
unregister_wer(
void *data, sentry_scope_t *scope, const sentry_options_t *UNUSED(options))
{
sentry_integration_wer_data_t *wer_data
= (sentry_integration_wer_data_t *)data;
if (!wer_data->observer) {
return;
}

sentry__value_foreach_key_value(scope->tags, wer_cleanup_tag, wer_data);

for (sentry_attachment_t *attachment = scope->attachments; attachment;
attachment = attachment->next) {
wer_remove_attachment(wer_data, attachment);
}

sentry__scope_remove_observer(scope, wer_data->observer);
wer_data->scope = NULL;
wer_data->observer = NULL;
}

sentry_integration_t *
sentry_integration_wer_new(void)
{
sentry_integration_t *integration = SENTRY_MAKE(sentry_integration_t);
if (!integration) {
return NULL;
}

integration->data = SENTRY_MAKE(sentry_integration_wer_data_t);
if (!integration->data) {
sentry_free(integration);
return NULL;
}

integration->register_func = register_wer;
integration->unregister_func = unregister_wer;
integration->free_func = sentry_integration_wer_free;

return integration;
}
11 changes: 11 additions & 0 deletions src/integrations/sentry_integration_wer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifndef SENTRY_INTEGRATION_WER_H_INCLUDED
#define SENTRY_INTEGRATION_WER_H_INCLUDED

#include "sentry_integration.h"

/**
* Creates the WER integration.
*/
sentry_integration_t *sentry_integration_wer_new(void);

#endif
7 changes: 7 additions & 0 deletions src/sentry_options.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
# include "integrations/sentry_integration_qt.h"
#endif

#ifdef SENTRY_INTEGRATION_WER
# include "integrations/sentry_integration_wer.h"
#endif

static double
normalize_sample_rate(double sample_rate, double default_value)
{
Expand Down Expand Up @@ -126,6 +130,9 @@ sentry_options_new(void)
#ifdef SENTRY_INTEGRATION_QT
sentry__options_add_integration(opts, sentry_integration_qt_new());
#endif
#ifdef SENTRY_INTEGRATION_WER
sentry__options_add_integration(opts, sentry_integration_wer_new());
#endif

return opts;
}
Expand Down
Loading
Loading