Fix a segfault if JACK libs are missing (#8026)

Fix a segmentation fault that occurs if the JACK libraries are not
installed. In that case `jack_client_open` which is called through
`lib_weakjack` will return a `nullptr` for the client. Subsequent calls
to `jack_client_open` do not check for `nullptr` in the library so we
have to do this ourselves to prevent the segmentation fault. The check
is added to `AudioJack::setupWidget::getAudioPortNames`.

Extract the printing of the JACK status into the function
`printJackStatus` as its functionality is needed several times.

Print a warning and the status in `AudioJack::setupWidget::setupWidget`.

## Code review changes

Use `std::printf` and `std::fprintf`and print to `stderr` whenever fitting.

---------

Co-authored-by: Andrew Wiltshire <62200778+AW1534@users.noreply.github.com>
This commit is contained in:
Michael Gregorius
2025-08-06 18:12:56 +02:00
committed by GitHub
parent dabfe6f95b
commit 88ed51edb9

View File

@@ -40,6 +40,8 @@
#include "MainWindow.h"
#include "MidiJack.h"
#include <cstdio>
namespace
{
@@ -57,6 +59,21 @@ QString getInputKeyByChannel(size_t channel)
return "input" + QString::number(channel + 1);
}
void printJackStatus(jack_status_t status)
{
std::fprintf(stderr, "Status: 0x%2.0x\n", static_cast<unsigned int>(status));
if (status & JackFailure)
{
std::fprintf(stderr, "Overall operation failed. JACK dependencies might need to be installed.\n");
}
if (status & JackServerFailed)
{
std::fprintf(stderr, "Could not connect to JACK server.\n");
}
}
}
namespace lmms
@@ -172,15 +189,16 @@ bool AudioJack::initJackClient()
m_client = jack_client_open(clientName.toLatin1().constData(), JackNullOption, &status, serverName);
if (m_client == nullptr)
{
printf("jack_client_open() failed, status 0x%2.0x\n", status);
if (status & JackServerFailed) { printf("Could not connect to JACK server.\n"); }
std::fprintf(stderr, "jack_client_open() failed, ");
printJackStatus(status);
return false;
}
if (status & JackNameNotUnique)
{
printf( "there's already a client with name '%s', so unique "
"name '%s' was assigned\n",
clientName.toLatin1().constData(), jack_get_client_name(m_client));
std::printf("there's already a client with name '%s', so unique "
"name '%s' was assigned\n",
clientName.toLatin1().constData(), jack_get_client_name(m_client));
}
resizeInputBuffer(jack_get_buffer_size(m_client));
@@ -212,7 +230,7 @@ bool AudioJack::initJackClient()
if (m_outputPorts.back() == nullptr)
{
printf("no more JACK-ports available!\n");
std::fprintf(stderr, "no more JACK-ports available!\n");
return false;
}
}
@@ -230,14 +248,14 @@ void AudioJack::resizeInputBuffer(jack_nframes_t nframes)
void AudioJack::attemptToConnect(size_t index, const char *lmms_port_type, const char *source_port, const char *destination_port)
{
printf("Attempting to reconnect %s port %u: %s -> %s", lmms_port_type, static_cast<unsigned int>(index), source_port, destination_port);
std::printf("Attempting to reconnect %s port %u: %s -> %s", lmms_port_type, static_cast<unsigned int>(index), source_port, destination_port);
if (!jack_connect(m_client, source_port, destination_port))
{
printf(" - Success!\n");
std::printf(" - Success!\n");
}
else
{
printf(" - Failure\n");
std::printf(" - Failure\n");
}
}
@@ -247,7 +265,7 @@ void AudioJack::attemptToReconnectOutput(size_t outputIndex, const QString& targ
if (targetPort == disconnectedRepresentation)
{
printf("Output port %u is not connected.\n", static_cast<unsigned int>(outputIndex));
std::fprintf(stderr, "Output port %u is not connected.\n", static_cast<unsigned int>(outputIndex));
return;
}
@@ -263,7 +281,7 @@ void AudioJack::attemptToReconnectInput(size_t inputIndex, const QString& source
if (sourcePort == disconnectedRepresentation)
{
printf("Input port %u is not connected.\n", static_cast<unsigned int>(inputIndex));
std::fprintf(stderr, "Input port %u is not connected.\n", static_cast<unsigned int>(inputIndex));
return;
}
@@ -284,7 +302,7 @@ void AudioJack::startProcessing()
if (jack_activate(m_client))
{
printf("cannot activate client\n");
std::fprintf(stderr, "cannot activate client\n");
return;
}
@@ -483,6 +501,11 @@ AudioJack::setupWidget::setupWidget(QWidget* parent)
const char* serverName = nullptr;
jack_status_t status;
m_client = jack_client_open("LMMS-Setup Dialog", JackNullOption, &status, serverName);
if (!m_client)
{
std::fprintf(stderr, "jack_client_open() failed, ");
printJackStatus(status);
}
QFormLayout * form = new QFormLayout(this);
@@ -562,6 +585,14 @@ std::vector<std::string> AudioJack::setupWidget::getAudioPortNames(JackPortFlags
{
std::vector<std::string> audioPorts;
// We are using weak_libjack. If JACK is not installed this will result in the client being nullptr.
// Because jack_get_ports in weak_libjack does not check for nullptr we have to do this here and fail gracefully,
// i.e. with an empty list of audio ports.
if (!m_client)
{
return audioPorts;
}
const char **inputAudioPorts = jack_get_ports(m_client, nullptr, JACK_DEFAULT_AUDIO_TYPE, portFlags);
if (inputAudioPorts)
{