Skip to content

Commit

Permalink
Add assertion macros, use new PCRE2_UNREACHABLE assertion at unreacha…
Browse files Browse the repository at this point in the history
…ble points in code (PCRE2Project#446)

* Correct typo ('mimimum' -> 'minimum')

* Add assertion macros

* Use PCRE2_UNREACHABLE assertion for unreachable points in code
  • Loading branch information
alexdowad authored Aug 28, 2024
1 parent 237899f commit 4f6c43d
Show file tree
Hide file tree
Showing 16 changed files with 188 additions and 50 deletions.
11 changes: 11 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ INCLUDE(CheckIncludeFile)
INCLUDE(CheckTypeSize)
INCLUDE(GNUInstallDirs) # for CMAKE_INSTALL_LIBDIR

CHECK_INCLUDE_FILE(assert.h HAVE_ASSERT_H)
CHECK_INCLUDE_FILE(dirent.h HAVE_DIRENT_H)
CHECK_INCLUDE_FILE(sys/stat.h HAVE_SYS_STAT_H)
CHECK_INCLUDE_FILE(sys/types.h HAVE_SYS_TYPES_H)
Expand All @@ -169,12 +170,22 @@ if(NOT MSVC AND NOT CMAKE_C_COMPILER_ID STREQUAL "XL")
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Werror")
endif()

CHECK_C_SOURCE_COMPILES(
"int main(void) { __builtin_expect(1+1, 2); return 0; }"
HAVE_BUILTIN_EXPECT
)

CHECK_C_SOURCE_COMPILES(
"#include <stddef.h>
int main(void) { int a,b; size_t m; __builtin_mul_overflow(a,b,&m); return 0; }"
HAVE_BUILTIN_MUL_OVERFLOW
)

CHECK_C_SOURCE_COMPILES(
"int main(void) { if (0) __builtin_unreachable(); return 0; }"
HAVE_BUILTIN_UNREACHABLE
)

CHECK_C_SOURCE_COMPILES(
"int main(void) { char buf[128] __attribute__((uninitialized)); (void)buf; return 0; }"
HAVE_ATTRIBUTE_UNINITIALIZED
Expand Down
2 changes: 1 addition & 1 deletion HACKING
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ The following are at first also followed just by an offset for use in error
messages. After the lengths of the branches of a lookbehind group have been
checked the error offset is no longer needed. The lower 16 bits of the main
word are now set to the maximum length of the first branch of the lookbehind
group, and the second word is set to the mimimum matching length for a
group, and the second word is set to the minimum matching length for a
variable-length lookbehind group, or to LOOKBEHIND_MAX for a group whose
branches are all of fixed length. These values are used when generating
OP_REVERSE or OP_VREVERSE for the first branch. The miminum value is also used
Expand Down
3 changes: 3 additions & 0 deletions config-cmake.h.in
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
/* config.h for CMake builds */

#cmakedefine HAVE_ASSERT_H 1
#cmakedefine HAVE_BUILTIN_EXPECT 1
#cmakedefine HAVE_BUILTIN_MUL_OVERFLOW 1
#cmakedefine HAVE_BUILTIN_UNREACHABLE 1
#cmakedefine HAVE_ATTRIBUTE_UNINITIALIZED 1
#cmakedefine HAVE_DIRENT_H 1
#cmakedefine HAVE_SYS_STAT_H 1
Expand Down
30 changes: 29 additions & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,20 @@ AC_SYS_LARGEFILE

PCRE2_VISIBILITY

# Check for the expect() builtin

AC_MSG_CHECKING([for __builtin_expect()])
AC_LANG_PUSH([C])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[__builtin_expect(1+1, 2)]])],
[pcre2_cc_cv_builtin_expect=yes],
[pcre2_cc_cv_builtin_expect=no])
AC_MSG_RESULT([$pcre2_cc_cv_builtin_expect])
if test "$pcre2_cc_cv_builtin_expect" = yes; then
AC_DEFINE([HAVE_BUILTIN_EXPECT], 1,
[Define this if your compiler provides __builtin_expect()])
fi
AC_LANG_POP([C])

# Check for the mul_overflow() builtin

AC_MSG_CHECKING([for __builtin_mul_overflow()])
Expand All @@ -95,6 +109,20 @@ if test "$pcre2_cc_cv_builtin_mul_overflow" = yes; then
fi
AC_LANG_POP([C])

# Check for the unreachable() builtin

