Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

# Build directories
build/
build-*/
_build/
cmake-build-*/

Expand All @@ -19,6 +20,10 @@ test_stress
test_features
test_security
test_client
test_welcome
test_starvation
test_reentrancy
test_http_edge
fuzz_http
mnet-server

Expand All @@ -36,7 +41,6 @@ example/example_combined

# User-compiled binaries
myapp
test_welcome

# OS
.DS_Store
Expand Down
29 changes: 29 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,27 @@ if(MSVC)
# names" — sscanf, strcpy, strdup, etc. These are false positives for
# portable C code; suppress them so /WX does not escalate them to errors.
add_compile_definitions(_CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE)
# MSVC's buffer-security hardening is on by default: /GS (stack cookies),
# /DYNAMICBASE (ASLR) and /NXCOMPAT (DEP) are all enabled unless explicitly
# turned off, so no extra flags are needed for parity with the POSIX side.
else()
add_compile_options(-Wall -Wextra -Wpedantic -Werror)

# Hardening. -fstack-protector-strong works at any optimization level.
add_compile_options(-fstack-protector-strong)

# _FORTIFY_SOURCE=2 only makes sense with optimization: without it glibc
# emits a #warning that -Werror would escalate, and CMake's default
# (empty) build type compiles without -O. Restrict it to the optimized
# build types.
if(CMAKE_BUILD_TYPE MATCHES "^(Release|RelWithDebInfo|MinSizeRel)$")
add_compile_definitions(_FORTIFY_SOURCE=2)
endif()

# relro/now are ELF-only.
if(UNIX AND NOT APPLE)
add_link_options(-Wl,-z,relro,-z,now)
endif()
endif()

if(NOT WIN32)
Expand Down Expand Up @@ -136,6 +155,16 @@ target_link_libraries(test_http_edge PRIVATE mnet_static)
target_include_directories(test_http_edge PRIVATE include src test)
add_test(NAME mnet_http_edge_tests COMMAND test_http_edge)

# Tests are assert()-based, and CMake's Release configs define NDEBUG, which
# would compile every assertion out: the suite would then pass without
# checking anything. Undefine it for the test targets so assertions stay
# active in every build type, matching the Make and Meson builds.
foreach(test_target IN ITEMS test_mnet test_http test_parser test_stress
test_features test_security test_client test_welcome test_starvation
test_reentrancy test_http_edge)
target_compile_options(${test_target} PRIVATE -UNDEBUG)
endforeach()

