Use length-bounded string/memory functions (#7709)

Resolves #3949 by replacing all calls to sprintf() and strcpy() in first-party code with calls to snprintf() or some other reasonable alternative.
This commit is contained in:
Fawn
2025-10-23 12:58:32 -07:00
committed by GitHub
parent 44a68b8b01
commit 0fcd67f911
5 changed files with 115 additions and 148 deletions

View File

@@ -26,7 +26,8 @@
#ifndef LMMS_DRUM_SYNTH_H
#define LMMS_DRUM_SYNTH_H
#include <stdint.h>
#include <cstddef>
#include <cstdint>
#include "LmmsTypes.h"
@@ -48,8 +49,9 @@ private:
float waveform(float ph, int form);
int GetPrivateProfileString(
const char* sec, const char* key, const char* def, char* buffer, int size, QString file);
std::size_t GetPrivateProfileString(const char* sec,
const char* key, const char* def, char* buffer,
std::size_t size, QString file);
int GetPrivateProfileInt(const char* sec, const char* key, int def, QString file);
float GetPrivateProfileFloat(const char* sec, const char* key, float def, QString file);
};

View File

@@ -4,44 +4,24 @@
#include <math.h>
#include "base.h"
int sp_create(sp_data **spp)
{
*spp = (sp_data *) malloc(sizeof(sp_data));
sp_data *sp = *spp;
sprintf(sp->filename, "test.wav");
sp->nchan = 1;
SPFLOAT *out = malloc(sizeof(SPFLOAT) * sp->nchan);
*out = 0;
sp->out = out;
sp->sr = 44100;
sp->len = 5 * sp->sr;
sp->pos = 0;
sp->rand = 0;
return 0;
}
int sp_create(sp_data **spp) { return sp_createn(spp, 1); }
int sp_createn(sp_data **spp, int nchan)
{
*spp = (sp_data *) malloc(sizeof(sp_data));
sp_data *sp = *spp;
sprintf(sp->filename, "test.wav");
sp->nchan = nchan;
SPFLOAT *out = malloc(sizeof(SPFLOAT) * sp->nchan);
*out = 0;
sp->out = out;
sp->sr = 44100;
sp->len = 5 * sp->sr;
sp->pos = 0;
sp->rand = 0;
return 0;
const uint32_t sr = 44100; // TODO C23: constexpr auto
const unsigned long len_seconds = 5; // TODO C23: constexpr auto
*spp = malloc(sizeof(sp_data));
**spp = (sp_data){ .out = calloc(nchan, sizeof(float)), .sr = sr,
.nchan = nchan, .len = len_seconds * sr, .pos = 0,
.filename = "test.wav", .rand = 0 };
return 0;
}
int sp_destroy(sp_data **spp)
{
sp_data *sp = *spp;
free(sp->out);
free(*spp);
return 0;
free((*spp)->out);
free(*spp);
return 0;
}
#ifndef NO_LIBSNDFILE
@@ -61,7 +41,7 @@ int sp_process(sp_data *sp, void *ud, void (*callback)(sp_data *, void *))
sf[0] = sf_open(sp->filename, SFM_WRITE, &info);
} else {
for(chan = 0; chan < sp->nchan; chan++) {
sprintf(tmp, "%02d_%s", chan, sp->filename);
snprintf(tmp, sizeof(tmp), "%02d_%s", chan, sp->filename);
sf[chan] = sf_open(tmp, SFM_WRITE, &info);
}
}

View File

