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/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

View file

@ -24,13 +24,32 @@
#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 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

View file

@ -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 <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;
@ -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));
}

View file

@ -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();

View file

@ -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] = {
"<span foreground=\"gray\"> Info:</span>",
"<span foreground=\"yellow\">Warning:</span>",
@ -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("<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();
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");
}
}

View file

@ -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);

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
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

View file

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