Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Let's fix the tests enough to run with AddressSanitizer and UB Sanitizer and enable those in CI #1151

Merged
merged 38 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
ff2bd0a
unit-test CMake: Add option to build with sanitizers
anordal Jun 4, 2024
7821269
unit-test CMake: Remove compile_options(-O0 -Wno-div-by-zero)
anordal Jun 4, 2024
1004eb2
unit-test: Fix missing symbol in a few tests (linker error)
anordal Jun 4, 2024
b3dc4a6
unit-test: Fix segfault due to discrepancy between the real and mocke…
anordal Jun 4, 2024
662a57e
FreeRTOS_ND_utest: Fix segfaults caused by no ethernet buffer
anordal Jun 4, 2024
93ae7bd
test_prvProcessEthernetPacket_*(): Fix memset(NULL, …) segfaults
anordal Jun 4, 2024
9e0a3a8
unit-test: Fix pxEthernetBuffer[-ipIP_TYPE_OFFSET] buffer underflows
anordal Jun 4, 2024
8b1ba02
test_vTCPWindowDestroy_list_length_not_zero(): Fix buffer overflow du…
anordal Jun 4, 2024
7c17cd4
test_eARPGetCacheEntryByMac_OneMatchingEntry(): Arrest dangling pointer
anordal Jun 4, 2024
468548e
FreeRTOS_TCP_Transmission_utest: Fix stack use after return: Point at…
anordal Jun 4, 2024
a926beb
FreeRTOS_TCP_IP_utest.c: Fix buffer overflow
anordal Jun 4, 2024
f4cdff0
prvTCPNextTimeout(): Fix leftshift by ~0 encountered in unittest
anordal Jun 4, 2024
abaea8c
FreeRTOS_DNS_Callback_utest: Fix buffer overflow caused by mocked malloc
anordal Jun 4, 2024
d94800a
test_vReceiveRA_vRAProcess(): Fix buffer overflow in test: Don't cast
anordal Jun 4, 2024
85bd89c
test_DNS_ParseDNSReply_answer_lmmnr_reply3(): Fix test failure due to…
anordal Jun 4, 2024
42d54ef
DNS: test_SendRequest_fail(): Fix testing the failure scenario
anordal Jun 4, 2024
d839080
FreeRTOS_DNS_utest.c: Fix size to copy when copying pointers instead …
anordal Jun 4, 2024
dbdf168
unit-test of DHCP option parser: Delete the buffer overflow
anordal Jun 4, 2024
1625765
test_eHandleIPv6ExtensionHeaders_TCPHappyPath: Fix buffer overflow
anordal Jun 4, 2024
df87c35
FreeRTOS_DNS.c: Fix NULL deref encountered in test_FreeRTOS_gethostby…
anordal Jun 4, 2024
7969ef0
FreeRTOS_DNS_Parser_utest: Don't return dangling pointers
anordal Jun 4, 2024
46a6557
FreeRTOS_DHCP_utest: Fix a read out of bounds
anordal Jun 4, 2024
37ac5cf
FreeRTOS_{DNS,Routing}_utest.c: Fix off-by-one buffer overflows
anordal Jun 4, 2024
2c00d48
unit-test FreeRTOS_DHCP_stubs.c: Fix NetworkBufferDescriptor_t alignment
anordal Jun 4, 2024
d559aec
FreeRTOS_{DHCPv6,DNS}_utest: Fix memory leaks
anordal Jun 4, 2024
bb80402
FreeRTOS_DNS_Parser_utest: Fix misaligned writes in the test
anordal Jun 4, 2024
ac05ffb
FreeRTOS_TCP_WIN_utest.c: Fix memory leaks of type free(NULL)
anordal Jun 4, 2024
6f64aa8
FreeRTOS_DHCP_utest: Fix misaligned writing of DHCP option fields
anordal Jun 4, 2024
dc1a5cb
FreeRTOS_ND_utest.c: Remove failing but redundant test
anordal Jun 4, 2024
402fd0c
unit-test: Fix differences between with and without sanitization due …
anordal Jun 4, 2024
a343be0
unit-test: Add FIXME for behavioural difference with sanitizers
anordal Jun 4, 2024
10c85d4
FreeRTOS_DNS_Parser_utest.c: Fix buffer alignment
anordal Jun 4, 2024
754f495
CI: Add SANITIZE=address,undefined build
anordal Jun 4, 2024
33d9aba
FreeRTOS_ND_utest: Don't use an uninitialized ip address
anordal Jun 4, 2024
4a08c8a
FreeRTOS_DHCP_utest: Fix attempt at making recvfrom return a NULL buffer
anordal Jun 4, 2024
66e54ed
FreeRTOS_ND_utest: Fix test failures due to missing initialization
anordal Jun 4, 2024
88a73c4
test_lTCPWindowTxAdd_nothing_to_do(): Fix TCP window initialization
anordal Jun 4, 2024
7f92b55
Merge branch 'main' into build-unittests-with-sanitizers
tony-josi-aws Jun 8, 2024
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
1 change: 1 addition & 0 deletions .github/.cSpellWords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ FPSP
FRAMERX
FRMFILTER
frms
fsanitize
FSDMA
FTSR
FUDUP
Expand Down
37 changes: 33 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,27 +38,56 @@ jobs:
echo "::endgroup::"
echo -e "${{ env.bashPass }} ${{ env.stepName }} ${{ env.bashEnd }}"

