Skip to content

Commit 88ed51e

Browse files
Fix a segfault if JACK libs are missing (LMMS#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>
1 parent dabfe6f commit 88ed51e

File tree

1 file changed

+43
-12
lines changed

1 file changed

+43
-12
lines changed

src/core/audio/AudioJack.cpp

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
#include "MainWindow.h"
4141
#include "MidiJack.h"
4242

43+
#include <cstdio>
44+
4345

4446
namespace
4547
{
@@ -57,6 +59,21 @@ QString getInputKeyByChannel(size_t channel)
5759
return "input" + QString::number(channel + 1);
5860
}
5961

62+
void printJackStatus(jack_status_t status)
63+
{
64+
std::fprintf(stderr, "Status: 0x%2.0x\n", static_cast<unsigned int>(status));
65+
66+
if (status & JackFailure)
67+
{
68+
std::fprintf(stderr, "Overall operation failed. JACK dependencies might need to be installed.\n");
69+
}
70+
71+
if (status & JackServerFailed)
72+
{
73+
std::fprintf(stderr, "Could not connect to JACK server.\n");
74+
}
75+
}
76+
6077
}
6178

6279
namespace lmms
@@ -172,15 +189,16 @@ bool AudioJack::initJackClient()
172189
m_client = jack_client_open(clientName.toLatin1().constData(), JackNullOption, &status, serverName);
173190
if (m_client == nullptr)
174191
{
175-
printf("jack_client_open() failed, status 0x%2.0x\n", status);
176-
if (status & JackServerFailed) { printf("Could not connect to JACK server.\n"); }
192+
std::fprintf(stderr, "jack_client_open() failed, ");
193+
printJackStatus(status);
194+
177195
return false;
178196
}
179197
if (status & JackNameNotUnique)
180198
{
181-
printf( "there's already a client with name '%s', so unique "
182-
"name '%s' was assigned\n",
183-
clientName.toLatin1().constData(), jack_get_client_name(m_client));
199+
std::printf("there's already a client with name '%s', so unique "
200+
"name '%s' was assigned\n",
201+
clientName.toLatin1().constData(), jack_get_client_name(m_client));
184202
}
185203

186204
resizeInputBuffer(jack_get_buffer_size(m_client));
@@ -212,7 +230,7 @@ bool AudioJack::initJackClient()
212230

213231
if (m_outputPorts.back() == nullptr)
214232
{
215-
printf("no more JACK-ports available!\n");
233+
std::fprintf(stderr, "no more JACK-ports available!\n");
216234
return false;
217235
}
218236
}
@@ -230,14 +248,14 @@ void AudioJack::resizeInputBuffer(jack_nframes_t nframes)
230248

231249
void AudioJack::attemptToConnect(size_t index, const char *lmms_port_type, const char *source_port, const char *destination_port)
232250
{
233-
printf("Attempting to reconnect %s port %u: %s -> %s", lmms_port_type, static_cast<unsigned int>(index), source_port, destination_port);
251+
std::printf("Attempting to reconnect %s port %u: %s -> %s", lmms_port_type, static_cast<unsigned int>(index), source_port, destination_port);
234252
if (!jack_connect(m_client, source_port, destination_port))
235253
{
236-
printf(" - Success!\n");
254+
std::printf(" - Success!\n");
237255
}
238256
else
239257
{
240-
printf(" - Failure\n");
258+
std::printf(" - Failure\n");
241259
}
242260
}
243261

@@ -247,7 +265,7 @@ void AudioJack::attemptToReconnectOutput(size_t outputIndex, const QString& targ
247265

248266
if (targetPort == disconnectedRepresentation)
249267
{
250-
printf("Output port %u is not connected.\n", static_cast<unsigned int>(outputIndex));
268+
std::fprintf(stderr, "Output port %u is not connected.\n", static_cast<unsigned int>(outputIndex));
251269
return;
252270
}
253271

@@ -263,7 +281,7 @@ void AudioJack::attemptToReconnectInput(size_t inputIndex, const QString& source
263281

264282
if (sourcePort == disconnectedRepresentation)
265283
{
266-
printf("Input port %u is not connected.\n", static_cast<unsigned int>(inputIndex));
284+
std::fprintf(stderr, "Input port %u is not connected.\n", static_cast<unsigned int>(inputIndex));
267285
return;
268286
}
269287

@@ -284,7 +302,7 @@ void AudioJack::startProcessing()
284302

285303
if (jack_activate(m_client))
286304
{
287-
printf("cannot activate client\n");
305+
std::fprintf(stderr, "cannot activate client\n");
288306
return;
289307
}
290308

@@ -483,6 +501,11 @@ AudioJack::setupWidget::setupWidget(QWidget* parent)
483501
const char* serverName = nullptr;
484502
jack_status_t status;
485503
m_client = jack_client_open("LMMS-Setup Dialog", JackNullOption, &status, serverName);
504+
if (!m_client)
505+
{
506+
std::fprintf(stderr, "jack_client_open() failed, ");
507+
printJackStatus(status);
508+
}
486509

487510
QFormLayout * form = new QFormLayout(this);
488511

@@ -562,6 +585,14 @@ std::vector<std::string> AudioJack::setupWidget::getAudioPortNames(JackPortFlags
562585
{
563586
std::vector<std::string> audioPorts;
564587

588+
// We are using weak_libjack. If JACK is not installed this will result in the client being nullptr.
589+
// Because jack_get_ports in weak_libjack does not check for nullptr we have to do this here and fail gracefully,
590+
// i.e. with an empty list of audio ports.
591+
if (!m_client)
592+
{
593+
return audioPorts;
594+
}
595+
565596
const char **inputAudioPorts = jack_get_ports(m_client, nullptr, JACK_DEFAULT_AUDIO_TYPE, portFlags);
566597
if (inputAudioPorts)
567598
{

0 commit comments

Comments
 (0)