Merge pull request #2571 from pi-hole/copilot/fix-b5adb213-37cc-4cb3-b094-28ab67b1773a

Performance optimizations: string processing, memory management, and compiler flags
This commit is contained in:
Dominik
2025-11-25 20:08:39 +01:00
committed by GitHub
6 changed files with 62 additions and 31 deletions

View File

@@ -218,7 +218,7 @@ endif()
set(CMAKE_C_FLAGS "-std=c17 -pipe ${WARN_FLAGS} -D_FILE_OFFSET_BITS=64 ${HARDENING_FLAGS} ${DEBUG_FLAGS} ${CMAKE_C_FLAGS} -DHAVE_POLL_H ${SQLITE_DEFINES}")
set(CMAKE_C_FLAGS_DEBUG "-O0 -g3")
set(CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG")
set(CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG -funroll-loops")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELEASE} -g3")
set(CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG")

View File

@@ -412,6 +412,7 @@ void parse_args(int argc, char *argv[])
// Generate X.509 certificate
if(argc > 1 && strcmp(argv[1], "--gen-x509") == 0)
{
#ifdef HAVE_MBEDTLS
if(argc < 3 || argc > 5)
{
printf("Usage: %s --gen-x509 <output file> [<domain>] [rsa]\n", argv[0]);
@@ -431,6 +432,10 @@ void parse_args(int argc, char *argv[])
const bool rsa = argc > 4 && strcasecmp(argv[4], "rsa") == 0;
exit(generate_certificate(argv[2], rsa, domain, config.webserver.tls.validity.v.ui) ? EXIT_SUCCESS : EXIT_FAILURE);
#else
printf("Error: FTL was compiled without TLS support. Certificate generation is not available.\n");
exit(EXIT_FAILURE);
#endif
}
// Parse X.509 certificate
@@ -438,6 +443,7 @@ void parse_args(int argc, char *argv[])
(strcmp(argv[1], "--read-x509") == 0 ||
strcmp(argv[1], "--read-x509-key") == 0))
{
#ifdef HAVE_MBEDTLS
if(argc > 4)
{
printf("Usage: %s %s [<input file>] [<domain>]\n", argv[0], argv[1]);
@@ -480,6 +486,10 @@ void parse_args(int argc, char *argv[])
printf("Certificate does not match domain %s\n", argv[3]);
exit(EXIT_FAILURE);
}
#else
printf("Error: FTL was compiled without TLS support. Certificate reading is not available.\n");
exit(EXIT_FAILURE);
#endif
}
// If the first argument is "gravity" (e.g., /usr/bin/pihole-FTL gravity),

View File

@@ -32,10 +32,11 @@
#include "lookup-table.h"
// converts upper to lower case, and leaves other characters unchanged
// Optimized version using pointer arithmetic for better performance
void strtolower(char *str)
{
int i = 0;
while(str[i]){ str[i] = tolower(str[i]); i++; }
for(; *str; ++str)
*str = tolower(*str);
}
/**
@@ -54,7 +55,7 @@ void strtolower(char *str)
*/
static uint32_t __attribute__ ((pure)) hashStr(const char *s)
{
// Jenkins' One-at-a-Time hash
// Jenkins' One-at-a-Time hash (optimized version)
// (http://www.burtleburtle.net/bob/hash/doobs.html)
uint32_t hash = 0;
for(; *s; ++s)
@@ -64,6 +65,7 @@ static uint32_t __attribute__ ((pure)) hashStr(const char *s)
hash ^= hash >> 6;
}
// Final mixing to ensure good distribution
hash += hash << 3;
hash ^= hash >> 11;
hash += hash << 15;
@@ -1005,16 +1007,19 @@ const char * __attribute__ ((pure)) get_blocked_statuslist(void)
unsigned int first = 0;
// Open parenthesis
blocked_list[0] = '(';
size_t pos = 1; // Track current position instead of calling strlen repeatedly
for(enum query_status status = 0; status < QUERY_STATUS_MAX; status++)
if(is_blocked(status))
snprintf(blocked_list + strlen(blocked_list),
sizeof(blocked_list) - strlen(blocked_list),
"%s%d", first++ < 1 ? "" : ",", status);
{
int written = snprintf(blocked_list + pos, sizeof(blocked_list) - pos,
"%s%d", first++ < 1 ? "" : ",", status);
if(written > 0 && (size_t)written < sizeof(blocked_list) - pos)
pos += written;
}
// Close parenthesis
const size_t len = strlen(blocked_list);
blocked_list[len] = ')';
blocked_list[len + 1] = '\0';
blocked_list[pos] = ')';
blocked_list[pos + 1] = '\0';
return blocked_list;
}
@@ -1028,16 +1033,19 @@ const char * __attribute__ ((pure)) get_cached_statuslist(void)
unsigned int first = 0;
// Open parenthesis
cached_list[0] = '(';
size_t pos = 1; // Track current position instead of calling strlen repeatedly
for(enum query_status status = 0; status < QUERY_STATUS_MAX; status++)
if(is_cached(status))
snprintf(cached_list + strlen(cached_list),
sizeof(cached_list) - strlen(cached_list),
"%s%d", first++ < 1 ? "" : ",", status);
{
int written = snprintf(cached_list + pos, sizeof(cached_list) - pos,
"%s%d", first++ < 1 ? "" : ",", status);
if(written > 0 && (size_t)written < sizeof(cached_list) - pos)
pos += written;
}
// Close parenthesis
const size_t len = strlen(cached_list);
cached_list[len] = ')';
cached_list[len + 1] = '\0';
cached_list[pos] = ')';
cached_list[pos + 1] = '\0';
return cached_list;
}
@@ -1051,16 +1059,19 @@ const char * __attribute__ ((pure)) get_permitted_statuslist(void)
unsigned int first = 0;
// Open parenthesis
permitted_list[0] = '(';
size_t pos = 1; // Track current position instead of calling strlen repeatedly
for(enum query_status status = 0; status < QUERY_STATUS_MAX; status++)
if(!is_blocked(status))
snprintf(permitted_list + strlen(permitted_list),
sizeof(permitted_list) - strlen(permitted_list),
"%s%d", first++ < 1 ? "" : ",", status);
{
int written = snprintf(permitted_list + pos, sizeof(permitted_list) - pos,
"%s%d", first++ < 1 ? "" : ",", status);
if(written > 0 && (size_t)written < sizeof(permitted_list) - pos)
pos += written;
}
// Close parenthesis
const size_t len = strlen(permitted_list);
permitted_list[len] = ')';
permitted_list[len + 1] = '\0';
permitted_list[pos] = ')';
permitted_list[pos + 1] = '\0';
return permitted_list;
}