# Separate builds for sanitizers and coverage:
# These can currently not be combined without branch coverage dilution.
- env:
stepName: Build Unit Tests
stepName: Build Unit Tests (aubsan build)
name: ${{ env.stepName }}
run: |
# ${{ env.stepName }}
echo -e "::group::${{ env.bashInfo }} ${{ env.stepName }} ${{ env.bashEnd }}"

cmake -S test/unit-test -B test/unit-test/build/ -G Ninja
cmake --build test/unit-test/build/ --target all
cmake --fresh -G Ninja -S test/unit-test -B test/unit-test/build/ -DSANITIZE=address,undefined
ninja -C test/unit-test/build/

echo "::endgroup::"
echo -e "${{ env.bashPass }} ${{ env.stepName }} ${{ env.bashEnd }}"

- env:
stepName: Run Unit Tests
stepName: Run Unit Tests (aubsan build)
name: ${{ env.stepName }}
shell: bash
run: |
# ${{ env.stepName }}
echo -e "::group::${{ env.bashInfo }} ${{ env.stepName }} ${{ env.bashEnd }}"

env ASAN_OPTIONS=detect_odr_violation=0 ctest --test-dir test/unit-test/build/ -E system --output-on-failure

echo "::endgroup::"
echo -e "${{ env.bashPass }} ${{ env.stepName }} ${{ env.bashEnd }}"

- env:
stepName: Build Unit Tests (coverage build)
name: ${{ env.stepName }}
run: |
# ${{ env.stepName }}
echo -e "::group::${{ env.bashInfo }} ${{ env.stepName }} ${{ env.bashEnd }}"

cmake --fresh -G Ninja -S test/unit-test -B test/unit-test/build/ -DSANITIZE=
ninja -C test/unit-test/build/

echo "::endgroup::"
echo -e "${{ env.bashPass }} ${{ env.stepName }} ${{ env.bashEnd }}"

- env:
stepName: Run Unit Tests (coverage build)
name: ${{ env.stepName }}
shell: bash
run: |
# ${{ env.stepName }}
echo -e "::group::${{ env.bashInfo }} ${{ env.stepName }} ${{ env.bashEnd }}"

find test/unit-test/build/ -name '*.gcda' -delete
ctest --test-dir test/unit-test/build/ -E system --output-on-failure

