diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c6d58e..19db91f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.0) -project(libfort VERSION 0.3.1) +project(libfort VERSION 0.3.2) string(REGEX REPLACE "([0-9]+)\\.([0-9]+)\\.([0-9]+)" "\\1.\\2" libfort_SOVERSION diff --git a/ChangeLog.md b/ChangeLog.md index 8ecaa1b..7b3bbbd 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,3 +1,9 @@ +## v0.3.2 + +### Bug fixes + +- Fix undefined behavior due to incorrect usage of `isprint` function. + ## v0.3.1 ### Bug fixes diff --git a/lib/fort.c b/lib/fort.c index 9888e9e..d93b162 100644 --- a/lib/fort.c +++ b/lib/fort.c @@ -2582,7 +2582,6 @@ SOFTWARE. #include #include #include -#include /* #include "vector.h" */ /* Commented by amalgamation script */ /* #include "fort_utils.h" */ /* Commented by amalgamation script */ @@ -5416,10 +5415,14 @@ int print_row_separator_impl(f_conv_context_t *cntx, size_t i = 0; /* If all chars are not printable, skip line separator */ - if ((strlen(*L) == 0 || (strlen(*L) == 1 && !isprint(**L))) - && (strlen(*I) == 0 || (strlen(*I) == 1 && !isprint(**I))) - && (strlen(*IV) == 0 || (strlen(*IV) == 1 && !isprint(**IV))) - && (strlen(*R) == 0 || (strlen(*R) == 1 && !isprint(**R)))) { + /* NOTE: argument of `isprint` should be explicitly converted to + * unsigned char according to + * https://en.cppreference.com/w/c/string/byte/isprint + */ + if ((strlen(*L) == 0 || (strlen(*L) == 1 && !isprint((unsigned char) **L))) + && (strlen(*I) == 0 || (strlen(*I) == 1 && !isprint((unsigned char) **I))) + && (strlen(*IV) == 0 || (strlen(*IV) == 1 && !isprint((unsigned char) **IV))) + && (strlen(*R) == 0 || (strlen(*R) == 1 && !isprint((unsigned char) **R)))) { status = 0; goto clear; } diff --git a/lib/fort.h b/lib/fort.h index a45a0e4..efda242 100644 --- a/lib/fort.h +++ b/lib/fort.h @@ -46,8 +46,8 @@ SOFTWARE. #define LIBFORT_MAJOR_VERSION 0 #define LIBFORT_MINOR_VERSION 3 -#define LIBFORT_REVISION 0 -#define LIBFORT_VERSION_STR "0.3.0" +#define LIBFORT_REVISION 2 +#define LIBFORT_VERSION_STR "0.3.2" /***************************************************************************** diff --git a/src/fort.h b/src/fort.h index a47ae64..efda242 100644 --- a/src/fort.h +++ b/src/fort.h @@ -46,8 +46,8 @@ SOFTWARE. #define LIBFORT_MAJOR_VERSION 0 #define LIBFORT_MINOR_VERSION 3 -#define LIBFORT_REVISION 1 -#define LIBFORT_VERSION_STR "0.3.1" +#define LIBFORT_REVISION 2 +#define LIBFORT_VERSION_STR "0.3.2" /***************************************************************************** diff --git a/src/fort_impl.c b/src/fort_impl.c index 446478e..8902658 100644 --- a/src/fort_impl.c +++ b/src/fort_impl.c @@ -31,7 +31,6 @@ SOFTWARE. #include #include #include -#include #include "vector.h" #include "fort_utils.h" diff --git a/src/row.c b/src/row.c index 0041213..84987c5 100644 --- a/src/row.c +++ b/src/row.c @@ -353,10 +353,14 @@ int print_row_separator_impl(f_conv_context_t *cntx, size_t i = 0; /* If all chars are not printable, skip line separator */ - if ((strlen(*L) == 0 || (strlen(*L) == 1 && !isprint(**L))) - && (strlen(*I) == 0 || (strlen(*I) == 1 && !isprint(**I))) - && (strlen(*IV) == 0 || (strlen(*IV) == 1 && !isprint(**IV))) - && (strlen(*R) == 0 || (strlen(*R) == 1 && !isprint(**R)))) { + /* NOTE: argument of `isprint` should be explicitly converted to + * unsigned char according to + * https://en.cppreference.com/w/c/string/byte/isprint + */ + if ((strlen(*L) == 0 || (strlen(*L) == 1 && !isprint((unsigned char) **L))) + && (strlen(*I) == 0 || (strlen(*I) == 1 && !isprint((unsigned char) **I))) + && (strlen(*IV) == 0 || (strlen(*IV) == 1 && !isprint((unsigned char) **IV))) + && (strlen(*R) == 0 || (strlen(*R) == 1 && !isprint((unsigned char) **R)))) { status = 0; goto clear; }