From 917eedb95b1456bccdd688cb7f907c87261f5acc Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Tue, 25 Apr 2023 18:02:15 -0500 Subject: [PATCH] Embedded TCC code no longer brings down the entire IDE on a sigsegv! --- CMakeLists.txt | 2 + embedded/recipe.h | 23 +++++++- src/compiler.c | 88 ++++++++++++++++++++++++++++++- src/main.c | 4 +- src/messages.c | 34 +++++++----- src/project.c | 4 ++ thirdparty/libsigsegv-2.14.tar.gz | 3 ++ tools/prebuild.sh | 17 ++++-- ui/Messages.glade | 4 +- 9 files changed, 155 insertions(+), 24 deletions(-) create mode 100644 thirdparty/libsigsegv-2.14.tar.gz diff --git a/CMakeLists.txt b/CMakeLists.txt index a681eac..bda7ed3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,6 +76,7 @@ add_custom_target(GENERATE_UI_HEADERS ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libz.a ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libtcc.a ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/tcc/libtcc1.a + ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libsigsegv.a ) add_dependencies(${CMAKE_PROJECT_NAME} GENERATE_UI_HEADERS) @@ -122,6 +123,7 @@ target_link_libraries(${CMAKE_PROJECT_NAME} ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libz.a ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libtcc.a ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/tcc/libtcc1.a + ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libsigsegv.a ${GTK3_LIBRARIES} -ldl -pthread diff --git a/embedded/recipe.h b/embedded/recipe.h index 0c4f65d..2bd393e 100644 --- a/embedded/recipe.h +++ b/embedded/recipe.h @@ -24,13 +24,32 @@ #include +#include +#include +#include +#include +#include +// These are valid for 64 bit hosts. +typedef short int16_t; +typedef int int32_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; + + +// Our shared data. extern char **___recipeTargets; -extern void recipeAddTarget(char *target); -extern void recipeMessage(char *format, ...); +// Things missing that are nice to have. +extern int fputc(int c, FILE *stream); +extern void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); + +// Our API. +extern char *utilCreateString(char *format, ...); +extern void recipeAddTarget(char *target); +extern void recipeMessage(char *format, ...); #endif // RECIPE_H diff --git a/src/compiler.c b/src/compiler.c index d3e77f0..4718220 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -23,12 +23,34 @@ #include "common.h" #include "compiler.h" #include "libtcc.h" +#include "sigsegv.h" #include "project.h" #include "messages.h" #include "utils.h" #include "array.h" +#if HAVE_SIGSEGV_RECOVERY +#include +#include + +#if defined _WIN32 && !defined __CYGWIN__ +// Windows doesn't have sigset_t. +typedef int sigset_t; +#define sigemptyset(set) +#define sigprocmask(how,set,oldset) +#endif + +volatile int runPass = 0; +jmp_buf runRecipe; +sigset_t runSigSet; + +static void sigHandlerContinuation(void *arg1, void *arg2, void *arg3); +int sigHandler(void *faultAddress, int serious); + +#endif + + char **___recipeTargets = NULL; @@ -49,7 +71,10 @@ static void compilerErrorHandler(void *opaque, const char *msg) { // All the paths passed in here are expected to be complete and absolute. int compilerRunRecipe(char *recipe, char *input, char *outputPath, void *context) { TCCState *s; - int result; + char *oldLocation; + char c; + int x; + int result = -255; int (*entry)(char *, char *); ___recipeTargets = NULL; @@ -60,9 +85,15 @@ int compilerRunRecipe(char *recipe, char *input, char *outputPath, void *context return -1; } - tcc_set_options(s, "-Wall -Wno-write-strings"); + // __resourcePath comes in with a trailing slash. Temporarily remove it. + x = strlen(__resourcePath) - 1; + c = __resourcePath[x]; + __resourcePath[x] = 0; tcc_set_lib_path(s, __resourcePath); tcc_add_sysinclude_path(s, __resourcePath); + __resourcePath[x] = c; + + tcc_set_options(s, "-Wall -Wno-write-strings"); tcc_set_error_func(s, stdout, compilerErrorHandler); tcc_set_output_type(s, TCC_OUTPUT_MEMORY); @@ -72,9 +103,13 @@ int compilerRunRecipe(char *recipe, char *input, char *outputPath, void *context return -4; } + tcc_add_symbol(s, "fputc", fputc); + tcc_add_symbol(s, "qsort", qsort); + tcc_add_symbol(s, "___recipeTargets", ___recipeTargets); tcc_add_symbol(s, "recipeAddTarget", recipeAddTarget); tcc_add_symbol(s, "recipeMessage", recipeMessage); + tcc_add_symbol(s, "utilCreateString", utilCreateString); if (tcc_relocate(s, TCC_RELOCATE_AUTO) < 0) { // Something bad happened. @@ -89,8 +124,42 @@ int compilerRunRecipe(char *recipe, char *input, char *outputPath, void *context return -3; } + getcwd(__utilFilenameBuffer, FILENAME_MAX); + oldLocation = strdup(__utilFilenameBuffer); + chdir(outputPath); + +#if HAVE_SIGSEGV_RECOVERY + sigset_t emptySet; + + runPass = 0; + + if (sigsegv_install_handler(&sigHandler) < 0) + return -5; + + sigemptyset(&emptySet); + sigprocmask(SIG_BLOCK, &emptySet, &runSigSet); + + switch (setjmp(runRecipe)) { + case 0: + result = entry(input, outputPath); + case 1: + sigprocmask(SIG_SETMASK, &runSigSet, NULL); + sigsegv_install_handler(NULL); + if (runPass != 0) { + message(MSG_SEVERE, "%s caused a segmentation fault!", recipe); + } + break; + } + +#else + result = entry(input, outputPath); +#endif + + chdir(oldLocation); + DEL(oldLocation); + while (arrlen(___recipeTargets) > 0) { if (projectAddToTree(context, ___recipeTargets[0])) { utilSetDirty((WindowDataT *)context, TRUE); @@ -106,6 +175,21 @@ int compilerRunRecipe(char *recipe, char *input, char *outputPath, void *context } +#if HAVE_SIGSEGV_RECOVERY +static void sigHandlerContinuation(void *arg1, void *arg2, void *arg3) { + (void)arg1; + (void)arg2; + (void)arg3; + longjmp(runRecipe, runPass); +} + + +int sigHandler(void *faultAddress, int serious) { + runPass++; + return sigsegv_leave_handler(sigHandlerContinuation, NULL, NULL, NULL); +} +#endif + void recipeAddTarget(char *target) { arrput(___recipeTargets, strdup(target)); } diff --git a/src/main.c b/src/main.c index 71952c6..30b6662 100644 --- a/src/main.c +++ b/src/main.c @@ -59,8 +59,8 @@ int main(int argc, char **argv) { utilExtractResource("/com/kangaroopunch/joeydev/resources/stdnoreturn.h"); utilExtractResource("/com/kangaroopunch/joeydev/resources/tccdefs.h"); utilExtractResource("/com/kangaroopunch/joeydev/resources/tcclib.h"); - utilExtractResource("/com/kangaroopunch/joeydev/resources/tgmath.h"); - utilExtractResource("/com/kangaroopunch/joeydev/resources/varargs.h"); + utilExtractResource("/com/kangaroopunch/joeydev/resources/tgmath.h"); // Not needed. + utilExtractResource("/com/kangaroopunch/joeydev/resources/varargs.h"); // Not needed. utilExtractResource("/com/kangaroopunch/joeydev/resources/recipe.h"); winJoeyDevCreate(); diff --git a/src/messages.c b/src/messages.c index a33d9c8..aa0d1dc 100644 --- a/src/messages.c +++ b/src/messages.c @@ -48,7 +48,8 @@ void message(MessageTypesT level, char *format, ...) { GtkWidget *label; va_list args; char *string; - char *temp; + char *msg; + char *tok; char *labels[MSG_COUNT] = { " Info:", "Warning:", @@ -74,24 +75,31 @@ void message(MessageTypesT level, char *format, ...) { // Display message. va_start(args, format); - temp = utilCreateStringVArgs(format, args); + msg = utilCreateStringVArgs(format, args); va_end(args); - string = utilCreateString("%s %s", labels[level], temp); + // Break multiline messages down into individual lines. + tok = strtok(msg, "\n"); + while (tok != NULL) { + //***TODO*** Filter out things that could be mistaken as markup tags. + string = utilCreateString("%s %s", labels[level], tok); - row = gtk_list_box_row_new(); - box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL,6); - gtk_widget_set_hexpand(box, TRUE); - label = gtk_label_new(string); - gtk_label_set_use_markup(GTK_LABEL(label), TRUE); + row = gtk_list_box_row_new(); + box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); + gtk_widget_set_hexpand(box, TRUE); + label = gtk_label_new(string); + gtk_label_set_use_markup(GTK_LABEL(label), TRUE); - DEL(string); + DEL(string); - gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0); - gtk_container_add(GTK_CONTAINER(row), box); - gtk_list_box_insert(GTK_LIST_BOX(_lstMessages), row, -1); + gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0); + gtk_container_add(GTK_CONTAINER(row), box); + gtk_list_box_insert(GTK_LIST_BOX(_lstMessages), row, -1); - gtk_widget_show_all(row); + gtk_widget_show_all(row); + + tok = strtok(NULL, "\n"); + } } diff --git a/src/project.c b/src/project.c index 4b1f1a9..877462c 100644 --- a/src/project.c +++ b/src/project.c @@ -180,6 +180,8 @@ EVENT void btnNewRecipeClicked(GtkButton *widget, gpointer userData) { (void)widget; + //***TODO*** This should be an embedded file. + //***TODO*** We should also provide .gitignore and .gitattribute files. if (utilFileSaveOtherAs((WindowDataT *)userData, "*.c", "Recipe", &newFile)) { out = fopen(newFile, "wt"); fprintf(out, "" @@ -1090,6 +1092,8 @@ static gboolean updateBuildOptions(ProjectDataT *self) { result = TRUE; } + //***TODO*** Grab the latest joey.h + // Unload current target listing. backup = targetArrayCopy(self->targets); targetArrayDelete(&self->targets); diff --git a/thirdparty/libsigsegv-2.14.tar.gz b/thirdparty/libsigsegv-2.14.tar.gz new file mode 100644 index 0000000..2a659d0 --- /dev/null +++ b/thirdparty/libsigsegv-2.14.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cdac3941803364cf81a908499beb79c200ead60b6b5b40cad124fd1e06caa295 +size 464658 diff --git a/tools/prebuild.sh b/tools/prebuild.sh index 4f91236..079dd61 100755 --- a/tools/prebuild.sh +++ b/tools/prebuild.sh @@ -154,12 +154,23 @@ pushd "${ROOT}" || exit &> /dev/null if [[ ! -f ${INSTALLED}/lib/libtcc.a ]]; then echo Building Dependency: TinyCC... - tar xzf ${THIRDPARTY}/tinycc-0.9.27.tar.bz2 + tar xjf ${THIRDPARTY}/tinycc-0.9.27.tar.bz2 pushd tinycc-0.9.27 || exit &> /dev/null ./configure \ --prefix=${INSTALLED} \ - --enable-static \ - --with-libgcc + --enable-static + make + make install + popd || true &> /dev/null + fi + + if [[ ! -f ${INSTALLED}/lib/libsigsegv.a ]]; then + echo Building Dependency: libsigsegv... + tar xzf ${THIRDPARTY}/libsigsegv-2.14.tar.gz + pushd libsigsegv-2.14 || exit &> /dev/null + ./configure \ + --prefix=${INSTALLED} \ + --enable-static make make install popd || true &> /dev/null diff --git a/ui/Messages.glade b/ui/Messages.glade index 6cec57e..39ed6cf 100644 --- a/ui/Messages.glade +++ b/ui/Messages.glade @@ -5,8 +5,8 @@ False Messages - 440 - 250 + 800 + 300