Only declare error codes that are safe to use.
authorAndre Noll <maan@systemlinux.org>
Sun, 7 Oct 2007 19:03:54 +0000 (21:03 +0200)
committerAndre Noll <maan@systemlinux.org>
Sun, 7 Oct 2007 19:03:54 +0000 (21:03 +0200)
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
afs.c
configure.ac
error.h
net.c

index 05008fb..c572100 100644 (file)
@@ -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 a3b8d88..e13e257 100644 (file)
--- 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();
 }
 
index bc08e74..0ad2106 100644 (file)
@@ -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 e8920d2..c164700 100644 (file)
--- 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 9a93553..046cf0b 100644 (file)
--- 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"