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

Add a test with a cpp executable including all mbed TLS headers #1454

Merged
merged 7 commits into from
Jul 20, 2018

Conversation

AndrzejKurek
Copy link
Contributor

Related to #1426 - in order to avoid such mistakes in the future, a test with all the mbed TLS headers included during a c++ executable building is added.

Internal ref: IOTSSL-2172

@AndrzejKurek AndrzejKurek added enhancement mbed TLS team needs-review Every commit must be reviewed by at least two team members, labels Mar 14, 2018
@AndrzejKurek
Copy link
Contributor Author

And we've got a winner:

/home/travis/build/ARMmbed/mbedtls/programs/test/header_test.cpp:117:2: error: expected '}'
}
^
/home/travis/build/ARMmbed/mbedtls/include/mbedtls/rsa_internal.h:63:12: note: to match this '{'
extern "C" {

Copy link
Contributor

@gilles-peskine-arm gilles-peskine-arm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should build the C++ program by default. Other than that, looks good.

@@ -67,6 +69,7 @@ APPS = aes/aescrypt2$(EXEXT) aes/crypt_and_hash$(EXEXT) \
random/gen_random_ctr_drbg$(EXEXT) \
test/ssl_cert_test$(EXEXT) test/benchmark$(EXEXT) \
test/selftest$(EXEXT) test/udp_proxy$(EXEXT) \
test/header_test$(EXEXT) \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should build this program by default. People who only have a C compiler and no C++ compiler, or who've set CC but not CXX, should be able to run make.

This applies to other build systems as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

#else
#include <stdio.h>
#include <stdlib.h>
#define mbedtls_printf printf
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why bother with these definitions here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wanted to keep the same include format as in the other mbed TLS files, but I guess it's not necessary here for now. Removed it.

@AndrzejKurek
Copy link
Contributor Author

This feature can be enabled by either:

  • Defining TEST_CPP using makefiles - make TEST_CPP=1
  • Defining TEST_CPP using cmake - (running cmake from a separate folder in mbed TLS directory, just to be tidy) cmake -D CMAKE_BUILD_TYPE:String="Check" -D TEST_CPP="yes" ../

int main( int argc, char *argv[] )
{
(void) argc;
(void) argv;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing return in a non void function.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In C++, that's allowed in main, by special dispensation. main has an implicit return 0.

Copy link
Contributor

@k-stachowiak k-stachowiak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no objections, just one minor remark.


int main( int argc, char *argv[] )
{
(void) argc;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C standard allows main to take no arguments, which seems to be exactly what is needed here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good tip, done.

#include "mbedtls/timing.h"
#include "mbedtls/x509.h"

#if defined(MBEDTLS_PLATFORM_C)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checking MEBDTLS_x_C should be done for all modules. Or if we always build this test with full config then why check here. For any reason if implementation for a header is missing, stubs can be provided in this test completeness sake.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can include any header file in any configuration, it's up to each header file to exclude things that shouldn't be included in a given configuration. MBEDTLS_PLATFORM_C is special in that regard.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file was intended for our CI and mainly for the cmake build, but I left a possibility for people to test their configuration with the most common exclusions - custom config.h and custom platform macros. Do you think that I should change this code, if so - how?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And - are you concerned about Including all headers despite having a smaller configuration? There are no guards in the headers anyway, .c files have ifdef guards.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I known that the guards are in C files. My question was why guard platform.h unlike others.

@@ -241,6 +247,10 @@ test/benchmark$(EXEXT): test/benchmark.c $(DEP)
echo " CC test/benchmark.c"
$(CC) $(LOCAL_CFLAGS) $(CFLAGS) test/benchmark.c $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@

test/header_test$(EXEXT): test/header_test.cpp $(DEP)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make this test self sufficient perhaps execute config.pl with full config.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, but that's up to test scripts such as all.sh, not the job of the build scripts.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you mean by self sufficient?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My idea was to have a make target that indicates whether the headers are compatible with C++. But general consensus here is do the config outside Makefile. Hence ignore this.

@@ -76,6 +78,10 @@ ifdef PTHREAD
APPS += ssl/ssl_pthread_server$(EXEXT)
endif

ifdef TEST_CPP
APPS += test/header_test$(EXEXT)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this test tests C++ compatibility of the headers with full config. It is different from other tests/programs that all build with one valid config. Please check if a full config is valid for other programs.
If not I would rather make it mutually exclusive with all other programs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This tests headers with any config - there are usually no ifdef guards in headers, hence nothing really should change.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In all.sh we should enable the full config and build this. The actual Makefile should just take the configs it's given.

@simonbutcher
Copy link
Contributor

simonbutcher commented Mar 15, 2018

Note this fix relates to existing bug #477 (IOTSSL-761), which should be closed when we merge this.

Copy link
Contributor

@simonbutcher simonbutcher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the efforts @AndrzejKurek. If you could respond to my review feedback before I approve I'd be grateful.

@@ -45,6 +45,7 @@ ssl/mini_client
test/benchmark
test/ecp-bench
test/selftest
test/header_test
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think header_test really conveys what we want to do here. Can we call it something like cpp_dummy_build? Or at least something that says it's a C++ test.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done - renamed to cpp_dummy_build.

@@ -76,6 +78,10 @@ ifdef PTHREAD
APPS += ssl/ssl_pthread_server$(EXEXT)
endif

ifdef TEST_CPP
APPS += test/header_test$(EXEXT)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In all.sh we should enable the full config and build this. The actual Makefile should just take the configs it's given.

/*
* A C++ program that includes all of the mbed TLS header files, in order to
* test if no errors are raised in the process.
*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than say we want to check we build without errors...

/*
 *  A C++ program that includes all of the mbed TLS header files, in order to
 *  test if no errors are raised in the process.

I'd like to state the purpose more clearly, so I'd propose:

/*
 * This program is a dummy C++ program to ensure Mbed TLS library header files
 * can be included and built with a C++ compiler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, updated as suggested.

#include "mbedtls/memory_buffer_alloc.h"
#endif

int main( int argc, char *argv[] )
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok - this is probably a naive question, but is this adequate? Shouldn't we want to check it links with a token function?

Mbed TLS works with C++ by compiling in C (not C++) as a C library, which the C++ linker can then resolve without the usual name mangling. As a build test, we're only confirming the preprocessor and compiler work - not the linker.

Can I propose we should call mbedlts_platform_setup() and then mbedtls_printf("CPP Build test\n") as a simple sanity test? (And the mbedtls_platform_teardown() for completeness).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we want to check this properly, we need to link with every function in the library. This would detect a missing extern "C" somewhere.

This means the .cpp source file would have to be automatically generated, which requires a rather different approach.

Automatically generating the source file would have the advantage that the list of headers would also be automatically generated. With a static file, we have to remember to add new headers. Fortunately this doesn't happen often. Still, we should add a check script (or code in an existing script) to verify that all the headers are included.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think trying to link every API function and/or a script to confirm every module is included is too much work for the moment, and a distraction from other issues. Feel free to raise those as issues if you want for the future.

However, I think we can link to a couple of files as I suggest above at little extra cost, and at least that would confirm the linker is working for something.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a basic set of calls as suggested.

simonbutcher
simonbutcher previously approved these changes Mar 16, 2018
mazimkhan
mazimkhan previously approved these changes Mar 16, 2018
Copy link

@mazimkhan mazimkhan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All my comments are answered. Approving.

@AndrzejKurek AndrzejKurek added approved Design and code approved - may be waiting for CI or backports and removed needs-review Every commit must be reviewed by at least two team members, labels Mar 16, 2018
@simonbutcher simonbutcher removed the approved Design and code approved - may be waiting for CI or backports label Mar 19, 2018
@simonbutcher
Copy link
Contributor

@gilles-peskine-arm - can you please approve, and then mark as 'ready for merge' as you see appropriate?

@AndrzejKurek
Copy link
Contributor Author

Sorry for marking as ready for merge - I thought that 2 approvals are enough for that.

Copy link
Contributor

@gilles-peskine-arm gilles-peskine-arm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's there is good. But there's no Visual Studio project. Please add one or justify why it isn't needed.

@AndrzejKurek
Copy link
Contributor Author

AndrzejKurek commented Mar 19, 2018

@gilles-peskine-arm
Do you think that there should be a C++ Visual Studio test? The C++ header check is mostly a sanity check, with a possibility for users to perform a check using their own set of headers (included via config.h). Current Visual Studio builds (as we're using it) create a C project, building our library as a C library, so creating a C++ Visual Studio project would be a new feature, with different guards to be added (for people that only want C Visual Studio builds).

@mpg mpg added needs-review Every commit must be reviewed by at least two team members, needs-work labels Apr 17, 2018
@mpg
Copy link
Contributor

mpg commented Apr 17, 2018

Re-adding "needs review" + "needs work" as there is one "change requested" review.

@simonbutcher
Copy link
Contributor

@AndrzejKurek - Looks like there's a small amount of rework and then we're good. Could you please look at this please? If you don't have access to Visual Studio, please let me know and we'll do something else.

@simonbutcher simonbutcher removed the request for review from dgreen-arm June 21, 2018 11:10
@simonbutcher simonbutcher removed the needs-review Every commit must be reviewed by at least two team members, label Jun 27, 2018
Copy link
Contributor

@k-stachowiak k-stachowiak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, however I'll hold the approval until the PR is rebased (and re-reviewed), or until it's decided the rebase is not necessary.

if [ $TEST_CXX -ne 0 ]; then
msg "build: Unix make, gcc and g++ test" # ~ 30s
cleanup
make TEST_CPP=1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason for this being CPP rather than CXX like elsewhere? It's far from being a blocker, but it is possible to make it consistent, I'd take the opportunity.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, CPP is the C preprocessor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I can change it, I just used it as an abbreviation of C++ (as in cppreference, not cxxreference).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update - Removed the flag alltogether.


msg "build: cmake, gcc and g++ test" # ~ 30s
cleanup
CC=gcc cmake -D TEST_CPP=YES .
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why test with both make and cmake? We run some tests with each to validate our build system. But here we're just building a program which has no purpose other than validating that it can be built. Any build system would do.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I opted for a larger coverage of build systems, just in case someone forces the CXX compiler for cmake to something not working.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update - Removed the cmake test.


msg "build: cmake, gcc and g++ test" # ~ 30s
cleanup
CC=gcc cmake -D TEST_CPP=YES .
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does CC=gcc influence the C++ compiler? Seems strange to me, I'd expect the C++ compiler to be ${CXX}.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does not, It's just the usual syntax used for other tests in all.sh, and I thought it's a prerequisite to compile the usual sources (which are getting compiled during this test too).

@mpg
Copy link
Contributor

mpg commented Jun 28, 2018

Just a general note on this PR: when it is merge, there should be an announcement on the relevant channels so that all developers know that from now on, every time you create a new module, you also new to add it's header to the C++ testing file.

Andrzej Kurek added 6 commits June 28, 2018 05:05
In case of any problems with the 'extern "C"' directives,
building the executable will fail
Remove unnecessary defines from the test.
Test by defining TEST_CPP using makefiles or cmake.
Change the name of header_test to cpp_dumy_build
Update the test description to better reflect its contents
@AndrzejKurek AndrzejKurek force-pushed the iotssl-2172-cpp-including-headers-test branch from 2a4a106 to 05be06c Compare June 28, 2018 09:16
@AndrzejKurek
Copy link
Contributor Author

I have rebased this PR, incorporated all of the comments, thus making the cpp test mandatory in all.sh (with no flag for removal), removed the cmake test in all.sh.
I have also updated the header list according to head state, and I've reordered them in an alphabetical order, as it is easier to spot any inconsistencies this way.
@k-stachowiak , @sbutcher-arm , @mazimkhan , @gilles-peskine-arm - please re-review.

@AndrzejKurek AndrzejKurek added needs-review Every commit must be reviewed by at least two team members, and removed needs-work labels Jun 28, 2018
@@ -580,6 +581,10 @@ msg "test/build: key-exchanges (gcc)" # ~ 1 min
cleanup
record_status tests/scripts/key-exchanges.pl

msg "build: Unix make, gcc and g++ test" # ~ 30s
cleanup
make TEST_CPP=1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we merge this with an existing build?

Advantage: faster.

Downside: slightly less good reports if it fails since we'd have to look closer at the logs to see if it's the fault of the C++. But this is all.sh anyway, we don't.

I'm not suggesting to add TEST_CPP=1 to an existing command line, that would make it harder to backport this script. Rather, add this after an existing make, before a subsequent cleanup.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So you'd like to have the following code below:

 msg "build: Unix make, -Os (gcc)" # ~ 30s
 cleanup
 make CC=gcc CFLAGS='-Werror -Wall -Wextra -Os'
+make TEST_CPP=1

?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's fine with me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated, with additional logs to make things clear.

Copy link
Contributor

@gilles-peskine-arm gilles-peskine-arm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a faithful rebase of my previous approval, plus almost-sorting the list of headers, plus an entry in all.sh. I have some reservations, but I'm willing to approve in a pinch.

#include "mbedtls/md2.h"
#include "mbedtls/md4.h"
#include "mbedtls/md5.h"
#include "mbedtls/md.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for sorting this list, but I'd prefer if it was sorted in binary order, rather than in some locale where punctuation is not sorted or sorted in a second pass and in a non-ASCII order (md.h should come before md2.h, ssl.h should come before ssl_anything.h).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the order reported by ls when using en_US.UTF-8. Could you suggest any other locale that would yield results that you've mentioned and could be considered more "default"? I'm curious, because that's what it would boil down to - checking it by hand, if not running the lengthy all-sh.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use the C locale for universally reproducible results.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

msg "build: Unix make, gcc and g++ test" # ~ 30s
cleanup
make TEST_CPP=1

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to add a check that cpp_dummy_build.cpp lists all the headers except for whitelisted ones.

check_headers_in_cpp () {
    ls include/mbedtls >headers.txt
    <programs/test/cpp_dummy_build.cpp sed -n 's/"$//; s!^#include "mbedtls/!!p' |
    sort |
    diff headers.txt -
    rm headers.txt
}
record_status check_headers_in_cpp

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will there be any whitelisted ones? Currently, this fails only because check-config.h is not included there (there's no need to test it since it does not have any extern directives), but there's no problem in adding it there.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check_config.h is the only whitelisted one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a check, included the check-config.h in the dummy build file.

change the g++ test to be incremental, to save time
reorganize header order in cpp_dummy_build.cpp according to c locale
@AndrzejKurek
Copy link
Contributor Author

@gilles-peskine-arm, @k-stachowiak, @mazimkhan - Could I kindly ask for your re-review?

@@ -77,6 +79,10 @@ ifdef PTHREAD
APPS += ssl/ssl_pthread_server$(EXEXT)
endif

ifdef TEST_CPP
APPS += test/cpp_dummy_build$(EXEXT)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you run make TEST_CPP=1 and later make clean, then test/cpp_dummy_build doesn't get cleaned. There's a similar preexisting defect with ssl/ssl_pthread_server. The defect with test/cpp_dummy_build is worse because we include it in our test scripts.

I won't block the PR for that, but please, in order of preference, either:

  • arrange for make clean to remove test/cpp_dummy_build (and ssl/ssl_pthread_server) regardless of the value of TEST_CPP;
  • or file an issue.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AndrzejKurek is out for a couple of weeks, so I've raised this as issue #1862, so we can at least merge what we have, and fix this later, as it's a minor issue,

@simonbutcher simonbutcher added approved Design and code approved - may be waiting for CI or backports and removed needs-review Every commit must be reviewed by at least two team members, labels Jul 16, 2018
@simonbutcher
Copy link
Contributor

CircleCI is failing, but that can be disregarded.

@simonbutcher simonbutcher merged commit 991f9fe into development Jul 20, 2018
@simonbutcher simonbutcher deleted the iotssl-2172-cpp-including-headers-test branch July 20, 2018 19:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Design and code approved - may be waiting for CI or backports enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants