From a05a33be9ed15982aabfa13726317a1fcb13cc19 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Sun, 7 Oct 2007 21:03:54 +0200 Subject: [PATCH] Only declare error codes that are safe to use. The following type of bug occurred frequently since the introduction of error.h: An error code was defined for some file a.c and was used in another file b.c. This is all good if each executable that contains b.o also contains a.o. If this is not the case, i.e. if there is an executable that contains b.o but _not_ a.o, the error texts of all errors defined for a.c are not included in the executable. This results in a segmentation fault at runtime if PARA_STRERROR() is used for such an error code. Unfortunately, this was hard to spot because all error codes were visible everywhere. This patch gets rid of this flaw by making only those error codes visible for b.c which are safe to use. According to the above, the set of error codes which are safe to use in b.c can be defined as follows. Let E_1, ... E_n be the set of executables that contain b.o and let, for j=1,...n, S_j be the set of files those files contained in E_j. Then, all errors defined in the intersection S_1 \cap S_2 \cap ... \cap S_n are safe to use in b.c. The patch adds a function to configure.ac That computes this intersection. Unfortunately, it is rather expensive. The good news is that this simplifies error.h a bit and that it already revealed a couple of bugs which are also fixed in the patch: - afs.c used E_SIGNAL_CAUGHT which was only defined in audiod. Introduce E_AFS_SIGNAL and change afs.c accordingly. - audiod uses E_RECV_SYNTAX, which belonged to recv which is not contained in audiod. Move it to recv_common instead. This bug is also present in v0.2.x and needs a similar fix. - E_NOTDIR was used in fd.c, but was defined in osl.c. Not all executables that include fd.o also include osl.o. Move E_NOTDIR to the set of errors for fd. --- Makefile.in | 2 +- afs.c | 2 +- configure.ac | 87 +++++++++++++++++++++++++--- error.h | 161 ++++----------------------------------------------- net.c | 2 +- 5 files changed, 92 insertions(+), 162 deletions(-) diff --git a/Makefile.in b/Makefile.in index 05008fbb..c572100b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -46,7 +46,7 @@ CPPFLAGS += -Wmissing-format-attribute CPPFLAGS += -Wunused-macros CPPFLAGS += -Wshadow CPPFLAGS += -Wbad-function-cast - +CPPFLAGS += -DMAIN_INPUT_FILE_IS_$(*F) CPPFLAGS += @SSL_CPPFLAGS@ CPPFLAGS += @ncurses_cppflags@ diff --git a/afs.c b/afs.c index a3b8d883..e13e257b 100644 --- a/afs.c +++ b/afs.c @@ -622,7 +622,7 @@ static void signal_post_select(struct sched *s, struct task *t) return; } PARA_NOTICE_LOG("caught signal %d\n", st->signum); - t->ret = -E_SIGNAL_CAUGHT; + t->ret = -E_AFS_SIGNAL; unregister_tasks(); } diff --git a/configure.ac b/configure.ac index bc08e740..0ad2106b 100644 --- a/configure.ac +++ b/configure.ac @@ -71,6 +71,15 @@ AC_CHECK_FUNCS([atexit dup2 memchr memmove memset \ strncasecmp strrchr strspn alarm], [], [AC_MSG_ERROR([function not found, cannot live without it])]) +all_errlist_objs="server mp3_afh vss command net string signal random_selector time +daemon stat crypt http_send afs_common close_on_fork playlist_selector ipc dccp +dccp_send fd user_list chunk_queue afs osl aft mood score attribute blob ringbuffer +playlist sha1 rbtree sched audiod grab_client filter_chain wav compress +http_recv dccp_recv recv_common write_common file_write audiod_command +client_common recv stdout filter stdin audioc write client fsck exec" +all_executables="server audiod recv filter audioc write client fsck" + + recv_cmdline_objs="recv.cmdline http_recv.cmdline dccp_recv.cmdline" recv_errlist_objs="http_recv recv_common recv time string net dccp_recv dccp fd sched stdout" @@ -121,6 +130,10 @@ client_ldflags="" fsck_cmdline_objs="fsck.cmdline" fsck_errlist_objs="osl rbtree fsck string sha1 fd" +gui_cmdline_objs="gui.cmdline" +gui_errlist_objs="exec close_on_fork signal string stat ringbuffer fd" +gui_other_objs="gui gui_common gui_theme" +gui_objs="$gui_cmdline_objs $gui_errlist_objs $gui_other_objs" ########################################################################### ssl dnl @synopsis CHECK_SSL @@ -225,6 +238,7 @@ if test "$have_ncurses" = "yes"; then AC_SUBST(ncurses_libs) AC_DEFINE(HAVE_NCURSES, 1, [define to 1 to turn on ncurses support]) extras="$extras para_gui" + all_executables="$all_executables gui" else AC_MSG_WARN([cannot build para_gui]) fi @@ -246,6 +260,8 @@ if test ${have_core_audio} = yes; then f3="-framework AudioUnit" f4="-framework CoreServices" f="$f1 $f2 $f3 $f4" + + all_errlist_objs="$all_errlist_objs osx_write" audiod_errlist_objs="$audiod_errlist_objs osx_write" audiod_cmdline_objs="$audiod_cmdline_objs osx_write.cmdline" audiod_ldflags="$audiod_ldflags $f" @@ -313,6 +329,7 @@ if test "$have_mysql" = "yes"; then selectors="$selectors mysql" server_ldflags="$server_ldflags $mysql_libs -lmysqlclient" server_errlist_objs="$server_errlist_objs mysql_selector" + all_errlist_objs="$all_errlist_objs mysql_selector" server_cmdline_objs="$server_cmdline_objs mysql_selector_command_list" AC_SUBST(mysql_cppflags) AC_SUBST(mysql_libs) @@ -345,6 +362,7 @@ AC_CHECK_LIB([ogg], [ogg_stream_init], [], [ have_ogg="no" ]) AC_CHECK_LIB([vorbis], [vorbis_info_init], [], [ have_ogg="no" ]) AC_CHECK_HEADERS([ogg/ogg.h vorbis/codec.h], [], [ have_ogg="no" ]) if test "$have_ogg" = "yes"; then + all_errlist_objs="$all_errlist_objs oggdec ogg_afh" AC_DEFINE(HAVE_OGGVORBIS, 1, define to 1 to turn on ogg vorbis support) filters="$filters oggdec" if test "$OSTYPE" = "Darwin"; then @@ -393,6 +411,7 @@ AC_CHECK_HEADER(neaacdec.h, [], have_faad=no) AC_CHECK_LIB([faad], [NeAACDecOpen], [], have_faad=no) if test "$have_faad" = "yes"; then AC_DEFINE(HAVE_FAAD, 1, define to 1 if you want to build the aacdec filter) + all_errlist_objs="$all_errlist_objs aac_common aacdec aac_afh" filter_errlist_objs="$filter_errlist_objs aacdec aac_common" filter_filters="$filter_filters aacdec" audiod_errlist_objs="$audiod_errlist_objs aacdec aac_common" @@ -437,6 +456,7 @@ AC_CHECK_LIB([mad], [mad_stream_init], [], [ ]) if test "$have_mad" = "yes"; then AC_DEFINE(HAVE_MAD, 1, define to 1 if you want to build the mp3dec filter) + all_errlist_objs="$all_errlist_objs mp3dec" filter_errlist_objs="$filter_errlist_objs mp3dec" audiod_errlist_objs="$audiod_errlist_objs mp3dec" filter_ldflags="$filter_ldflags $mad_libs -lmad" @@ -471,6 +491,7 @@ AC_CHECK_LIB([asound], [snd_pcm_open], [], [ have_alsa="no" ]) if test "$have_alsa" = "yes"; then + all_errlist_objs="$all_errlist_objs alsa_write" audiod_errlist_objs="$audiod_errlist_objs alsa_write" audiod_cmdline_objs="$audiod_cmdline_objs alsa_write.cmdline" audiod_ldflags="$audiod_ldflags -lasound" @@ -504,6 +525,8 @@ fi AC_CHECK_HEADERS([ortp/ortp.h], [], [have_ortp="no"]) AC_CHECK_LIB([ortp], [ortp_init], [], [have_ortp="no"]) if test "$have_ortp" = "yes"; then + all_errlist_objs="$all_errlist_objs ortp_recv ortp_send" + recv_cmdline_objs="$recv_cmdline_objs ortp_recv.cmdline" recv_errlist_objs="$recv_errlist_objs ortp_recv" @@ -562,6 +585,58 @@ AC_CONFIG_FILES([Makefile]) AC_DEFUN([add_dot_o],[$(for i in $@; do printf "$i.o "; done)]) AC_DEFUN([objlist_to_errlist],[$(for i in $@; do printf "DEFINE_ERRLIST($(echo $i| tr 'a-z' 'A-Z'));"; done) [const char **para_errlist[[]]] = {$(for i in $@; do printf "PARA_ERRLIST($(echo $i | tr 'a-z' 'A-Z')), "; done) }]) +AC_DEFUN([define_safe_error_enums], +[ + exe="" + for i in $all_executables; do +# eval echo checking if $1 is linked into $i + for j in $(eval echo \$${i}_errlist_objs); do + if test $j = $1; then + exe="$exe $i" + break; + fi + done + done + #echo "$1 gets linked into $exe" + safe_errlists="" + for i in $all_errlist_objs; do + for j in $exe; do + found=0 + for k in $(eval echo \$${j}_errlist_objs); do + if test $k = $i; then + found=1 + break; + fi + done + if test $found -eq 0; then + break; + fi + done + if test $found -eq 1; then + safe_errlists="$safe_errlists $i" + fi + done + #echo "safe errlists for $1: $safe_errlists" + ss_defs="" + for i in $safe_errlists; do + echo "SS_ENUM($(echo $i | tr 'a-z' 'A-Z'));" + done +] +) + +AC_MSG_NOTICE(creating error2.h) +for obj in $all_errlist_objs; do + SS="$SS SS_$(echo $obj | tr 'a-z' 'A-Z')," + echo "#ifdef MAIN_INPUT_FILE_IS_$obj" + define_safe_error_enums($obj) + echo "#endif" +done > error2.h +AC_DEFINE_UNQUOTED(DEFINE_ERRLIST_OBJECT_ENUM, + [enum {$SS NUM_SS}], + [list of all objects that use paraslash's error facility] +) + + recv_objs="$recv_cmdline_objs $recv_errlist_objs" filter_objs="$filter_cmdline_objs $filter_errlist_objs" audiod_objs="$audiod_cmdline_objs $audiod_errlist_objs" @@ -611,6 +686,10 @@ AC_SUBST(audioc_ldflags, $audioc_ldflags) AC_DEFINE_UNQUOTED(INIT_AUDIOC_ERRLISTS, objlist_to_errlist($audioc_errlist_objs), errors used by para_audioc) +AC_SUBST(gui_objs, add_dot_o($gui_objs)) +AC_DEFINE_UNQUOTED(INIT_GUI_ERRLISTS, + objlist_to_errlist($gui_errlist_objs), errors used by para_gui) + enum="$(for i in $writers; do printf "${i}_WRITE, " | tr '[a-z]' '[A-Z]'; done)" AC_DEFINE_UNQUOTED(WRITER_ENUM, $enum NUM_SUPPORTED_WRITERS, enum of supported writers) @@ -627,14 +706,6 @@ AC_DEFINE_UNQUOTED(AUDIOD_AUDIO_FORMATS_ENUM, $enum NUM_AUDIO_FORMATS, names="$(for i in $audiod_audio_formats; do printf \"$i\",' ' ; done)" AC_DEFINE_UNQUOTED(AUDIOD_AUDIO_FORMAT_ARRAY, $names, array of audio formats supported by audiod) -gui_cmdline_objs="gui.cmdline" -gui_errlist_objs="exec close_on_fork signal string stat ringbuffer fd" -gui_other_objs="gui gui_common gui_theme" -gui_objs="$gui_cmdline_objs $gui_errlist_objs $gui_other_objs" -AC_DEFINE_UNQUOTED(INIT_GUI_ERRLISTS, - objlist_to_errlist($gui_errlist_objs), errors used by para_gui) -AC_SUBST(gui_objs, add_dot_o($gui_objs)) - AC_OUTPUT AC_MSG_NOTICE([creating Makefile.deps]) gcc -MM -MG $mysql_cppflags $faad_cppflags $mad_cppflags $ortp_cppflags $oggvorbis_cppflags *.c > Makefile.deps diff --git a/error.h b/error.h index e8920d29..c164700d 100644 --- a/error.h +++ b/error.h @@ -6,77 +6,10 @@ /** \file error.h list of error messages for all subsystems */ -/** \cond list of all subsystems that support the shiny error facility */ -enum para_subsystem { - SS_CLIENT, - SS_GUI, - SS_TIME, - SS_WAV, - SS_COMPRESS, - SS_CLOSE_ON_FORK, - SS_DAEMON, - SS_DCCP_SEND, - SS_RINGBUFFER, - SS_RECV, - SS_NET, - SS_ORTP_RECV, - SS_CLIENT_COMMON, - SS_AUDIOC, - SS_SCHED, - SS_AUDIOD, - SS_AUDIOD_COMMAND, - SS_EXEC, - SS_STDIN, - SS_STDOUT, - SS_SIGNAL, - SS_STRING, - SS_STAT, - SS_GRAB_CLIENT, - SS_HTTP_RECV, - SS_RECV_COMMON, - SS_FILTER_CHAIN, - SS_OGGDEC, - SS_FILTER, - SS_COMMAND, - SS_RANDOM_SELECTOR, - SS_PLAYLIST_SELECTOR, - SS_CRYPT, - SS_HTTP_SEND, - SS_ORTP_SEND, - SS_AFS_COMMON, - SS_OGG_AFH, - SS_MP3_AFH, - SS_AAC_AFH, - SS_MP3DEC, - SS_AACDEC, - SS_AAC_COMMON, - SS_SERVER, - SS_VSS, - SS_MYSQL_SELECTOR, - SS_IPC, - SS_DCCP, - SS_DCCP_RECV, - SS_FD, - SS_WRITE, - SS_WRITE_COMMON, - SS_ALSA_WRITE, - SS_FILE_WRITE, - SS_OSX_WRITE, - SS_USER_LIST, - SS_CHUNK_QUEUE, - SS_AFS, - SS_OSL, - SS_AFT, - SS_MOOD, - SS_SCORE, - SS_ATTRIBUTE, - SS_BLOB, - SS_PLAYLIST, - SS_SHA1, - SS_RBTREE, - SS_FSCK, - NUM_SS -}; +/** \cond */ + +/* list of all subsystems that use paraslash's error facility */ +DEFINE_ERRLIST_OBJECT_ENUM; /* these do not need error handling (yet) */ #define SERVER_ERRORS @@ -91,9 +24,9 @@ enum para_subsystem { #define RINGBUFFER_ERRORS #define SCORE_ERRORS #define SHA1_ERRORS +#define RECV_ERRORS extern const char **para_errlist[]; -/** \endcond */ #define FSCK_ERRORS \ PARA_ERROR(FSCK_SYNTAX, "fsck syntax error"), \ @@ -121,7 +54,6 @@ extern const char **para_errlist[]; PARA_ERROR(BAD_SIZE, "invalid size specified"), \ PARA_ERROR(TRUNC, "failed to truncate file"), \ PARA_ERROR(UNLINK, "failed to remove file"), \ - PARA_ERROR(NOTDIR, "error: not a directory"), \ PARA_ERROR(BAD_TABLE, "table not open"), \ PARA_ERROR(BAD_TABLE_DESC, "invalid table description"), \ PARA_ERROR(RB_KEY_EXISTS, "key already exists in rbtree"), \ @@ -154,6 +86,7 @@ extern const char **para_errlist[]; PARA_ERROR(INPUT_TOO_LARGE, "input too large for stdin command"), \ PARA_ERROR(READ, "read error"), \ PARA_ERROR(AFS_SYNTAX, "afs syntax error"), \ + PARA_ERROR(AFS_SIGNAL, "afs caught deadly signal"), \ #define MOOD_ERRORS \ @@ -276,12 +209,8 @@ extern const char **para_errlist[]; PARA_ERROR(HTTP_RECV_EOF, "http_recv: end of file"), \ PARA_ERROR(HTTP_RECV_OVERRUN, "http_recv: outout buffer overrun"), \ - -#define RECV_ERRORS \ - PARA_ERROR(RECV_SYNTAX, "recv syntax error"), \ - - #define RECV_COMMON_ERRORS \ + PARA_ERROR(RECV_SYNTAX, "recv syntax error"), \ #define AUDIOD_ERRORS \ @@ -486,6 +415,7 @@ extern const char **para_errlist[]; #define FD_ERRORS \ + PARA_ERROR(NOTDIR, "error: not a directory"), \ PARA_ERROR(F_GETFL, "failed to get fd flags"), \ PARA_ERROR(F_SETFL, "failed to set fd flags"), \ PARA_ERROR(FGETS, "fgets error"), \ @@ -552,6 +482,7 @@ extern const char **para_errlist[]; #define CHUNK_QUEUE_ERRORS \ PARA_ERROR(QUEUE, "packet queue overrun"), \ +/** \endcond */ /** * the subsystem shift @@ -622,79 +553,7 @@ extern const char **para_errlist[]; * 'E_') and gets later redefined to expand to the error text only */ #define PARA_ERROR(err, msg) E_ ## err - -// #define SS_NAME(ss) para_errlist[ss]? para_errlist[ss][0] : "" - -/** \cond popcorn time */ -SS_ENUM(GUI); -SS_ENUM(SCHED); -SS_ENUM(STDIN); -SS_ENUM(STDOUT); -SS_ENUM(WAV); -SS_ENUM(COMPRESS); -SS_ENUM(TIME); -SS_ENUM(CLOSE_ON_FORK); -SS_ENUM(ORTP_RECV); -SS_ENUM(NET); -SS_ENUM(RECV); -SS_ENUM(AUDIOD); -SS_ENUM(AUDIOD_COMMAND); -SS_ENUM(EXEC); -SS_ENUM(SIGNAL); -SS_ENUM(STRING); -SS_ENUM(DAEMON); -SS_ENUM(STAT); -SS_ENUM(GRAB_CLIENT); -SS_ENUM(HTTP_RECV); -SS_ENUM(RECV_COMMON); -SS_ENUM(FILTER_CHAIN); -SS_ENUM(OGGDEC); -SS_ENUM(MP3DEC); -SS_ENUM(AACDEC); -SS_ENUM(FILTER); -SS_ENUM(MP3_AFH); -SS_ENUM(OGG_AFH); -SS_ENUM(AAC_AFH); -SS_ENUM(AAC_COMMON); -SS_ENUM(SERVER); -SS_ENUM(VSS); -SS_ENUM(COMMAND); -SS_ENUM(RANDOM_SELECTOR); -SS_ENUM(PLAYLIST_SELECTOR); -SS_ENUM(CRYPT); -SS_ENUM(HTTP_SEND); -SS_ENUM(ORTP_SEND); -SS_ENUM(AFS_COMMON); -SS_ENUM(MYSQL_SELECTOR); -SS_ENUM(IPC); -SS_ENUM(DCCP); -SS_ENUM(DCCP_RECV); -SS_ENUM(DCCP_SEND); -SS_ENUM(FD); -SS_ENUM(WRITE); -SS_ENUM(WRITE_COMMON); -SS_ENUM(ALSA_WRITE); -SS_ENUM(FILE_WRITE); -SS_ENUM(OSX_WRITE); -SS_ENUM(RINGBUFFER); -SS_ENUM(CLIENT); -SS_ENUM(CLIENT_COMMON); -SS_ENUM(AUDIOC); -SS_ENUM(USER_LIST); -SS_ENUM(CHUNK_QUEUE); - -SS_ENUM(AFS); -SS_ENUM(OSL); -SS_ENUM(AFT); -SS_ENUM(MOOD); -SS_ENUM(SCORE); -SS_ENUM(ATTRIBUTE); -SS_ENUM(BLOB); -SS_ENUM(PLAYLIST); -SS_ENUM(SHA1); -SS_ENUM(RBTREE); -SS_ENUM(FSCK); -/** \endcond */ +#include "error2.h" #undef PARA_ERROR /* rest of the world only sees the error text */ #define PARA_ERROR(err, msg) msg diff --git a/net.c b/net.c index 9a935539..046cf0b7 100644 --- a/net.c +++ b/net.c @@ -6,8 +6,8 @@ /** \file net.c networking-related helper functions */ -#include "error.h" #include "para.h" +#include "error.h" #include "net.h" #include "string.h" -- 2.39.2