From 5e8a8ea41f73e4e24ec91382b7e6a697097b48aa Mon Sep 17 00:00:00 2001 From: "Mr.X" <94920917+MRX-72@users.noreply.github.com> Date: Wed, 23 Sep 2026 15:18:49 +0530 Subject: [PATCH] Add yr_get_version to report the version of the library loaded at runtime (#2247) YR_MAJOR_VERSION, YR_MINOR_VERSION and YR_MICRO_VERSION are fixed when the caller is compiled, so a program linked against a shared libyara has no way to tell which version it actually loaded. Distros ship libyara.so in its own package precisely so it can be updated independently of its consumers, which is exactly the case the macros cannot describe. Add yr_get_version(), which reports the version of the library that is actually loaded. Any argument may be NULL if the caller does not need that component, and since the function touches no global state it can be called before yr_initialize. Closes #2136 --------- Co-authored-by: Victor M. Alvarez --- docs/capi.rst | 13 +++++++++++++ libyara/include/yara/libyara.h | 6 ++++++ libyara/libyara.c | 26 +++++++++++++++++++++++++- tests/test-version.c | 22 ++++++++++++++++++++++ 4 files changed, 66 insertions(+), 1 deletion(-) diff --git a/docs/capi.rst b/docs/capi.rst index 646a5994..f5da3dab 100644 --- a/docs/capi.rst +++ b/docs/capi.rst @@ -510,6 +510,19 @@ Functions success another error code in case of error. The list of possible return codes vary according to the modules compiled into YARA. +.. c:function:: void yr_get_version(int* major, int* minor, int* micro) + + Get the version of the library loaded at runtime. The + :c:macro:`YR_MAJOR_VERSION`, :c:macro:`YR_MINOR_VERSION` and + :c:macro:`YR_MICRO_VERSION` macros are fixed when your program is compiled, + so a program linked against a shared ``libyara`` cannot use them to tell + which version it actually got. This function reports that. + + Any argument may be ``NULL`` if you do not need that component. Unlike the + rest of the API, this may be called before :c:func:`yr_initialize`. + + .. versionadded:: 4.6.0 + .. c:function:: int yr_compiler_create(YR_COMPILER** compiler) Create a YARA compiler. You must pass the address of a pointer to a diff --git a/libyara/include/yara/libyara.h b/libyara/include/yara/libyara.h index 1dad7fb6..334e71bf 100644 --- a/libyara/include/yara/libyara.h +++ b/libyara/include/yara/libyara.h @@ -87,6 +87,12 @@ YR_API int yr_initialize(void); YR_API int yr_finalize(void); +// Returns the version of the library actually loaded at runtime, which is not +// necessarily the one the caller was compiled against. Any of the arguments +// may be NULL if that component is not needed. Unlike the rest of the API this +// can be called before yr_initialize. +YR_API void yr_get_version(int* major, int* minor, int* micro); + YR_API int yr_set_configuration(YR_CONFIG_NAME, void*); YR_API int yr_set_configuration_uint32(YR_CONFIG_NAME, uint32_t); YR_API int yr_set_configuration_uint64(YR_CONFIG_NAME, uint64_t); diff --git a/libyara/libyara.c b/libyara/libyara.c index f8331f20..7379e133 100644 --- a/libyara/libyara.c +++ b/libyara/libyara.c @@ -546,4 +546,28 @@ YR_API int yr_get_configuration_uint64(YR_CONFIG_NAME name, uint64_t *value) default: return ERROR_INVALID_ARGUMENT; } -} \ No newline at end of file +} + +//////////////////////////////////////////////////////////////////////////////// +// Get the version of the library loaded at runtime. +// +// The YR_MAJOR_VERSION, YR_MINOR_VERSION and YR_MICRO_VERSION macros are fixed +// at compile time, so a program linked against libyara.so cannot use them to +// tell which version it ended up with. This function reports the version of +// the library that is actually loaded. +// +// Any argument may be NULL if the caller does not need that component. This +// function does not depend on any global state, so unlike the rest of the API +// it can be called before yr_initialize. +// +YR_API void yr_get_version(int *major, int *minor, int *micro) +{ + if (major != NULL) + *major = YR_MAJOR_VERSION; + + if (minor != NULL) + *minor = YR_MINOR_VERSION; + + if (micro != NULL) + *micro = YR_MICRO_VERSION; +} diff --git a/tests/test-version.c b/tests/test-version.c index 70b56a51..df6dbcaa 100644 --- a/tests/test-version.c +++ b/tests/test-version.c @@ -42,6 +42,28 @@ int main(int argc, char **argv) int result = strcmp(PACKAGE_VERSION, YR_VERSION); + // yr_get_version must report the same version the macros carry, and must + // work before yr_initialize and with any argument omitted. + + int major = -1, minor = -1, micro = -1; + + yr_get_version(&major, &minor, µ); + + if (major != YR_MAJOR_VERSION || minor != YR_MINOR_VERSION || + micro != YR_MICRO_VERSION) + result = 1; + + major = minor = micro = -1; + + yr_get_version(&major, NULL, NULL); + yr_get_version(NULL, &minor, NULL); + yr_get_version(NULL, NULL, µ); + yr_get_version(NULL, NULL, NULL); + + if (major != YR_MAJOR_VERSION || minor != YR_MINOR_VERSION || + micro != YR_MICRO_VERSION) + result = 1; + YR_DEBUG_FPRINTF( 1, stderr, "} = %d // %s() in %s\n", result, __FUNCTION__, argv[0]);