Embedded TCC code no longer brings down the entire IDE on a sigsegv!

This commit is contained in:
Scott Duensing 2023-04-25 18:02:15 -05:00
parent 4b32b111cf
commit 917eedb95b
9 changed files with 155 additions and 24 deletions

View file

@ -76,6 +76,7 @@ add_custom_target(GENERATE_UI_HEADERS
${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libz.a ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libz.a
${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libtcc.a ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libtcc.a
${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/tcc/libtcc1.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) 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/libz.a
${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libtcc.a ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libtcc.a
${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/tcc/libtcc1.a ${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/tcc/libtcc1.a
${CMAKE_SOURCE_DIR}/thirdparty-installed/lib/libsigsegv.a
${GTK3_LIBRARIES} ${GTK3_LIBRARIES}
-ldl -ldl
-pthread -pthread

View file

@ -24,11 +24,30 @@
#include <tcclib.h> #include <tcclib.h>
#include <float.h>
#include <stdalign.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <stdnoreturn.h>
// 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 char **___recipeTargets;
// 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 recipeAddTarget(char *target);
extern void recipeMessage(char *format, ...); extern void recipeMessage(char *format, ...);

View file

@ -23,12 +23,34 @@
#include "common.h" #include "common.h"
#include "compiler.h" #include "compiler.h"
#include "libtcc.h" #include "libtcc.h"
#include "sigsegv.h"
#include "project.h" #include "project.h"
#include "messages.h" #include "messages.h"
#include "utils.h" #include "utils.h"
#include "array.h" #include "array.h"
#if HAVE_SIGSEGV_RECOVERY
#include <setjmp.h>
#include <signal.h>
#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; 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. // All the paths passed in here are expected to be complete and absolute.
int compilerRunRecipe(char *recipe, char *input, char *outputPath, void *context) { int compilerRunRecipe(char *recipe, char *input, char *outputPath, void *context) {
TCCState *s; TCCState *s;
int result; char *oldLocation;
char c;
int x;
int result = -255;
int (*entry)(char *, char *); int (*entry)(char *, char *);
___recipeTargets = NULL; ___recipeTargets = NULL;
@ -60,9 +85,15 @@ int compilerRunRecipe(char *recipe, char *input, char *outputPath, void *context
return -1; 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_set_lib_path(s, __resourcePath);
tcc_add_sysinclude_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_error_func(s, stdout, compilerErrorHandler);
tcc_set_output_type(s, TCC_OUTPUT_MEMORY); tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
@ -72,9 +103,13 @@ int compilerRunRecipe(char *recipe, char *input, char *outputPath, void *context
return -4; return -4;
} }
tcc_add_symbol(s, "fputc", fputc);
tcc_add_symbol(s, "qsort", qsort);
tcc_add_symbol(s, "___recipeTargets", ___recipeTargets); tcc_add_symbol(s, "___recipeTargets", ___recipeTargets);
tcc_add_symbol(s, "recipeAddTarget", recipeAddTarget); tcc_add_symbol(s, "recipeAddTarget", recipeAddTarget);
tcc_add_symbol(s, "recipeMessage", recipeMessage); tcc_add_symbol(s, "recipeMessage", recipeMessage);
tcc_add_symbol(s, "utilCreateString", utilCreateString);
if (tcc_relocate(s, TCC_RELOCATE_AUTO) < 0) { if (tcc_relocate(s, TCC_RELOCATE_AUTO) < 0) {
// Something bad happened. // Something bad happened.
@ -89,7 +124,41 @@ int compilerRunRecipe(char *recipe, char *input, char *outputPath, void *context
return -3; 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); 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) { while (arrlen(___recipeTargets) > 0) {
if (projectAddToTree(context, ___recipeTargets[0])) { if (projectAddToTree(context, ___recipeTargets[0])) {
@ -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) { void recipeAddTarget(char *target) {
arrput(___recipeTargets, strdup(target)); arrput(___recipeTargets, strdup(target));
} }

View file

@ -59,8 +59,8 @@ int main(int argc, char **argv) {
utilExtractResource("/com/kangaroopunch/joeydev/resources/stdnoreturn.h"); utilExtractResource("/com/kangaroopunch/joeydev/resources/stdnoreturn.h");
utilExtractResource("/com/kangaroopunch/joeydev/resources/tccdefs.h"); utilExtractResource("/com/kangaroopunch/joeydev/resources/tccdefs.h");
utilExtractResource("/com/kangaroopunch/joeydev/resources/tcclib.h"); utilExtractResource("/com/kangaroopunch/joeydev/resources/tcclib.h");
utilExtractResource("/com/kangaroopunch/joeydev/resources/tgmath.h"); utilExtractResource("/com/kangaroopunch/joeydev/resources/tgmath.h"); // Not needed.
utilExtractResource("/com/kangaroopunch/joeydev/resources/varargs.h"); utilExtractResource("/com/kangaroopunch/joeydev/resources/varargs.h"); // Not needed.
utilExtractResource("/com/kangaroopunch/joeydev/resources/recipe.h"); utilExtractResource("/com/kangaroopunch/joeydev/resources/recipe.h");
winJoeyDevCreate(); winJoeyDevCreate();

View file

@ -48,7 +48,8 @@ void message(MessageTypesT level, char *format, ...) {
GtkWidget *label; GtkWidget *label;
va_list args; va_list args;
char *string; char *string;
char *temp; char *msg;
char *tok;
char *labels[MSG_COUNT] = { char *labels[MSG_COUNT] = {
"<span foreground=\"gray\"> Info:</span>", "<span foreground=\"gray\"> Info:</span>",
"<span foreground=\"yellow\">Warning:</span>", "<span foreground=\"yellow\">Warning:</span>",
@ -74,10 +75,14 @@ void message(MessageTypesT level, char *format, ...) {
// Display message. // Display message.
va_start(args, format); va_start(args, format);
temp = utilCreateStringVArgs(format, args); msg = utilCreateStringVArgs(format, args);
va_end(args); va_end(args);
string = utilCreateString("<tt>%s %s</tt>", 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("<tt>%s %s</tt>", labels[level], tok);
row = gtk_list_box_row_new(); row = gtk_list_box_row_new();
box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
@ -92,6 +97,9 @@ void message(MessageTypesT level, char *format, ...) {
gtk_list_box_insert(GTK_LIST_BOX(_lstMessages), row, -1); gtk_list_box_insert(GTK_LIST_BOX(_lstMessages), row, -1);
gtk_widget_show_all(row); gtk_widget_show_all(row);
tok = strtok(NULL, "\n");
}
} }

View file

@ -180,6 +180,8 @@ EVENT void btnNewRecipeClicked(GtkButton *widget, gpointer userData) {
(void)widget; (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)) { if (utilFileSaveOtherAs((WindowDataT *)userData, "*.c", "Recipe", &newFile)) {
out = fopen(newFile, "wt"); out = fopen(newFile, "wt");
fprintf(out, "" fprintf(out, ""
@ -1090,6 +1092,8 @@ static gboolean updateBuildOptions(ProjectDataT *self) {
result = TRUE; result = TRUE;
} }
//***TODO*** Grab the latest joey.h
// Unload current target listing. // Unload current target listing.
backup = targetArrayCopy(self->targets); backup = targetArrayCopy(self->targets);
targetArrayDelete(&self->targets); targetArrayDelete(&self->targets);

BIN
thirdparty/libsigsegv-2.14.tar.gz (Stored with Git LFS) vendored Normal file

Binary file not shown.

View file

@ -154,12 +154,23 @@ pushd "${ROOT}" || exit &> /dev/null
if [[ ! -f ${INSTALLED}/lib/libtcc.a ]]; then if [[ ! -f ${INSTALLED}/lib/libtcc.a ]]; then
echo Building Dependency: TinyCC... 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 pushd tinycc-0.9.27 || exit &> /dev/null
./configure \ ./configure \
--prefix=${INSTALLED} \ --prefix=${INSTALLED} \
--enable-static \ --enable-static
--with-libgcc 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
make install make install
popd || true &> /dev/null popd || true &> /dev/null

View file

@ -5,8 +5,8 @@
<object class="GtkWindow" id="winMessages"> <object class="GtkWindow" id="winMessages">
<property name="can-focus">False</property> <property name="can-focus">False</property>
<property name="title" translatable="yes">Messages</property> <property name="title" translatable="yes">Messages</property>
<property name="default-width">440</property> <property name="default-width">800</property>
<property name="default-height">250</property> <property name="default-height">300</property>
<signal name="delete-event" handler="winMessagesClose" swapped="no"/> <signal name="delete-event" handler="winMessagesClose" swapped="no"/>
<child> <child>
<object class="GtkScrolledWindow"> <object class="GtkScrolledWindow">