Skip to content

Commit 8fedeaa

Browse files
authored
Merge pull request #2871 from gilles-peskine-arm/test_malloc_0_null-2.16
Backport 2.16: Test the library when malloc(0) returns NULL
2 parents 069fb0e + c6b0986 commit 8fedeaa

File tree

3 files changed

+137
-0
lines changed

3 files changed

+137
-0
lines changed

programs/test/selftest.c

+83
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@
6666
#else
6767
#include <stdio.h>
6868
#include <stdlib.h>
69+
#define mbedtls_calloc calloc
70+
#define mbedtls_free free
6971
#define mbedtls_printf printf
7072
#define mbedtls_snprintf snprintf
7173
#define mbedtls_exit exit
@@ -78,6 +80,86 @@
7880
#endif
7981

8082

83+
#if defined MBEDTLS_SELF_TEST
84+
/* Sanity check for malloc. This is not expected to fail, and is rather
85+
* intended to display potentially useful information about the platform,
86+
* in particular the behavior of malloc(0). */
87+
static int calloc_self_test( int verbose )
88+
{
89+
int failures = 0;
90+
void *empty1 = mbedtls_calloc( 0, 1 );
91+
void *empty2 = mbedtls_calloc( 0, 1 );
92+
void *buffer1 = mbedtls_calloc( 1, 1 );
93+
void *buffer2 = mbedtls_calloc( 1, 1 );
94+
uintptr_t old_buffer1;
95+
96+
if( empty1 == NULL && empty2 == NULL )
97+
{
98+
if( verbose )
99+
mbedtls_printf( " CALLOC(0): passed (NULL)\n" );
100+
}
101+
else if( empty1 == NULL || empty2 == NULL )
102+
{
103+
if( verbose )
104+
mbedtls_printf( " CALLOC(0): failed (mix of NULL and non-NULL)\n" );
105+
++failures;
106+
}
107+
else if( empty1 == empty2 )
108+
{
109+
if( verbose )
110+
mbedtls_printf( " CALLOC(0): passed (same non-null)\n" );
111+
}
112+
else
113+
{
114+
if( verbose )
115+
mbedtls_printf( " CALLOC(0): passed (distinct non-null)\n" );
116+
}
117+
118+
if( buffer1 == NULL || buffer2 == NULL )
119+
{
120+
if( verbose )
121+
mbedtls_printf( " CALLOC(1): failed (NULL)\n" );
122+
++failures;
123+
}
124+
else if( buffer1 == buffer2 )
125+
{
126+
if( verbose )
127+
mbedtls_printf( " CALLOC(1): failed (same buffer twice)\n" );
128+
++failures;
129+
}
130+
else
131+
{
132+
if( verbose )
133+
mbedtls_printf( " CALLOC(1): passed\n" );
134+
}
135+
136+
old_buffer1 = (uintptr_t) buffer1;
137+
mbedtls_free( buffer1 );
138+
buffer1 = mbedtls_calloc( 1, 1 );
139+
if( buffer1 == NULL )
140+
{
141+
if( verbose )
142+
mbedtls_printf( " CALLOC(1 again): failed (NULL)\n" );
143+
++failures;
144+
}
145+
else
146+
{
147+
if( verbose )
148+
mbedtls_printf( " CALLOC(1 again): passed (%s address)\n",
149+
(uintptr_t) old_buffer1 == (uintptr_t) buffer1 ?
150+
"same" : "different" );
151+
}
152+
153+
if( verbose )
154+
mbedtls_printf( "\n" );
155+
mbedtls_free( empty1 );
156+
mbedtls_free( empty2 );
157+
mbedtls_free( buffer1 );
158+
mbedtls_free( buffer2 );
159+
return( failures );
160+
}
161+
#endif /* MBEDTLS_SELF_TEST */
162+
81163
static int test_snprintf( size_t n, const char ref_buf[10], int ref_ret )
82164
{
83165
int ret;
@@ -174,6 +256,7 @@ typedef struct
174256

175257
const selftest_t selftests[] =
176258
{
259+
{"calloc", calloc_self_test},
177260
#if defined(MBEDTLS_MD2_C)
178261
{"md2", mbedtls_md2_self_test},
179262
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/* config.h wrapper that forces calloc(0) to return NULL.
2+
* Used for testing.
3+
*/
4+
/*
5+
* Copyright (C) 2019, ARM Limited, All Rights Reserved
6+
* SPDX-License-Identifier: Apache-2.0
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License"); you may
9+
* not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*
20+
* This file is part of mbed TLS (https://tls.mbed.org)
21+
*/
22+
23+
#ifndef MBEDTLS_CONFIG_H
24+
/* Don't #define MBEDTLS_CONFIG_H, let config.h do it. */
25+
26+
#include "mbedtls/config.h"
27+
28+
#include <stdlib.h>
29+
static inline void *custom_calloc( size_t nmemb, size_t size )
30+
{
31+
if( nmemb == 0 || size == 0 )
32+
return( NULL );
33+
return( calloc( nmemb, size ) );
34+
}
35+
36+
#define MBEDTLS_PLATFORM_MEMORY
37+
#define MBEDTLS_PLATFORM_STD_CALLOC custom_calloc
38+
39+
#endif /* MBEDTLS_CONFIG_H */

tests/scripts/all.sh

+15
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,21 @@ component_test_platform_calloc_macro () {
992992
make test
993993
}
994994

995+
component_test_malloc_0_null () {
996+
msg "build: malloc(0) returns NULL (ASan+UBSan build)"
997+
scripts/config.pl full
998+
scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C
999+
make CC=gcc CFLAGS="'-DMBEDTLS_CONFIG_FILE=\"$PWD/tests/configs/config-wrapper-malloc-0-null.h\"' -O -Werror -Wall -Wextra -fsanitize=address,undefined" LDFLAGS='-fsanitize=address,undefined'
1000+
1001+
msg "test: malloc(0) returns NULL (ASan+UBSan build)"
1002+
make test
1003+
1004+
msg "selftest: malloc(0) returns NULL (ASan+UBSan build)"
1005+
# Just the calloc selftest. "make test" ran the others as part of the
1006+
# test suites.
1007+
if_build_succeeded programs/test/selftest calloc
1008+
}
1009+
9951010
component_test_aes_fewer_tables () {
9961011
msg "build: default config with AES_FEWER_TABLES enabled"
9971012
scripts/config.pl set MBEDTLS_AES_FEWER_TABLES

0 commit comments

Comments
 (0)