@@ -30,6 +30,7 @@
*
*/
#include <cmath>
#include "lmmsconfig.h"
@@ -1010,13 +1011,14 @@ bool RemoteVstPlugin::load( const std::string & _plugin_file )
return false;
}
const char id[5] = {
static_cast<char>(m_plugin->uniqueID >> 24),
static_cast<char>(m_plugin->uniqueID >> 16),
static_cast<char>(m_plugin->uniqueID >> 8),
static_cast<char>(m_plugin->uniqueID ),
0
};
char id[5];
sprintf( id, "%c%c%c%c", ((char *)&m_plugin->uniqueID)[3],
((char *)&m_plugin->uniqueID)[2],
((char *)&m_plugin->uniqueID)[1],
((char *)&m_plugin->uniqueID)[0] );
id[4] = 0;
sendMessage( message( IdVstPluginUniqueID ).addString( id ) );
pluginDispatch( effOpen );
@@ -1244,10 +1246,14 @@ void RemoteVstPlugin::getParameterLabels()
void RemoteVstPlugin::sendCurrentProgramName()
{
char presName[64];
sprintf( presName, "%d/%d: %s", pluginDispatch( effGetProgram ) + 1, m_plugin->numPrograms, programName() );
sendMessage( message( IdVstCurrentProgramName ).addString( presName ) );
char presName[64] = {};
std::snprintf(presName, sizeof(presName),
"%d/%d: %s",
pluginDispatch(effGetProgram) + 1,
m_plugin->numPrograms,
programName()
);
sendMessage(message(IdVstCurrentProgramName).addString(presName));
}
@@ -1372,36 +1378,46 @@ void RemoteVstPlugin::rotateProgram( int offset )
void RemoteVstPlugin::getProgramNames()
{
char presName[1024+256*30];
char curProgName[30];
if (isInitialized() == false) return;
bool progNameIndexed = pluginDispatch(effGetProgramNameIndexed, 0, -1, curProgName) == 1;
char presName[1024 + 256 * 30] = {};
char curProgName[30] = {};
if (!isInitialized()) { return; }
const bool progNameIndexed = pluginDispatch(effGetProgramNameIndexed, 0, -1, curProgName) == 1;
if (m_plugin->numPrograms > 1) {
if (progNameIndexed) {
for (int i = 0; i< (m_plugin->numPrograms >= 256?256:m_plugin->numPrograms); i++)
if (m_plugin->numPrograms > 1)
{
const auto maxPrograms = std::min(m_plugin->numPrograms, 256);
if (progNameIndexed)
{
for (int i = 0; i < maxPrograms; i++)
{
pluginDispatch(effGetProgramNameIndexed, i, -1, curProgName);
if (i == 0) sprintf( presName, "%s", curProgName );
else sprintf( presName + strlen(presName), "|%s", curProgName );
if (i == 0) { std::snprintf(presName, sizeof(presName), "%s", curProgName); }
else
{
const auto len = std::strlen(presName);
std::snprintf(presName + len, sizeof(presName) - len, "|%s", curProgName);
}
}
}
else
{
int currProgram = pluginDispatch( effGetProgram );
for (int i = 0; i< (m_plugin->numPrograms >= 256?256:m_plugin->numPrograms); i++)
const int currProgram = pluginDispatch(effGetProgram);
for (int i = 0; i < maxPrograms; i++)
{
pluginDispatch( effSetProgram, 0, i );
if (i == 0) sprintf( presName, "%s", programName() );
else sprintf( presName + strlen(presName), "|%s", programName() );
pluginDispatch(effSetProgram, 0, i);
if (i == 0) { std::snprintf(presName, sizeof(presName), "%s", programName()); }
else
{
const auto len = std::strlen(presName);
std::snprintf(presName + len, sizeof(presName) - len, "|%s", programName());
}
}
pluginDispatch( effSetProgram, 0, currProgram );
pluginDispatch(effSetProgram, 0, currProgram);
}
} else sprintf( presName, "%s", programName() );
}
else { std::snprintf(presName, sizeof(presName), "%s", programName()); }
presName[sizeof(presName)-1] = 0;
sendMessage( message( IdVstProgramNames ).addString( presName ) );
sendMessage(message(IdVstProgramNames).addString(presName));
}
@@ -1725,19 +1741,12 @@ int RemoteVstPlugin::updateInOutCount()
setInputOutputCount( inputCount(), outputCount() );
char buf[64];
sprintf( buf, "inputs: %d output: %d\n", inputCount(), outputCount() );
debugMessage( buf );
char buf[64] = {};
std::snprintf(buf, sizeof(buf), "inputs: %d; outputs: %d\n", inputCount(), outputCount());
debugMessage(buf);
if( inputCount() > 0 )
{
m_inputs = new float * [inputCount()];
}
if( outputCount() > 0 )
{
m_outputs = new float * [outputCount()];
}
if (inputCount() > 0) { m_inputs = new float*[inputCount()]; }
if (outputCount() > 0) { m_outputs = new float*[outputCount()]; }
return 1;
}
@@ -1765,9 +1774,9 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode,
{
static VstTimeInfo _timeInfo;
#ifdef DEBUG_CALLBACKS
char buf[64];
sprintf( buf, "host-callback, opcode = %d\n", (int) _opcode );
SHOW_CALLBACK( buf );
char buf[64] = {};
std::snprintf(buf, sizeof(buf), "host-callback, opcode = %d\n", static_cast<int>(_opcode));
SHOW_CALLBACK(buf);
#endif
// workaround for early callbacks by some plugins
@@ -1776,6 +1785,7 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode,
__plugin->m_plugin = _effect;
}
const auto p = static_cast<char*>(_ptr);
switch( _opcode )
{
case audioMasterAutomate:
@@ -2070,15 +2080,14 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode,
SHOW_CALLBACK( "amc: audioMasterGetVendorString\n" );
// fills <ptr> with a string identifying the vendor
// (max 64 char)
strcpy( (char *) _ptr, "Tobias Doerffel" );
std::strcpy(p, "Tobias Doerffel");
return 1;
case audioMasterGetProductString:
SHOW_CALLBACK( "amc: audioMasterGetProductString\n" );
// fills <ptr> with a string with product name
// (max 64 char)
strcpy( (char *) _ptr,
"LMMS VST Support Layer (LVSL)" );
std::strcpy(p, "LMMS VST Support Layer (LVSL)");
return 1;
case audioMasterGetVendorVersion:
@@ -2092,12 +2101,12 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode,
return 0;
case audioMasterCanDo:
SHOW_CALLBACK( "amc: audioMasterCanDo\n" );
return !strcmp( (char *) _ptr, "sendVstEvents" ) ||
!strcmp( (char *) _ptr, "sendVstMidiEvent" ) ||
!strcmp( (char *) _ptr, "sendVstTimeInfo" ) ||
!strcmp( (char *) _ptr, "sizeWindow" ) ||
!strcmp( (char *) _ptr, "supplyIdle" );
SHOW_CALLBACK("amc: audioMasterCanDo\n");
return !(std::strcmp(p, "sendVstEvents")
&& std::strcmp(p, "sendVstMidiEvent")
&& std::strcmp(p, "sendVstTimeInfo")
&& std::strcmp(p, "sizeWindow")
&& std::strcmp(p, "supplyIdle"));
case audioMasterGetLanguage:
SHOW_CALLBACK( "amc: audioMasterGetLanguage\n" );

View File

@@ -26,6 +26,7 @@
#include "DrumSynth.h"
#include <QFile>
#include <array>
#include <cmath>
#include <cstring>
#include <sstream>
@@ -185,14 +186,14 @@ float DrumSynth::waveform(float ph, int form)
return (saw01 < 0.5f) ? 1.f : -1.f;
}
int DrumSynth::GetPrivateProfileString(
const char* sec, const char* key, const char* def, char* buffer, int size, QString file)
std::size_t DrumSynth::GetPrivateProfileString(const char* sec,
const char* key, const char* def, char* buffer, std::size_t size,
QString file)
{
const auto maxlen = std::max(std::size_t{1}, size) - 1; // TODO C++26: Use std::sub_sat(size, 1)
stringstream is;
bool inSection = false;
int len = 0;
char* line = static_cast<char*>(malloc(200));
std::array<char, 200> line = {};
// Use QFile to handle unicode file name on Windows
// Previously we used ifstream directly
@@ -201,68 +202,47 @@ int DrumSynth::GetPrivateProfileString(
QByteArray dat = f.readAll().constData();
is.str(string(dat.constData(), dat.size()));
// If buffer[0] isn't overwritten after reading file, default value
// `def` will be used.
std::memset(buffer, '\0', size);
while (is.good())
{
if (!inSection)
{
is.ignore(numeric_limits<streamsize>::max(), '[');
if (!is.eof())
{
is.getline(line, 200, ']');
if (strcasecmp(line, sec) == 0)
{
inSection = true;
}
is.getline(line.data(), line.size(), ']');
if (!strcasecmp(line.data(), sec)) { inSection = true; }
}
}
else if (!is.eof())
{
is.getline(line, 200);
if (line[0] == '[')
is.getline(line.data(), line.size());
if (line[0] == '[') { break; }
char* k = std::strtok(line.data(), " \t=");
char* b = std::strtok(nullptr, "\n\r\0");
if (k && !strcasecmp(k, key))
{
break;
}
char* k = strtok(line, " \t=");
char* b = strtok(nullptr, "\n\r\0");
if (k != 0 && strcasecmp(k, key) == 0)
{
if (b == 0)
if (b)
{
len = 0;
buffer[0] = 0;
}
else
{
k = static_cast<char*>(b + strlen(b) - 1);
while ((k >= b) && (*k == ' ' || *k == '\t'))
{
--k;
}
*(k + 1) = '\0';
len = strlen(b);
if (len > size - 1)
{
len = size - 1;
}
strncpy(buffer, b, len + 1);
// Trim trailing whitespace
k = &b[std::strlen(b)];
while (k >= b && (*k == ' ' || *k == '\t')) { --k; }
k[1] = '\0'; // k == b - 1 when string is empty or all whitespace
std::strncpy(buffer, b, maxlen);
}
break;
}
}
}
if (len == 0)
{
len = strlen(def);
strncpy(buffer, def, size);
}
free(line);
// Use default value `def` if value is missing
if (!buffer[0]) { std::strncpy(buffer, def, maxlen); }
// Since nothing ever copies past `maxlen`, buffer must be null-terminated
const auto len = std::strlen(buffer);
return len;
}
@@ -345,7 +325,7 @@ int DrumSynth::GetDSFileSamples(QString dsfile, int16_t*& wave, int channels, sa
}
// try to read version from input file
strcpy(sec, "General");
std::strcpy(sec, "General");
GetPrivateProfileString(sec, "Version", "", ver, sizeof(ver), dsfile);
ver[9] = 0;
if ((strcasecmp(ver, "DrumSynth") != 0) // input fail
@@ -398,7 +378,7 @@ int DrumSynth::GetDSFileSamples(QString dsfile, int16_t*& wave, int channels, sa
GetEnv(7, sec, "FilterEnv", dsfile);
// read noise parameters
strcpy(sec, "Noise");
std::strcpy(sec, "Noise");
chkOn[1] = GetPrivateProfileInt(sec, "On", 0, dsfile);
sliLev[1] = GetPrivateProfileInt(sec, "Level", 0, dsfile);
NT = GetPrivateProfileInt(sec, "Slope", 0, dsfile);
@@ -423,7 +403,7 @@ int DrumSynth::GetDSFileSamples(QString dsfile, int16_t*& wave, int channels, sa
// srand(1); //fixed random sequence
// read tone parameters
strcpy(sec, "Tone");
std::strcpy(sec, "Tone");
chkOn[0] = GetPrivateProfileInt(sec, "On", 0, dsfile);
TON = chkOn[0];
sliLev[0] = GetPrivateProfileInt(sec, "Level", 128, dsfile);
@@ -452,7 +432,7 @@ int DrumSynth::GetDSFileSamples(QString dsfile, int16_t*& wave, int channels, sa
Tphi = GetPrivateProfileFloat(sec, "Phase", 90.f, dsfile) / 57.29578f; // degrees>radians
// read overtone parameters
strcpy(sec, "Overtones");
std::strcpy(sec, "Overtones");
chkOn[2] = GetPrivateProfileInt(sec, "On", 0, dsfile);
OON = chkOn[2];
sliLev[2] = GetPrivateProfileInt(sec, "Level", 128, dsfile);
@@ -497,7 +477,7 @@ int DrumSynth::GetDSFileSamples(QString dsfile, int16_t*& wave, int channels, sa
}
// read noise band parameters
strcpy(sec, "NoiseBand");
std::strcpy(sec, "NoiseBand");
chkOn[3] = GetPrivateProfileInt(sec, "On", 0, dsfile);
BON = chkOn[3];
sliLev[3] = GetPrivateProfileInt(sec, "Level", 128, dsfile);
@@ -510,7 +490,7 @@ int DrumSynth::GetDSFileSamples(QString dsfile, int16_t*& wave, int channels, sa
BQ = BQ * BQ / (10000.f - 6600.f * (std::sqrt(BF) - 0.19f));
BFStep = 1 + static_cast<int>((40.f - (BFStep / 2.5f)) / (BQ + 1.f + (1.f * BF)));
strcpy(sec, "NoiseBand2");
std::strcpy(sec, "NoiseBand2");
chkOn[4] = GetPrivateProfileInt(sec, "On", 0, dsfile);
BON2 = chkOn[4];
sliLev[4] = GetPrivateProfileInt(sec, "Level", 128, dsfile);
@@ -524,7 +504,7 @@ int DrumSynth::GetDSFileSamples(QString dsfile, int16_t*& wave, int channels, sa
BFStep2 = 1 + static_cast<int>((40 - (BFStep2 / 2.5)) / (BQ2 + 1 + (1 * BF2)));
// read distortion parameters
strcpy(sec, "Distortion");
std::strcpy(sec, "Distortion");
chkOn[5] = GetPrivateProfileInt(sec, "On", 0, dsfile);
DiON = chkOn[5];
DStep = 1 + GetPrivateProfileInt(sec, "Rate", 0, dsfile);

View File

@@ -286,11 +286,7 @@ int main( int argc, char * * argv )
}
else if (arg == "--geometry" || arg == "-geometry")
{
if (arg == "--geometry")
{
// Delete the first "-" so Qt recognize the option
strcpy(argv[i], "-geometry");
}
if (arg == "--geometry") { argv[i]++; } // Delete the first "-" so Qt recognize the option
// option -geometry is filtered by Qt later,
// so we need to check its presence now to
// determine, if the application should run in