Skip to content

Commit

Permalink
harden strings.h against null pointers
Browse files Browse the repository at this point in the history
  • Loading branch information
ennorehling committed Aug 26, 2023
1 parent 0e335d4 commit 2c34e58
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 66 deletions.
49 changes: 31 additions & 18 deletions strings.c
Original file line number Diff line number Diff line change
Expand Up @@ -232,34 +232,44 @@ void sbs_init(struct sbstring *sbs, char *buffer, size_t size)

void sbs_adopt(struct sbstring *sbs, char *buffer, size_t size)
{
size_t len = strlen(buffer);
assert(sbs);
assert(size > len);
sbs->begin = buffer;
sbs->size = size;
sbs->end = buffer + len;
if (buffer && size > 0) {
size_t len = strlen(buffer);
assert(sbs);
assert(size > len);
sbs->begin = buffer;
sbs->size = size;
sbs->end = buffer + len;
}
else {
sbs->end = sbs->begin = NULL;
sbs->size = 0;
}
}

void sbs_strncat(struct sbstring *sbs, const char *str, size_t size)
{
size_t len;
assert(sbs);
len = sbs->size - (sbs->end - sbs->begin) - 1;
if (len < size) {
size = len;
if (str) {
size_t len;
len = sbs->size - (sbs->end - sbs->begin) - 1;
if (len < size) {
size = len;
}
memcpy(sbs->end, str, size);
sbs->end[size] = '\0';
sbs->end += size;
}
memcpy(sbs->end, str, size);
sbs->end[size] = '\0';
sbs->end += size;
}

void sbs_strcat(struct sbstring *sbs, const char *str)
{
size_t len;
assert(sbs);
len = sbs->size - (sbs->end - sbs->begin);
str_strlcpy(sbs->end, str, len);
sbs->end += strlen(sbs->end);
if (str) {
len = sbs->size - (sbs->end - sbs->begin);
str_strlcpy(sbs->end, str, len);
sbs->end += strlen(sbs->end);
}
assert(sbs->begin + sbs->size >= sbs->end);
}

Expand All @@ -285,8 +295,11 @@ void sbs_substr(sbstring *sbs, ptrdiff_t pos, size_t len)

size_t sbs_length(const struct sbstring *sbs)
{
assert(sbs->begin + sbs->size >= sbs->end);
return sbs->end - sbs->begin;
if (sbs->begin) {
assert(sbs->begin + sbs->size >= sbs->end);
return sbs->end - sbs->begin;
}
return 0;
}

char *str_unescape(char *str) {
Expand Down
84 changes: 36 additions & 48 deletions strings.h
Original file line number Diff line number Diff line change
@@ -1,50 +1,43 @@
#pragma once
#ifndef STRINGS_H
#define STRINGS_H

#include <stddef.h>
#include <string.h>

#ifdef __cplusplus
extern "C" {
#endif

void str_replace(char *buffer, size_t size, const char *tmpl, const char *var, const char *value);
int str_hash(const char *s);
const char *str_itoa(int i);
size_t str_slprintf(char * dst, size_t size, const char * format, ...);
size_t str_strlcpy(char *dst, const char *src, size_t len);
size_t str_strlcat(char *dst, const char *src, size_t len);
char *str_strdup(const char *s);

const char *str_escape(const char *str, char *buffer, size_t size);
const char *str_escape_ex(const char *str, char *buffer, size_t size, const char *chars);
char *str_unescape(char *str);

unsigned int jenkins_hash(unsigned int a);
unsigned int wang_hash(unsigned int a);

/* static buffered string */
typedef struct sbstring {
size_t size;
char *begin;
char *end;
} sbstring;

void sbs_printf(struct sbstring *sbs, const char *format, ...);
void sbs_init(struct sbstring *sbs, char *buffer, size_t size);
void sbs_adopt(struct sbstring *sbs, char *buffer, size_t size);
void sbs_strcat(struct sbstring *sbs, const char *str);
void sbs_strncat(struct sbstring *sbs, const char *str, size_t size);
void sbs_substr(struct sbstring *sbp, ptrdiff_t pos, size_t len);
size_t sbs_length(const struct sbstring *sbs);

/* benchmark for units:
* JENKINS_HASH: 5.25 misses/hit (with good cache behavior)
* WANG_HASH: 5.33 misses/hit (with good cache behavior)
* KNUTH_HASH: 1.93 misses/hit (with bad cache behavior)
* CF_HASH: fucking awful!
*/
void str_replace(char *buffer, size_t size, const char *tmpl, const char *var, const char *value);
int str_hash(const char *s);
const char *str_itoa(int i);
size_t str_slprintf(char * dst, size_t size, const char * format, ...);
size_t str_strlcpy(char *dst, const char *src, size_t len);
size_t str_strlcat(char *dst, const char *src, size_t len);
char *str_strdup(const char *s);

const char *str_escape(const char *str, char *buffer, size_t size);
const char *str_escape_ex(const char *str, char *buffer, size_t size, const char *chars);
char *str_unescape(char *str);

unsigned int jenkins_hash(unsigned int a);
unsigned int wang_hash(unsigned int a);

/* static buffered string */
typedef struct sbstring {
size_t size;
char *begin;
char *end;
} sbstring;

void sbs_printf(struct sbstring *sbs, const char *format, ...);
void sbs_init(struct sbstring *sbs, char *buffer, size_t size);
void sbs_adopt(struct sbstring *sbs, char *buffer, size_t size);
void sbs_strcat(struct sbstring *sbs, const char *str);
void sbs_strncat(struct sbstring *sbs, const char *str, size_t size);
void sbs_substr(struct sbstring *sbp, ptrdiff_t pos, size_t len);
size_t sbs_length(const struct sbstring *sbs);

/* benchmark for units:
* JENKINS_HASH: 5.25 misses/hit (with good cache behavior)
* WANG_HASH: 5.33 misses/hit (with good cache behavior)
* KNUTH_HASH: 1.93 misses/hit (with bad cache behavior)
* CF_HASH: fucking awful!
*/
#define KNUTH_HASH1(a, m) ((a) % m)
#define KNUTH_HASH2(a, m) (m - 2 - a % (m-2))
#define CF_HASH1(a, m) ((a) % m)
Expand All @@ -57,8 +50,3 @@ extern "C" {
#define HASH1 JENKINS_HASH1
#define HASH2 JENKINS_HASH2
#define slprintf str_slprintf

#ifdef __cplusplus
}
#endif
#endif /* STRINGS_H */
9 changes: 9 additions & 0 deletions test_strings.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ static void test_sbstring(CuTest * tc)
sbstring sbs;
sbs_init(&sbs, buffer, sizeof(buffer));
CuAssertStrEquals(tc, "", sbs.begin);
CuAssertIntEquals(tc, 0, (int)sbs_length(&sbs));
sbs_strcat(&sbs, "Hodor");
CuAssertStrEquals(tc, "Hodor", sbs.begin);
sbs_strcat(&sbs, "Hodor");
Expand Down Expand Up @@ -179,6 +180,10 @@ static void test_sbstring(CuTest * tc)
sbs_adopt(&sbs, buffer + 2, sizeof(buffer) - 2);
CuAssertStrEquals(tc, "3456789012345", sbs.begin);
CuAssertIntEquals(tc, 13, (int)sbs_length(&sbs));

sbs_adopt(&sbs, NULL, 8);
CuAssertStrEquals(tc, NULL, sbs.begin);
CuAssertIntEquals(tc, 0, (int)sbs_length(&sbs));
}

static void test_sbs_strcat(CuTest * tc)
Expand All @@ -189,6 +194,8 @@ static void test_sbs_strcat(CuTest * tc)
sbs_init(&sbs, buffer, sizeof(buffer));
sbs_strcat(&sbs, "AB");
CuAssertStrEquals(tc, "AB", sbs.begin);
sbs_strcat(&sbs, NULL);
CuAssertStrEquals(tc, "AB", sbs.begin);
sbs_strcat(&sbs, "CD");
CuAssertStrEquals(tc, "ABCD", sbs.begin);

Expand All @@ -201,6 +208,8 @@ static void test_sbs_strcat(CuTest * tc)
sbs_init(&sbs, buffer, sizeof(buffer));
sbs_strncat(&sbs, "12345678901234567890", 4);
CuAssertStrEquals(tc, "1234", sbs.begin);
sbs_strncat(&sbs, NULL, 4);
CuAssertStrEquals(tc, "1234", sbs.begin);
sbs_strncat(&sbs, "12345678901234567890", 4);
CuAssertStrEquals(tc, "1234123", sbs.begin);
}
Expand Down

0 comments on commit 2c34e58

Please sign in to comment.