echo "::endgroup::"
Expand Down
2 changes: 1 addition & 1 deletion source/FreeRTOS_DNS.c
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,7 @@
if( ulIPAddress != 0UL )
{
#if ( ipconfigUSE_IPv6 != 0 )
if( ( ppxAddressInfo != NULL ) && ( ( *ppxAddressInfo )->ai_family == FREERTOS_AF_INET6 ) )
if( ( ppxAddressInfo != NULL ) && ( *ppxAddressInfo != NULL ) && ( ( *ppxAddressInfo )->ai_family == FREERTOS_AF_INET6 ) )
{
FreeRTOS_printf( ( "prvPrepareLookup: found '%s' in cache: %pip\n",
pcHostName, ( void * ) ( *ppxAddressInfo )->xPrivateStorage.sockaddr.sin_address.xIP_IPv6.ucBytes ) );
Expand Down
9 changes: 8 additions & 1 deletion source/FreeRTOS_TCP_IP.c
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,14 @@
* active connect(). */
if( pxSocket->u.xTCP.ucRepCount < 3U )
{
ulDelayMs = ( ( ( uint32_t ) 3000U ) << ( pxSocket->u.xTCP.ucRepCount - 1U ) );
if( pxSocket->u.xTCP.ucRepCount == 0U )
{
ulDelayMs = 0U;
}
else
{
ulDelayMs = ( ( uint32_t ) 3000U ) << ( pxSocket->u.xTCP.ucRepCount - 1U );
}
}
else
{
Expand Down
6 changes: 6 additions & 0 deletions test/unit-test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ if( ${PROJECT_SOURCE_DIR} STREQUAL ${PROJECT_BINARY_DIR} )
message( FATAL_ERROR "In-source build is not allowed. Please build in a separate directory, such as ${PROJECT_SOURCE_DIR}/build." )
endif()

set(SANITIZE "" CACHE STRING "Comma-separated list of compiler sanitizers to enable; empty string disables.")
if(NOT ${SANITIZE} STREQUAL "")
add_compile_options(-fsanitize=${SANITIZE} -fno-sanitize-recover)
add_link_options(-fsanitize=${SANITIZE} -fno-sanitize-recover)
endif()

# Set global path variables.
get_filename_component( __MODULE_ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE )
set( MODULE_ROOT_DIR ${__MODULE_ROOT_DIR} CACHE INTERNAL "FreeRTOS-Plus-TCP repository root." )
Expand Down
12 changes: 9 additions & 3 deletions test/unit-test/FreeRTOS_ARP/FreeRTOS_ARP_utest.c
Original file line number Diff line number Diff line change
Expand Up @@ -2034,29 +2034,34 @@ void test_eARPGetCacheEntryByMac_OneMatchingEntry( void )
eARPLookupResult_t eResult;
MACAddress_t xMACAddress = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 };
int i;
struct xNetworkInterface * xInterface;
NetworkEndPoint_t xNetworkEndPoint = { 0 };
NetworkInterface_t xInterface, * pxInterface = NULL;

xNetworkEndPoint.pxNetworkInterface = &xInterface;

/* =================================================== */
/* Make sure one entry matches. */
for( i = 0; i < ipconfigARP_CACHE_ENTRIES; i++ )
{
xARPCache[ i ].ulIPAddress = 0xAABBCCDD;
xARPCache[ i ].pxEndPoint = &xNetworkEndPoint;
memset( xARPCache[ i ].xMACAddress.ucBytes, 0x11, sizeof( xMACAddress.ucBytes ) );
}

ulEntryToTest = 1;
memset( xARPCache[ ulEntryToTest ].xMACAddress.ucBytes, 0x22, sizeof( xMACAddress.ucBytes ) );
xARPCache[ ulEntryToTest ].ulIPAddress = 0xAABBCCEE;
eResult = eARPGetCacheEntryByMac( &xMACAddress, &ulIPAddress, &xInterface );
eResult = eARPGetCacheEntryByMac( &xMACAddress, &ulIPAddress, &pxInterface );
TEST_ASSERT_EQUAL( eARPCacheHit, eResult );
TEST_ASSERT_EQUAL( xARPCache[ ulEntryToTest ].ulIPAddress, ulIPAddress );
TEST_ASSERT_EQUAL( &xInterface, pxInterface );
/* =================================================== */
eResult = eARPGetCacheEntryByMac( &xMACAddress, &ulIPAddress, NULL );
TEST_ASSERT_EQUAL( eARPCacheHit, eResult );
TEST_ASSERT_EQUAL( xARPCache[ ulEntryToTest ].ulIPAddress, ulIPAddress );
/* =================================================== */
xARPCache[ ulEntryToTest ].pxEndPoint = NULL;
eResult = eARPGetCacheEntryByMac( &xMACAddress, &ulIPAddress, &xInterface );
eResult = eARPGetCacheEntryByMac( &xMACAddress, &ulIPAddress, &pxInterface );
TEST_ASSERT_EQUAL( eARPCacheHit, eResult );
TEST_ASSERT_EQUAL( xARPCache[ ulEntryToTest ].ulIPAddress, ulIPAddress );
/* =================================================== */
Expand Down Expand Up @@ -2305,6 +2310,7 @@ void test_eARPGetCacheEntry_NoCacheHit( void )
{
xARPCache[ i ].ulIPAddress = 0;
xARPCache[ i ].ucValid = ( uint8_t ) pdTRUE;
xARPCache[ i ].pxEndPoint = NULL;
}

ulSavedGatewayAddress = xNetworkAddressing.ulGatewayAddress;
Expand Down
35 changes: 20 additions & 15 deletions test/unit-test/FreeRTOS_DHCP/FreeRTOS_DHCP_stubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
#include "FreeRTOS_IP.h"
#include "FreeRTOS_IP_Private.h"

#define prvROUND_UP_TO( SIZE, ALIGNMENT ) ( ( ( SIZE ) + ( ALIGNMENT ) -1 ) / ( ALIGNMENT ) *( ALIGNMENT ) )

/* FIXME: Consider instead fixing ipBUFFER_PADDING if it's supposed to be pointer aligned. */
#define prvALIGNED_BUFFER_PADDING prvROUND_UP_TO( ipBUFFER_PADDING, sizeof( void * ) )

struct xNetworkEndPoint * pxNetworkEndPoints = NULL;

NetworkInterface_t xInterfaces[ 1 ];
Expand Down Expand Up @@ -212,9 +217,9 @@ static NetworkBufferDescriptor_t * GetNetworkBuffer( size_t SizeOfEthBuf,
long unsigned int xTimeToBlock,
int callbacks )
{
NetworkBufferDescriptor_t * pxNetworkBuffer = malloc( sizeof( NetworkBufferDescriptor_t ) + ipBUFFER_PADDING ) + ipBUFFER_PADDING;
NetworkBufferDescriptor_t * pxNetworkBuffer = malloc( sizeof( NetworkBufferDescriptor_t ) + prvALIGNED_BUFFER_PADDING ) + prvALIGNED_BUFFER_PADDING;

pxNetworkBuffer->pucEthernetBuffer = malloc( SizeOfEthBuf + ipBUFFER_PADDING ) + ipBUFFER_PADDING;
pxNetworkBuffer->pucEthernetBuffer = malloc( SizeOfEthBuf + prvALIGNED_BUFFER_PADDING ) + prvALIGNED_BUFFER_PADDING;

/* Ignore the callback count. */
( void ) callbacks;
Expand All @@ -230,9 +235,9 @@ static NetworkBufferDescriptor_t * GetNetworkBuffer( size_t SizeOfEthBuf,
static void ReleaseNetworkBuffer( void )
{
/* Free the ethernet buffer. */
free( ( ( uint8_t * ) pxGlobalNetworkBuffer[ --GlobalBufferCounter ]->pucEthernetBuffer ) - ipBUFFER_PADDING );
free( ( ( uint8_t * ) pxGlobalNetworkBuffer[ --GlobalBufferCounter ]->pucEthernetBuffer ) - prvALIGNED_BUFFER_PADDING );
/* Free the network buffer. */
free( ( ( uint8_t * ) pxGlobalNetworkBuffer[ GlobalBufferCounter ] ) - ipBUFFER_PADDING );
free( ( ( uint8_t * ) pxGlobalNetworkBuffer[ GlobalBufferCounter ] ) - prvALIGNED_BUFFER_PADDING );
}

static void ReleaseUDPBuffer( const void * temp,
Expand Down Expand Up @@ -289,19 +294,19 @@ static int32_t FreeRTOS_recvfrom_Generic( const ConstSocket_t xSocket,
return ulGenericLength;
}

static int32_t FreeRTOS_recvfrom_Generic_NullBuffer( const ConstSocket_t xSocket,
void * pvBuffer,
size_t uxBufferLength,
BaseType_t xFlags,
struct freertos_sockaddr * pxSourceAddress,
socklen_t * pxSourceAddressLength,
int callbacks )
static int32_t FreeRTOS_recvfrom_Small_NullBuffer( const ConstSocket_t xSocket,
void * pvBuffer,
size_t uxBufferLength,
BaseType_t xFlags,
struct freertos_sockaddr * pxSourceAddress,
socklen_t * pxSourceAddressLength,
int callbacks )
{
pvBuffer = NULL;
return xSizeofUDPBuffer;
/* Admittedly, returning a (NULL, 1) slice is contrived, but coverage speaks. */
*( ( uint8_t ** ) pvBuffer ) = NULL;
return 1;
}


static int32_t FreeRTOS_recvfrom_eWaitingOfferRecvfromLessBytesNoTimeout( const ConstSocket_t xSocket,
void * pvBuffer,
size_t uxBufferLength,
Expand Down Expand Up @@ -336,7 +341,7 @@ static int32_t FreeRTOS_recvfrom_ResetAndIncorrectStateWithSocketAlreadyCreated_
pxIterator = pxIterator->pxNext;
}

if( xFlags == FREERTOS_ZERO_COPY + FREERTOS_MSG_PEEK )
if( ( xFlags & FREERTOS_ZERO_COPY ) != 0 )
{
*( ( uint8_t ** ) pvBuffer ) = pucUDPBuffer;
}
Expand Down
Loading
Loading