# Install
install(TARGETS mnet_static mnet_shared
ARCHIVE DESTINATION lib
Expand Down
10 changes: 10 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ ifeq ($(shell uname -s),Darwin)
CFLAGS += -D_DARWIN_C_SOURCE
endif

# Hardening. -fstack-protector-strong works at any optimization level and on
# GCC/Clang; -Wl,-z,relro,-z,now is ELF-only, so it stays on Linux.
# _FORTIFY_SOURCE=2 needs optimization, which this Makefile does not set by
# default: add it yourself when building optimized, e.g.
# make CFLAGS="-O2 -D_FORTIFY_SOURCE=2 ..."
CFLAGS += -fstack-protector-strong
ifeq ($(shell uname -s),Linux)
LDFLAGS += -Wl,-z,relro,-z,now
endif

# The worker pool needs pthreads on POSIX.
ifeq ($(OS),Windows_NT)
LDFLAGS += -lws2_32
Expand Down
34 changes: 34 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,26 @@ if cc.get_id() == 'msvc'
add_project_arguments(['/W4', '/WX'], language: 'c')
# Suppress false-positive C4996 deprecation warnings for standard C functions.
add_project_arguments(['/D_CRT_SECURE_NO_WARNINGS', '/D_CRT_NONSTDC_NO_DEPRECATE'], language: 'c')
# MSVC's buffer-security hardening is on by default: /GS (stack cookies),
# /DYNAMICBASE (ASLR) and /NXCOMPAT (DEP) are all enabled unless explicitly
# turned off, so no extra flags are needed for parity with the POSIX side.
else
add_project_arguments(warning_flags, language: 'c')

# Hardening. -fstack-protector-strong works at any optimization level.
add_project_arguments('-fstack-protector-strong', language: 'c')

# _FORTIFY_SOURCE=2 only makes sense with optimization: without it glibc
# emits a #warning that -Werror would escalate. Meson's debug buildtype
# is -O0, so restrict it to optimized builds.
if get_option('optimization') != '0'
add_project_arguments('-D_FORTIFY_SOURCE=2', language: 'c')
endif

# relro/now are ELF-only.
if host_machine.system() == 'linux'
add_project_link_arguments('-Wl,-z,relro,-z,now', language: 'c')
endif
endif

# glibc's _FORTIFY_SOURCE is only meaningful with optimization, and some
Expand Down Expand Up @@ -164,6 +182,22 @@ test_http_edge = executable('test_http_edge',

test('mnet_http_edge_tests', test_http_edge)

test_client = executable('test_client',
'test/test_client.c',
link_with: mnet_static,
include_directories: [mnet_inc, include_directories('src'), include_directories('test')],
)

test('mnet_client_tests', test_client)

test_welcome = executable('test_welcome',
'test/test_welcome.c',
link_with: mnet_static,
include_directories: [mnet_inc, include_directories('src'), include_directories('test')],
)

test('mnet_welcome_tests', test_welcome)

# Install headers (libraries are installed by default)
install_headers('include/mnet/mnet.h', 'include/mnet/mnet_app.h', 'include/mnet/mnet_request.h',
'include/mnet/mnet_response.h', 'include/mnet/mnet_router.h', 'include/mnet/mnet_socket.h',
Expand Down
27 changes: 11 additions & 16 deletions test/test_mnet.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,27 +130,26 @@ static void test_mnet_json_escape(void)
{
char out[256];

size_t n = mnet_json_escape(out, sizeof(out), "hello");
(void)mnet_json_escape(out, sizeof(out), "hello");
assert(strcmp(out, "hello") == 0);

n = mnet_json_escape(out, sizeof(out), "he\"llo");
(void)mnet_json_escape(out, sizeof(out), "he\"llo");
assert(strcmp(out, "he\\\"llo") == 0);

n = mnet_json_escape(out, sizeof(out), "a\\b");
(void)mnet_json_escape(out, sizeof(out), "a\\b");
assert(strcmp(out, "a\\\\b") == 0);

n = mnet_json_escape(out, sizeof(out), "a\nb");
(void)mnet_json_escape(out, sizeof(out), "a\nb");
assert(strcmp(out, "a\\nb") == 0);

n = mnet_json_escape(out, sizeof(out), "a\rb");
(void)mnet_json_escape(out, sizeof(out), "a\rb");
assert(strcmp(out, "a\\rb") == 0);

n = mnet_json_escape(out, sizeof(out), "a\tb");
(void)mnet_json_escape(out, sizeof(out), "a\tb");
assert(strcmp(out, "a\\tb") == 0);

n = mnet_json_escape(out, sizeof(out), "");
assert(mnet_json_escape(out, sizeof(out), "") == 0);
assert(strcmp(out, "") == 0);
assert(n == 0);

printf(" PASS test_mnet_json_escape\n");
}
Expand Down Expand Up @@ -574,25 +573,21 @@ static void test_mnet_url_decode_malformed(void)

/* The legacy wrapper must not leave a truncated value behind. */
memset(out, 'X', sizeof(out));
size_t n = mnet_url_decode(out, sizeof(out), "a%zzb");
assert(n == 0);
assert(mnet_url_decode(out, sizeof(out), "a%zzb") == 0);
assert(out[0] == '\0');

memset(out, 'X', sizeof(out));
n = mnet_url_decode(out, sizeof(out), "a%00b");
assert(n == 0);
assert(mnet_url_decode(out, sizeof(out), "a%00b") == 0);
assert(out[0] == '\0');

/* exact fit succeeds */
char buf4[4];
n = mnet_url_decode(buf4, sizeof(buf4), "abc");
assert(n == 3);
assert(mnet_url_decode(buf4, sizeof(buf4), "abc") == 3);
assert(strcmp(buf4, "abc") == 0);

/* overflow refuses */
char buf3[3];
n = mnet_url_decode(buf3, sizeof(buf3), "abcd");
assert(n == 0);
assert(mnet_url_decode(buf3, sizeof(buf3), "abcd") == 0);
assert(buf3[0] == '\0');

printf(" PASS test_mnet_url_decode_malformed\n");
Expand Down
Loading