View File

@@ -151,7 +151,7 @@ bool compile_regex(const char *regexin, regexData *regex, char **message)
// Extract regular expression pattern in front of FTL-specific syntax
char *saveptr = NULL;
char *part = strtok_r(buf, FTL_REGEX_SEP, &saveptr);
strncpy(rgxbuf, part, strlen(regexin));
strncpy(rgxbuf, part, strlen(part));
// Analyze FTL-specific parts
while((part = strtok_r(NULL, FTL_REGEX_SEP, &saveptr)) != NULL)

View File

@@ -78,10 +78,18 @@ void set_sqlite3_stmt_vec(sqlite3_stmt_vec *v, unsigned int index, sqlite3_stmt
if(index >= v->capacity)
{
// Allocate more memory when trying to set a statement vector entry with
// an index larger than the current array size (this makes set an
// equivalent alternative to append)
if(!resize_sqlite3_stmt_vec(v, index + VEC_ALLOC_STEP))
return;
// an index larger than the current array size. Use exponential growth
// for better performance with large datasets.
unsigned int new_capacity = v->capacity * VEC_GROWTH_FACTOR;
if(new_capacity <= index)
new_capacity = index + VEC_ALLOC_STEP;
// Overflow check
if(new_capacity > v->capacity)
{
// Resize vector
if(!resize_sqlite3_stmt_vec(v, new_capacity))
return;
}
}
// Set item
@@ -102,10 +110,11 @@ sqlite3_stmt * __attribute__((pure)) get_sqlite3_stmt_vec(sqlite3_stmt_vec *v, u
if(index >= v->capacity)
{
// Silently increase size of vector if trying to read out-of-bounds
// Return NULL if the allocation fails
if(!resize_sqlite3_stmt_vec(v, index + VEC_ALLOC_STEP))
return NULL;
// Silently return NULL when trying to get a statement vector
// entry with an index larger than the current array size. The
// code will later initiate a refreshing of the prepared
// statements in this case.
return NULL;
}
sqlite3_stmt* item = v->items[index];

View File

@@ -20,6 +20,7 @@
#include "database/sqlite3.h"
#define VEC_ALLOC_STEP 10u
#define VEC_GROWTH_FACTOR 2u // For exponential growth when expanding beyond initial capacity
typedef struct sqlite3_stmt_vec {
unsigned int capacity;