From 7f8e6556d286a0035291495f4fd588cecfc1266c Mon Sep 17 00:00:00 2001 From: Govind Yadav Date: Sun, 16 Aug 2026 17:34:41 +0530 Subject: [PATCH 1/4] feat(windows): add WINE runtime context --- CHANGELOG.md | 1 + src/sentry_os.c | 65 +++++++++++++++++++++++++++++++++++++++++ src/sentry_os.h | 14 +++++++++ src/sentry_scope.c | 8 +++++ tests/unit/test_os.c | 69 ++++++++++++++++++++++++++++++++++++++++++++ tests/unit/tests.inc | 1 + 6 files changed, 158 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5056684763..4d00891753 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ **Features**: +- Windows: report WINE runtime and host metadata in a separate `wine` context. ([#1004](https://github.com/getsentry/sentry-native/issues/1004)) - Native/Windows: capture WER report ID and expose as `contexts.wer.report_id` in crash events when the WER integration is enabled. ([#1970](https://github.com/getsentry/sentry-native/pull/1970)) - Add `sentry_set_tags` and `sentry_scope_set_tags` for updating multiple tags with a single scope flush, improving bulk-update performance. ([#1993](https://github.com/getsentry/sentry-native/pull/1993)) - Add `sentry_get_last_event_id` and `sentry_scope_get_last_event_id` for retrieving the last event ID captured with the global or given scope, respectively. ([#1992](https://github.com/getsentry/sentry-native/pull/1992)) diff --git a/src/sentry_os.c b/src/sentry_os.c index e1bb18cb94..f45300ca35 100644 --- a/src/sentry_os.c +++ b/src/sentry_os.c @@ -178,6 +178,71 @@ sentry__get_windows_version(windows_version_t *win_ver) return 1; } +static void +set_wine_context_string( + sentry_value_t context, const char *key, const char *value) +{ + if (value && value[0]) { + sentry_value_set_by_key(context, key, sentry_value_new_string(value)); + } +} + +sentry_value_t +sentry__make_wine_context(sentry__wine_get_version_t wine_get_version, + sentry__wine_get_build_id_t wine_get_build_id, + sentry__wine_get_host_version_t wine_get_host_version) +{ + if (!wine_get_version) { + return sentry_value_new_null(); + } + + const char *version = wine_get_version(); + if (!version || !version[0]) { + return sentry_value_new_null(); + } + + sentry_value_t context = sentry_value_new_object(); + if (sentry_value_is_null(context)) { + return context; + } + + set_wine_context_string(context, "version", version); + if (wine_get_build_id) { + set_wine_context_string(context, "build", wine_get_build_id()); + } + if (wine_get_host_version) { + const char *sysname = NULL; + const char *release = NULL; + wine_get_host_version(&sysname, &release); + set_wine_context_string(context, "sysname", sysname); + set_wine_context_string(context, "release", release); + } + + sentry_value_freeze(context); + return context; +} + +sentry_value_t +sentry__get_wine_context(void) +{ + const HMODULE ntdll = GetModuleHandleW(L"ntdll.dll"); + if (!ntdll) { + return sentry_value_new_null(); + } + + const sentry__wine_get_version_t wine_get_version + = (sentry__wine_get_version_t)GetProcAddress(ntdll, "wine_get_version"); + const sentry__wine_get_build_id_t wine_get_build_id + = (sentry__wine_get_build_id_t)GetProcAddress( + ntdll, "wine_get_build_id"); + const sentry__wine_get_host_version_t wine_get_host_version + = (sentry__wine_get_host_version_t)GetProcAddress( + ntdll, "wine_get_host_version"); + + return sentry__make_wine_context( + wine_get_version, wine_get_build_id, wine_get_host_version); +} + # endif // !defined(SENTRY_PLATFORM_XBOX) sentry_value_t diff --git a/src/sentry_os.h b/src/sentry_os.h index 41d1b6b14b..976e5d8fc8 100644 --- a/src/sentry_os.h +++ b/src/sentry_os.h @@ -52,6 +52,20 @@ typedef struct { int sentry__get_kernel_version(windows_version_t *win_ver); int sentry__get_windows_version(windows_version_t *win_ver); + +# if !defined(SENTRY_PLATFORM_XBOX) +typedef const char *(CDECL *sentry__wine_get_version_t)(void); +typedef const char *(CDECL *sentry__wine_get_build_id_t)(void); +typedef void(CDECL *sentry__wine_get_host_version_t)( + const char **sysname, const char **release); + +sentry_value_t sentry__make_wine_context( + sentry__wine_get_version_t wine_get_version, + sentry__wine_get_build_id_t wine_get_build_id, + sentry__wine_get_host_version_t wine_get_host_version); +sentry_value_t sentry__get_wine_context(void); +# endif + void sentry__set_default_thread_stack_guarantee(void); void sentry__init_cached_kernel32_functions(void); void sentry__get_system_time(LPFILETIME filetime); diff --git a/src/sentry_scope.c b/src/sentry_scope.c index 0bb7057e14..35a0cc654b 100644 --- a/src/sentry_scope.c +++ b/src/sentry_scope.c @@ -109,6 +109,14 @@ get_scope(void) init_scope(&g_scope); g_scope.user = sentry_value_new_object(); sentry_value_set_by_key(g_scope.contexts, "os", sentry__get_os_context()); +#if defined(SENTRY_PLATFORM_WINDOWS) && !defined(SENTRY_PLATFORM_XBOX) + sentry_value_t wine_context = sentry__get_wine_context(); + if (!sentry_value_is_null(wine_context)) { + sentry_value_set_by_key(g_scope.contexts, "wine", wine_context); + } else { + sentry_value_decref(wine_context); + } +#endif g_scope.client_sdk = get_client_sdk(); g_scope_initialized = true; diff --git a/tests/unit/test_os.c b/tests/unit/test_os.c index 5a4d3337ce..0db5576d7f 100644 --- a/tests/unit/test_os.c +++ b/tests/unit/test_os.c @@ -200,6 +200,33 @@ extern void(WINAPI *g_kernel32_GetCurrentThreadStackLimits)( PULONG_PTR, PULONG_PTR); static size_t g_kernel32_SetThreadStackGuaranteeCalled = 0; +# if !defined(SENTRY_PLATFORM_XBOX) +static const char *CDECL +wine_get_version(void) +{ + return "9.0"; +} + +static const char *CDECL +wine_get_empty_version(void) +{ + return ""; +} + +static const char *CDECL +wine_get_build_id(void) +{ + return "wine-9.0"; +} + +static void CDECL +wine_get_host_version(const char **sysname, const char **release) +{ + *sysname = "Linux"; + *release = "6.8.0"; +} +# endif + static BOOL WINAPI no_previous_guarantee(PULONG guarantee) { @@ -295,6 +322,48 @@ stack_reserve_exact_factor_minus_one(PULONG_PTR low, PULONG_PTR high) } #endif +SENTRY_TEST(wine_context) +{ +#if !defined(SENTRY_PLATFORM_WINDOWS) || defined(SENTRY_PLATFORM_XBOX) + SKIP_TEST(); +#else + sentry_value_t context = sentry__make_wine_context( + wine_get_version, wine_get_build_id, wine_get_host_version); + TEST_CHECK(!sentry_value_is_null(context)); + TEST_CHECK(sentry_value_is_frozen(context)); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(sentry_value_get_by_key(context, "version")), + "9.0"); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(sentry_value_get_by_key(context, "build")), + "wine-9.0"); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(sentry_value_get_by_key(context, "sysname")), + "Linux"); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(sentry_value_get_by_key(context, "release")), + "6.8.0"); + sentry_value_decref(context); + + context = sentry__make_wine_context(wine_get_version, NULL, NULL); + TEST_CHECK(!sentry_value_is_null(context)); + TEST_CHECK(sentry_value_is_null(sentry_value_get_by_key(context, "build"))); + TEST_CHECK( + sentry_value_is_null(sentry_value_get_by_key(context, "sysname"))); + TEST_CHECK( + sentry_value_is_null(sentry_value_get_by_key(context, "release"))); + sentry_value_decref(context); + + context = sentry__make_wine_context(NULL, NULL, NULL); + TEST_CHECK(sentry_value_is_null(context)); + sentry_value_decref(context); + + context = sentry__make_wine_context(wine_get_empty_version, NULL, NULL); + TEST_CHECK(sentry_value_is_null(context)); + sentry_value_decref(context); +#endif +} + SENTRY_TEST(stack_guarantee) { #if !defined(SENTRY_PLATFORM_WINDOWS) diff --git a/tests/unit/tests.inc b/tests/unit/tests.inc index 98a99e31c0..615da711fa 100644 --- a/tests/unit/tests.inc +++ b/tests/unit/tests.inc @@ -507,6 +507,7 @@ XX(value_uint64) XX(value_unicode) XX(value_user) XX(value_wrong_type) +XX(wine_context) XX(write_envelope_partial_write_fails) XX(write_raw_envelope_to_file) XX(writer_byte_count_stops_after_failure) From 293a4a983a4cb17a4e8791e743bb622c291b476a Mon Sep 17 00:00:00 2001 From: Govind Yadav Date: Tue, 18 Aug 2026 16:43:36 +0530 Subject: [PATCH 2/4] feat(windows): detect Proton runtime variants --- CHANGELOG.md | 2 +- src/sentry_os.c | 191 ++++++++++++++++++++++++++++++++++++------- src/sentry_os.h | 8 +- tests/unit/test_os.c | 94 ++++++++++++++------- 4 files changed, 228 insertions(+), 67 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d00891753..0cbdf6b626 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ **Features**: -- Windows: report WINE runtime and host metadata in a separate `wine` context. ([#1004](https://github.com/getsentry/sentry-native/issues/1004)) +- Windows: report WINE and Proton metadata in a separate runtime context. ([#1995](https://github.com/getsentry/sentry-native/pull/1995)) - Native/Windows: capture WER report ID and expose as `contexts.wer.report_id` in crash events when the WER integration is enabled. ([#1970](https://github.com/getsentry/sentry-native/pull/1970)) - Add `sentry_set_tags` and `sentry_scope_set_tags` for updating multiple tags with a single scope flush, improving bulk-update performance. ([#1993](https://github.com/getsentry/sentry-native/pull/1993)) - Add `sentry_get_last_event_id` and `sentry_scope_get_last_event_id` for retrieving the last event ID captured with the global or given scope, respectively. ([#1992](https://github.com/getsentry/sentry-native/pull/1992)) diff --git a/src/sentry_os.c b/src/sentry_os.c index f45300ca35..59a4eca2a5 100644 --- a/src/sentry_os.c +++ b/src/sentry_os.c @@ -1,4 +1,5 @@ #include "sentry_os.h" +#include "sentry_path.h" #include "sentry_slice.h" #include "sentry_string.h" #if defined(SENTRY_PLATFORM_LINUX) || defined(SENTRY_PLATFORM_WINDOWS) @@ -178,46 +179,177 @@ sentry__get_windows_version(windows_version_t *win_ver) return 1; } -static void -set_wine_context_string( - sentry_value_t context, const char *key, const char *value) +static bool +string_ends_with(const char *value, size_t value_len, const char *suffix) +{ + const size_t suffix_len = strlen(suffix); + return value_len >= suffix_len + && memcmp(value + value_len - suffix_len, suffix, suffix_len) == 0; +} + +static char * +make_wine_path(const char *path, const char *suffix) { - if (value && value[0]) { - sentry_value_set_by_key(context, key, sentry_value_new_string(value)); + sentry_stringbuilder_t sb; + sentry__stringbuilder_init(&sb); + if (sentry__stringbuilder_append(&sb, "Z:") + || sentry__stringbuilder_append(&sb, path) + || sentry__stringbuilder_append(&sb, suffix)) { + sentry__stringbuilder_cleanup(&sb); + return NULL; } + return sentry__stringbuilder_into_string(&sb); +} + +static char * +read_wine_file(const char *path) +{ + sentry_path_t *file_path = sentry__path_from_str(path); + char *contents + = file_path ? sentry__path_read_to_buffer(file_path, NULL) : NULL; + sentry__path_free(file_path); + return contents; +} + +static char * +get_proton_version(bool *is_proton) +{ + *is_proton = false; + const char *compat_path = getenv("STEAM_COMPAT_DATA_PATH"); + if (!compat_path || !compat_path[0]) { + return NULL; + } + + char *config_path = make_wine_path(compat_path, "/config_info"); + char *config = config_path ? read_wine_file(config_path) : NULL; + sentry_free(config_path); + if (!config) { + return NULL; + } + + char *fonts_path = strchr(config, '\n'); + if (!fonts_path) { + sentry_free(config); + return NULL; + } + fonts_path++; + while (*fonts_path == ' ' || *fonts_path == '\t') { + fonts_path++; + } + size_t fonts_path_len = strcspn(fonts_path, "\r\n"); + while (fonts_path_len > 0 + && (fonts_path[fonts_path_len - 1] == ' ' + || fonts_path[fonts_path_len - 1] == '\t')) { + fonts_path_len--; + } + + const char *fonts_suffix = NULL; + if (string_ends_with(fonts_path, fonts_path_len, "/files/share/fonts/")) { + fonts_suffix = "/files/share/fonts/"; + } else if (string_ends_with( + fonts_path, fonts_path_len, "/dist/share/fonts/")) { + fonts_suffix = "/dist/share/fonts/"; + } + if (!fonts_suffix) { + sentry_free(config); + return NULL; + } + + const size_t root_len = fonts_path_len - strlen(fonts_suffix); + char *proton_root = sentry__string_clone_n(fonts_path, root_len); + sentry_free(config); + if (!proton_root) { + return NULL; + } + + char *proton_path = make_wine_path(proton_root, "/proton"); + sentry_path_t *proton_file = sentry__path_from_str(proton_path); + *is_proton = proton_file && sentry__path_is_file(proton_file); + sentry__path_free(proton_file); + sentry_free(proton_path); + + char *version_path = make_wine_path(proton_root, "/version"); + sentry_free(proton_root); + char *version_file = version_path ? read_wine_file(version_path) : NULL; + sentry_free(version_path); + if (!version_file) { + return NULL; + } + + char *version = strpbrk(version_file, " \t"); + if (!version) { + sentry_free(version_file); + return NULL; + } + while (*version == ' ' || *version == '\t') { + version++; + } + size_t version_len = strcspn(version, "\r\n"); + while (version_len > 0 + && (version[version_len - 1] == ' ' + || version[version_len - 1] == '\t')) { + version_len--; + } + + char *result + = version_len ? sentry__string_clone_n(version, version_len) : NULL; + sentry_free(version_file); + return result; +} + +static bool +string_starts_with(const char *value, const char *prefix) +{ + const size_t value_len = strlen(value); + const size_t prefix_len = strlen(prefix); + return value_len >= prefix_len && memcmp(value, prefix, prefix_len) == 0; } sentry_value_t sentry__make_wine_context(sentry__wine_get_version_t wine_get_version, - sentry__wine_get_build_id_t wine_get_build_id, - sentry__wine_get_host_version_t wine_get_host_version) + const char *proton_version, bool is_proton) { if (!wine_get_version) { return sentry_value_new_null(); } - const char *version = wine_get_version(); - if (!version || !version[0]) { + const char *runtime_name = "Wine"; + const char *runtime_version = wine_get_version(); + if (!runtime_version || !runtime_version[0]) { return sentry_value_new_null(); } + if (proton_version && proton_version[0]) { + runtime_version = proton_version; + if (is_proton) { + if (string_starts_with(proton_version, "proton-")) { + runtime_name = "Proton"; + runtime_version += strlen("proton-"); + } else if (string_starts_with(proton_version, "experimental-")) { + runtime_name = "Proton Experimental"; + runtime_version += strlen("experimental-"); + } else if (string_starts_with(proton_version, "GE-Proton")) { + runtime_name = "GE-Proton"; + runtime_version += strlen("GE-Proton"); + } else if (string_starts_with(proton_version, "hotfix-")) { + runtime_name = "Proton Hotfix"; + runtime_version += strlen("hotfix-"); + } else { + runtime_name = "Proton Custom"; + } + } + } + sentry_value_t context = sentry_value_new_object(); if (sentry_value_is_null(context)) { return context; } - - set_wine_context_string(context, "version", version); - if (wine_get_build_id) { - set_wine_context_string(context, "build", wine_get_build_id()); - } - if (wine_get_host_version) { - const char *sysname = NULL; - const char *release = NULL; - wine_get_host_version(&sysname, &release); - set_wine_context_string(context, "sysname", sysname); - set_wine_context_string(context, "release", release); - } - + sentry_value_set_by_key( + context, "type", sentry_value_new_string("runtime")); + sentry_value_set_by_key( + context, "name", sentry_value_new_string(runtime_name)); + sentry_value_set_by_key( + context, "version", sentry_value_new_string(runtime_version)); sentry_value_freeze(context); return context; } @@ -232,15 +364,12 @@ sentry__get_wine_context(void) const sentry__wine_get_version_t wine_get_version = (sentry__wine_get_version_t)GetProcAddress(ntdll, "wine_get_version"); - const sentry__wine_get_build_id_t wine_get_build_id - = (sentry__wine_get_build_id_t)GetProcAddress( - ntdll, "wine_get_build_id"); - const sentry__wine_get_host_version_t wine_get_host_version - = (sentry__wine_get_host_version_t)GetProcAddress( - ntdll, "wine_get_host_version"); - - return sentry__make_wine_context( - wine_get_version, wine_get_build_id, wine_get_host_version); + bool is_proton = false; + char *proton_version = get_proton_version(&is_proton); + sentry_value_t context = sentry__make_wine_context( + wine_get_version, proton_version, is_proton); + sentry_free(proton_version); + return context; } # endif // !defined(SENTRY_PLATFORM_XBOX) diff --git a/src/sentry_os.h b/src/sentry_os.h index 976e5d8fc8..ed701dfb92 100644 --- a/src/sentry_os.h +++ b/src/sentry_os.h @@ -55,14 +55,10 @@ int sentry__get_windows_version(windows_version_t *win_ver); # if !defined(SENTRY_PLATFORM_XBOX) typedef const char *(CDECL *sentry__wine_get_version_t)(void); -typedef const char *(CDECL *sentry__wine_get_build_id_t)(void); -typedef void(CDECL *sentry__wine_get_host_version_t)( - const char **sysname, const char **release); sentry_value_t sentry__make_wine_context( - sentry__wine_get_version_t wine_get_version, - sentry__wine_get_build_id_t wine_get_build_id, - sentry__wine_get_host_version_t wine_get_host_version); + sentry__wine_get_version_t wine_get_version, const char *proton_version, + bool is_proton); sentry_value_t sentry__get_wine_context(void); # endif diff --git a/tests/unit/test_os.c b/tests/unit/test_os.c index 0db5576d7f..90e47ea2e7 100644 --- a/tests/unit/test_os.c +++ b/tests/unit/test_os.c @@ -213,18 +213,6 @@ wine_get_empty_version(void) return ""; } -static const char *CDECL -wine_get_build_id(void) -{ - return "wine-9.0"; -} - -static void CDECL -wine_get_host_version(const char **sysname, const char **release) -{ - *sysname = "Linux"; - *release = "6.8.0"; -} # endif static BOOL WINAPI @@ -327,38 +315,86 @@ SENTRY_TEST(wine_context) #if !defined(SENTRY_PLATFORM_WINDOWS) || defined(SENTRY_PLATFORM_XBOX) SKIP_TEST(); #else - sentry_value_t context = sentry__make_wine_context( - wine_get_version, wine_get_build_id, wine_get_host_version); + sentry_value_t context + = sentry__make_wine_context(wine_get_version, NULL, false); TEST_CHECK(!sentry_value_is_null(context)); TEST_CHECK(sentry_value_is_frozen(context)); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(sentry_value_get_by_key(context, "type")), + "runtime"); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(sentry_value_get_by_key(context, "name")), + "Wine"); TEST_CHECK_STRING_EQUAL( sentry_value_as_string(sentry_value_get_by_key(context, "version")), "9.0"); + sentry_value_decref(context); + + context + = sentry__make_wine_context(wine_get_version, "proton-10.0-4", true); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(sentry_value_get_by_key(context, "name")), + "Proton"); TEST_CHECK_STRING_EQUAL( - sentry_value_as_string(sentry_value_get_by_key(context, "build")), - "wine-9.0"); + sentry_value_as_string(sentry_value_get_by_key(context, "version")), + "10.0-4"); + sentry_value_decref(context); + + context = sentry__make_wine_context( + wine_get_version, "experimental-10.0-20260113", true); TEST_CHECK_STRING_EQUAL( - sentry_value_as_string(sentry_value_get_by_key(context, "sysname")), - "Linux"); + sentry_value_as_string(sentry_value_get_by_key(context, "name")), + "Proton Experimental"); TEST_CHECK_STRING_EQUAL( - sentry_value_as_string(sentry_value_get_by_key(context, "release")), - "6.8.0"); + sentry_value_as_string(sentry_value_get_by_key(context, "version")), + "10.0-20260113"); sentry_value_decref(context); - context = sentry__make_wine_context(wine_get_version, NULL, NULL); - TEST_CHECK(!sentry_value_is_null(context)); - TEST_CHECK(sentry_value_is_null(sentry_value_get_by_key(context, "build"))); - TEST_CHECK( - sentry_value_is_null(sentry_value_get_by_key(context, "sysname"))); - TEST_CHECK( - sentry_value_is_null(sentry_value_get_by_key(context, "release"))); + context + = sentry__make_wine_context(wine_get_version, "GE-Proton9-27", true); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(sentry_value_get_by_key(context, "name")), + "GE-Proton"); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(sentry_value_get_by_key(context, "version")), + "9-27"); + sentry_value_decref(context); + + context + = sentry__make_wine_context(wine_get_version, "hotfix-20251031", true); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(sentry_value_get_by_key(context, "name")), + "Proton Hotfix"); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(sentry_value_get_by_key(context, "version")), + "20251031"); + sentry_value_decref(context); + + context + = sentry__make_wine_context(wine_get_version, "custom-tool-1", true); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(sentry_value_get_by_key(context, "name")), + "Proton Custom"); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(sentry_value_get_by_key(context, "version")), + "custom-tool-1"); + sentry_value_decref(context); + + context + = sentry__make_wine_context(wine_get_version, "wine-ge-8-26", false); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(sentry_value_get_by_key(context, "name")), + "Wine"); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(sentry_value_get_by_key(context, "version")), + "wine-ge-8-26"); sentry_value_decref(context); - context = sentry__make_wine_context(NULL, NULL, NULL); + context = sentry__make_wine_context(NULL, NULL, false); TEST_CHECK(sentry_value_is_null(context)); sentry_value_decref(context); - context = sentry__make_wine_context(wine_get_empty_version, NULL, NULL); + context = sentry__make_wine_context(wine_get_empty_version, NULL, false); TEST_CHECK(sentry_value_is_null(context)); sentry_value_decref(context); #endif From d2696f4a51f50269cef740244f7d3227d32ab651 Mon Sep 17 00:00:00 2001 From: Govind Yadav Date: Wed, 19 Aug 2026 11:17:31 +0530 Subject: [PATCH 3/4] fix(windows): omit empty Proton runtime version --- src/sentry_os.c | 6 ++++-- tests/unit/test_os.c | 9 +++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/sentry_os.c b/src/sentry_os.c index 59a4eca2a5..7bd28aa674 100644 --- a/src/sentry_os.c +++ b/src/sentry_os.c @@ -348,8 +348,10 @@ sentry__make_wine_context(sentry__wine_get_version_t wine_get_version, context, "type", sentry_value_new_string("runtime")); sentry_value_set_by_key( context, "name", sentry_value_new_string(runtime_name)); - sentry_value_set_by_key( - context, "version", sentry_value_new_string(runtime_version)); + if (runtime_version[0]) { + sentry_value_set_by_key( + context, "version", sentry_value_new_string(runtime_version)); + } sentry_value_freeze(context); return context; } diff --git a/tests/unit/test_os.c b/tests/unit/test_os.c index 90e47ea2e7..4f260a418a 100644 --- a/tests/unit/test_os.c +++ b/tests/unit/test_os.c @@ -360,6 +360,15 @@ SENTRY_TEST(wine_context) "9-27"); sentry_value_decref(context); + context + = sentry__make_wine_context(wine_get_version, "GE-Proton", true); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(sentry_value_get_by_key(context, "name")), + "GE-Proton"); + TEST_CHECK(sentry_value_is_null( + sentry_value_get_by_key(context, "version"))); + sentry_value_decref(context); + context = sentry__make_wine_context(wine_get_version, "hotfix-20251031", true); TEST_CHECK_STRING_EQUAL( From 28b9db1ba192686fe55640d092cb2dcdb8de12ec Mon Sep 17 00:00:00 2001 From: Govind Yadav Date: Thu, 20 Aug 2026 13:25:26 +0530 Subject: [PATCH 4/4] fix Wine environment path encoding --- src/sentry_os.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sentry_os.c b/src/sentry_os.c index 7bd28aa674..b67a3d0cc1 100644 --- a/src/sentry_os.c +++ b/src/sentry_os.c @@ -215,12 +215,15 @@ static char * get_proton_version(bool *is_proton) { *is_proton = false; - const char *compat_path = getenv("STEAM_COMPAT_DATA_PATH"); + char *compat_path + = sentry__string_from_wstr(_wgetenv(L"STEAM_COMPAT_DATA_PATH")); if (!compat_path || !compat_path[0]) { + sentry_free(compat_path); return NULL; } char *config_path = make_wine_path(compat_path, "/config_info"); + sentry_free(compat_path); char *config = config_path ? read_wine_file(config_path) : NULL; sentry_free(config_path); if (!config) {