AC_MSG_CHECKING([for __builtin_unreachable()])
AC_LANG_PUSH([C])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[if (0) __builtin_unreachable()]])],
[pcre2_cc_cv_builtin_unreachable=yes],
[pcre2_cc_cv_builtin_unreachable=no])
AC_MSG_RESULT([$pcre2_cc_cv_builtin_unreachable])
if test "$pcre2_cc_cv_builtin_unreachable" = yes; then
AC_DEFINE([HAVE_BUILTIN_UNREACHABLE], 1,
[Define this if your compiler provides __builtin_unreachable()])
fi
AC_LANG_POP([C])

# Check for Clang __attribute__((uninitialized)) feature

AC_MSG_CHECKING([for __attribute__((uninitialized))])
Expand Down Expand Up @@ -521,7 +549,7 @@ HAVE_BCOPY is defined. If your system has neither bcopy() nor memmove(), make
sure both macros are undefined; an emulation function will then be used. */])

# Checks for header files.
AC_CHECK_HEADERS(limits.h sys/types.h sys/stat.h dirent.h)
AC_CHECK_HEADERS(assert.h limits.h sys/types.h sys/stat.h dirent.h)
AC_CHECK_HEADERS([windows.h], [HAVE_WINDOWS_H=1])
AC_CHECK_HEADERS([sys/wait.h], [HAVE_SYS_WAIT_H=1])

Expand Down
9 changes: 9 additions & 0 deletions src/config.h.generic
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,24 @@ sure both macros are undefined; an emulation function will then be used. */
LF does in an ASCII/Unicode environment. */
/* #undef EBCDIC_NL25 */

/* Define to 1 if you have the <assert.h> header file. */
/* #undef HAVE_ASSERT_H */

/* Define this if your compiler supports __attribute__((uninitialized)) */
/* #undef HAVE_ATTRIBUTE_UNINITIALIZED */

/* Define to 1 if you have the 'bcopy' function. */
/* #undef HAVE_BCOPY */

/* Define this if your compiler provides __builtin_expect() */
/* #undef HAVE_BUILTIN_EXPECT */

/* Define this if your compiler provides __builtin_mul_overflow() */
/* #undef HAVE_BUILTIN_MUL_OVERFLOW */

/* Define this if your compiler provides __builtin_unreachable() */
/* #undef HAVE_BUILTIN_UNREACHABLE */

/* Define to 1 if you have the <bzlib.h> header file. */
/* #undef HAVE_BZLIB_H */

Expand Down
9 changes: 9 additions & 0 deletions src/config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,24 @@ sure both macros are undefined; an emulation function will then be used. */
LF does in an ASCII/Unicode environment. */
#undef EBCDIC_NL25

/* Define to 1 if you have the <assert.h> header file. */
#undef HAVE_ASSERT_H

/* Define this if your compiler supports __attribute__((uninitialized)) */
#undef HAVE_ATTRIBUTE_UNINITIALIZED

/* Define to 1 if you have the 'bcopy' function. */
#undef HAVE_BCOPY

/* Define this if your compiler provides __builtin_expect() */
#undef HAVE_BUILTIN_EXPECT

/* Define this if your compiler provides __builtin_mul_overflow() */
#undef HAVE_BUILTIN_MUL_OVERFLOW

/* Define this if your compiler provides __builtin_unreachable() */
#undef HAVE_BUILTIN_UNREACHABLE

/* Define to 1 if you have the <bzlib.h> header file. */
#undef HAVE_BZLIB_H

Expand Down
23 changes: 23 additions & 0 deletions src/pcre2.h.generic
Original file line number Diff line number Diff line change
Expand Up @@ -1002,6 +1002,29 @@ PCRE2_SUFFIX a no-op. Otherwise, generate an error. */
#endif
#endif /* PCRE2_CODE_UNIT_WIDTH is defined */

/* Assertion macros */

#ifdef HAVE_BUILTIN_UNREACHABLE
#define PCRE2_UNREACHABLE() __builtin_unreachable()
#else
#define PCRE2_UNREACHABLE() do {} while(0)
#endif

#ifdef PCRE2_DEBUG
#if defined(HAVE_BUILTIN_EXPECT) && defined(HAVE_BUILTIN_UNREACHABLE)
#define PCRE2_ASSERT(x) do { if (__builtin_expect(!(x), 0)) __builtin_unreachable(); } while (0)
#elif defined(HAVE_ASSERT_H)
#include <assert.h>
#define PCRE2_ASSERT(x) assert(x)
#elif defined(HAVE_STDLIB_H) && defined(HAVE_STDIO_H)
#define PCRE2_ASSERT(x) do { if (!(x)) { fprintf(stderr, "Assertion failed at " __FILE__ ":%d\n", __LINE__); abort(); }} while(0)
#else
#define PCRE2_ASSERT(x) do {} while(0)
#endif
#else
#define PCRE2_ASSERT(x) do {} while(0)
#endif

