Reject older versions of PipeWire than built against
Newer versions of PipeWire may add things to public structures. For example, pw_buffer::requested added in 0.3.49. Building against 0.3.49 or newer, but then running with 0.3.48 could result in invalid accesses since the returned pw_buffer objects are shorter than the definition says to expect, creating undefined behavior. Even if explicit access to the additional fields is protected by a runtime check, the language allows the compiler to assume a pointer to a pw_buffer object contains a complete pw_buffer, allowing the optimizer to access the field earlier than the check (with the check only controlling if the value gets used). Another example is pw_time, which had a few fields added in 0.3.50 along with a function, pw_stream_get_time_n, that provides the size of the pw_time struct the application is using (so the library knows what version of the struct it has to fill in). If a later version adds a new field, running it with an older version will either fail (due to the library getting a size larger than it knows about) or silently leave the newer fields as garbage.
This commit is contained in:
parent
10e863d1b4
commit
96756acc52
@ -115,12 +115,26 @@ constexpr char pwireDevice[] = "PipeWire Output";
|
||||
constexpr char pwireInput[] = "PipeWire Input";
|
||||
|
||||
|
||||
bool check_version(const char *version)
|
||||
{
|
||||
/* There doesn't seem to be a function to get the version as an integer, so
|
||||
* instead we have to parse the string, which hopefully won't break in the
|
||||
* future.
|
||||
*/
|
||||
int major{0}, minor{0}, revision{0};
|
||||
int ret{sscanf(version, "%d.%d.%d", &major, &minor, &revision)};
|
||||
if(ret == 3 && PW_CHECK_VERSION(major, minor, revision))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DYNLOAD
|
||||
#define PWIRE_FUNCS(MAGIC) \
|
||||
MAGIC(pw_context_connect) \
|
||||
MAGIC(pw_context_destroy) \
|
||||
MAGIC(pw_context_new) \
|
||||
MAGIC(pw_core_disconnect) \
|
||||
MAGIC(pw_get_library_version) \
|
||||
MAGIC(pw_init) \
|
||||
MAGIC(pw_properties_free) \
|
||||
MAGIC(pw_properties_new) \
|
||||
@ -199,6 +213,7 @@ bool pwire_load()
|
||||
#define pw_context_destroy ppw_context_destroy
|
||||
#define pw_context_new ppw_context_new
|
||||
#define pw_core_disconnect ppw_core_disconnect
|
||||
#define pw_get_library_version ppw_get_library_version
|
||||
#define pw_init ppw_init
|
||||
#define pw_properties_free ppw_properties_free
|
||||
#define pw_properties_new ppw_properties_new
|
||||
@ -1930,6 +1945,15 @@ bool PipeWireBackendFactory::init()
|
||||
if(!pwire_load())
|
||||
return false;
|
||||
|
||||
const char *version{pw_get_library_version()};
|
||||
if(!check_version(version))
|
||||
{
|
||||
WARN("PipeWire version \"%s\" too old (%s or newer required)\n", version,
|
||||
pw_get_headers_version());
|
||||
return false;
|
||||
}
|
||||
TRACE("Found PipeWire version \"%s\" (%s or newer)\n", version, pw_get_headers_version());
|
||||
|
||||
pw_init(0, nullptr);
|
||||
if(!gEventHandler.init())
|
||||
return false;
|
||||
|
Loading…
x
Reference in New Issue
Block a user