#ifdef __cplusplus
} /* extern "C" */
#endif
Expand Down
23 changes: 23 additions & 0 deletions src/pcre2.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,29 @@ PCRE2_SUFFIX a no-op. Otherwise, generate an error. */
#endif
#endif /* PCRE2_CODE_UNIT_WIDTH is defined */

/* Assertion macros */

#ifdef HAVE_BUILTIN_UNREACHABLE
#define PCRE2_UNREACHABLE() __builtin_unreachable()
#else
#define PCRE2_UNREACHABLE() do {} while(0)
#endif

#ifdef PCRE2_DEBUG
#if defined(HAVE_BUILTIN_EXPECT) && defined(HAVE_BUILTIN_UNREACHABLE)
#define PCRE2_ASSERT(x) do { if (__builtin_expect(!(x), 0)) __builtin_unreachable(); } while (0)
#elif defined(HAVE_ASSERT_H)
#include <assert.h>
#define PCRE2_ASSERT(x) assert(x)
#elif defined(HAVE_STDLIB_H) && defined(HAVE_STDIO_H)
#define PCRE2_ASSERT(x) do { if (!(x)) { fprintf(stderr, "Assertion failed at " __FILE__ ":%d\n", __LINE__); abort(); }} while(0)
#else
#define PCRE2_ASSERT(x) do {} while(0)
#endif
#else
#define PCRE2_ASSERT(x) do {} while(0)
#endif

#ifdef __cplusplus
} /* extern "C" */
#endif
Expand Down
9 changes: 5 additions & 4 deletions src/pcre2_auto_possess.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,8 @@ switch(ptype)
default:
return (PRIV(ucp_gentype)[prop->chartype] == ucp_Z) == negated;
}
break; /* Control never reaches here */
PCRE2_UNREACHABLE(); /* Control never reaches here */
break;

case PT_WORD:
return (PRIV(ucp_gentype)[prop->chartype] == ucp_L ||
Expand All @@ -259,7 +260,8 @@ switch(ptype)
if (c < *p) return !negated;
if (c == *p++) return negated;
}
break; /* Control never reaches here */
PCRE2_UNREACHABLE(); /* Control never reaches here */
break;

/* Haven't yet thought these through. */

Expand Down Expand Up @@ -1119,8 +1121,7 @@ for(;;)
if (list[1] == 0) return TRUE;
}

/* Control never reaches here. There used to be a fail-save return FALSE; here,
but some compilers complain about an unreachable statement. */
PCRE2_UNREACHABLE(); /* Control never reaches here */
}


Expand Down
14 changes: 8 additions & 6 deletions src/pcre2_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -5233,7 +5233,8 @@ for (;;)
return code;
}
}
/* Control never reaches here */

PCRE2_UNREACHABLE(); /* Control never reaches here */
}


Expand Down Expand Up @@ -8482,7 +8483,7 @@ for (;; pptr++)
} /* End of big switch */
} /* End of big loop */

/* Control never reaches here. */
PCRE2_UNREACHABLE(); /* Control never reaches here */
}


Expand Down Expand Up @@ -8610,7 +8611,7 @@ for (;;)
int branch_return;

/* Insert OP_REVERSE or OP_VREVERSE if this is a lookbehind assertion. There
is only a single mimimum length for the whole assertion. When the mimimum
is only a single minimum length for the whole assertion. When the minimum
length is LOOKBEHIND_MAX it means that all branches are of fixed length,
though not necessarily the same length. In this case, the original OP_REVERSE
can be used. It can also be used if a branch in a variable length lookbehind
Expand Down Expand Up @@ -8787,7 +8788,8 @@ for (;;)
lookbehindlength = META_DATA(*pptr);
pptr++;
}
/* Control never reaches here */

PCRE2_UNREACHABLE(); /* Control never reaches here */
}


Expand Down Expand Up @@ -9472,8 +9474,8 @@ for (;; pptr++)
if (meta >= sizeof(meta_extra_lengths)) return NULL;
pptr += meta_extra_lengths[meta];
}
/* Control never reaches here */
return pptr;

PCRE2_UNREACHABLE(); /* Control never reaches here */
}


Expand Down
4 changes: 1 addition & 3 deletions src/pcre2_convert.c
Original file line number Diff line number Diff line change
Expand Up @@ -1158,9 +1158,7 @@ for (i = 0; i < 2; i++)
use_length = *bufflenptr + 1;
}

/* Control should never get here. */

return PCRE2_ERROR_INTERNAL;
PCRE2_UNREACHABLE(); /* Control never reaches here */
}


Expand Down
Loading

0 comments on commit 4f6c43d

Please sign in to comment.