Suppressions

Suppressions are a feature in EDoc++ which allow the user to modify the data used by EDoc++ at various stages of processing. Primarily it is used to suppress errors/warnings and to restrict/add possible function calls due to a call to a function pointer or virtual function. However suppressions can also be used to perform almost any kind of manipulation of the EDoc++ data.

Suppressions are implemented using a python script. The user provides this python suppressions file that will add/remove or mark data in particular ways to achieve what the user requires. The suppression files should be given the file extension ".eds" for EDoc Suppression since although they are python scripts, they can not be run outside the EDoc++ program. EDoc++ will fail to recognise files with the incorrect extension.

Default suppressions

EDoc++ includes some default suppressions for commonly used code. In particular the code in the GCC crtbegin and crtend objects along with code for libc and a few others. This code is generally support code and it is not the users intention to generate documentation for this code or to have to sift through warnings/errors that occur while processing this code. As such edoc will include default suppressions to omit this information.

To demonstrate lets look at the simple example from Simple Format We will compare the example listing from that section to one run without default suppressions. So if you run the following command:

edoc --disable-auto-import --disable-default-suppressions --show-all --format simple simple.edc
U: _IO_getc(_IO_FILE*)

U: _IO_putc(int, _IO_FILE*)

U: _Jv_RegisterClasses(void*)

F: Function1()
O: 	Exception
O: 	FileException
O: 	int

F: Function2()
O: 	FileException
E: 	Exception  -  Function1()
E: 	FileException  -  Function1()
E: 	int  -  Function1()

F: Function3()
O: 	float
P: 	Exception  -  Function1()
P: 	FileException  -  Function1()
P: 	int  -  Function1()
E: 	FileException  -  Function2()
E: 	FileException  -  Function2()
E: 	Exception  -  Function2()
E: 	int  -  Function2()

U: __builtin_constant_p(...)

U: __builtin_expect(long int, long int)

U: __cxa_begin_catch(void*)

U: __cxa_end_catch()

F: __do_global_ctors_aux()
P: 	Exception  -  Function1()
P: 	FileException  -  Function1()
P: 	int  -  Function1()

F: __do_global_dtors_aux()
P: 	Exception  -  Function1()
P: 	FileException  -  Function1()
P: 	int  -  Function1()

U: __getdelim(char**, size_t*, int, FILE*)

U: __overflow(_IO_FILE*, int)

U: __rawmemchr(void*, int)

F: __strcspn_c1(char*, int)

F: __strcspn_c1(char*, int)

F: __strcspn_c2(char*, int, int)

F: __strcspn_c2(char*, int, int)

F: __strcspn_c3(char*, int, int, int)

F: __strcspn_c3(char*, int, int, int)

F: __strpbrk_c2(char*, int, int)

F: __strpbrk_c2(char*, int, int)

F: __strpbrk_c3(char*, int, int, int)

F: __strpbrk_c3(char*, int, int, int)

F: __strsep_1c(char**, char)

F: __strsep_1c(char**, char)

F: __strsep_2c(char**, char, char)

F: __strsep_2c(char**, char, char)

F: __strsep_3c(char**, char, char, char)

F: __strsep_3c(char**, char, char, char)

F: __strspn_c1(char*, int)

F: __strspn_c1(char*, int)

F: __strspn_c2(char*, int, int)

F: __strspn_c2(char*, int, int)

F: __strspn_c3(char*, int, int, int)

F: __strspn_c3(char*, int, int, int)

F: __strtok_r_1c(char*, char, char**)

F: __strtok_r_1c(char*, char, char**)

U: __uflow(_IO_FILE*)

F: atof(char*)

F: atof(char*)

F: atoi(char*)

F: atoi(char*)

F: atol(char*)

F: atol(char*)

F: atoll(char*)

F: atoll(char*)

F: feof_unlocked(FILE*)

F: feof_unlocked(FILE*)

F: ferror_unlocked(FILE*)

F: ferror_unlocked(FILE*)

F: fgetc_unlocked(FILE*)

F: fgetc_unlocked(FILE*)

F: fputc_unlocked(int, FILE*)

F: fputc_unlocked(int, FILE*)

F: frame_dummy()
P: 	Exception  -  Function1()
P: 	FileException  -  Function1()
P: 	int  -  Function1()

F: get_cie(dwarf_fde*)

F: get_cie(dwarf_fde*)

F: getc_unlocked(FILE*)

F: getc_unlocked(FILE*)

F: getchar()

F: getchar()

F: getchar_unlocked()

F: getchar_unlocked()

F: getline(char**, size_t*, FILE*)

F: getline(char**, size_t*, FILE*)

F: gnu_dev_major(long long unsigned int)

F: gnu_dev_major(long long unsigned int)

F: gnu_dev_makedev(unsigned int, unsigned int)

F: gnu_dev_makedev(unsigned int, unsigned int)

F: gnu_dev_minor(long long unsigned int)

F: gnu_dev_minor(long long unsigned int)

F: last_fde(object*, fde*)

F: last_fde(object*, fde*)

F: main()

F: next_fde(fde*)

F: next_fde(fde*)

F: putc_unlocked(int, FILE*)

F: putc_unlocked(int, FILE*)

F: putchar(int)

F: putchar(int)

F: putchar_unlocked(int)

F: putchar_unlocked(int)

U: __builtin_strchr(char*, int)

U: strtod(char*, char**)

U: strtol(char*, char**, int)

U: strtoll(char*, char**, int)

U: vfprintf(FILE*, char*, char*)

F: vprintf(char*, char*)

F: vprintf(char*, char*)

WARNING(WUNIMPL): Function used but no implementation found : _Jv_RegisterClasses(void*)
WARNING(WUNIMPL): Function used but no implementation found : __cxa_begin_catch(void*)
WARNING(WUNIMPL): Function used but no implementation found : __cxa_end_catch()
ERROR(EUSUPP_EXC): An exception may propogate through a function that was compiled with the -fno-exceptions flag. :The function: __do_global_ctors_aux(), can throw exception of type: Exception
ERROR(EUSUPP_EXC): An exception may propogate through a function that was compiled with the -fno-exceptions flag. :The function: __do_global_ctors_aux(), can throw exception of type: FileException
ERROR(EUSUPP_EXC): An exception may propogate through a function that was compiled with the -fno-exceptions flag. :The function: __do_global_ctors_aux(), can throw exception of type: int
ERROR(EUSUPP_EXC): An exception may propogate through a function that was compiled with the -fno-exceptions flag. :The function: __do_global_dtors_aux(), can throw exception of type: Exception
ERROR(EUSUPP_EXC): An exception may propogate through a function that was compiled with the -fno-exceptions flag. :The function: __do_global_dtors_aux(), can throw exception of type: FileException
ERROR(EUSUPP_EXC): An exception may propogate through a function that was compiled with the -fno-exceptions flag. :The function: __do_global_dtors_aux(), can throw exception of type: int
ERROR(EUSUPP_EXC): An exception may propogate through a function that was compiled with the -fno-exceptions flag. :The function: frame_dummy(), can throw exception of type: Exception
ERROR(EUSUPP_EXC): An exception may propogate through a function that was compiled with the -fno-exceptions flag. :The function: frame_dummy(), can throw exception of type: FileException
ERROR(EUSUPP_EXC): An exception may propogate through a function that was compiled with the -fno-exceptions flag. :The function: frame_dummy(), can throw exception of type: int

You will notice from the above that not only is the code that the user requested in the output but so is a whole lot of other code for standard functions etc. There are also a number of errors/warnings that are normally suppressed. Usually the user does not care about these. To be pedantic and produce the safest possible code, it may be desired to disable default suppressions and look at ALL errors/warnings that edoc emits, however this will not be a common usage.

General Usage

The edoc application is passed suppression files on the command line as foo.eds files. By default it will also import suppression files for additional data if the given additional data provides a suppression file. For example if libstdc++.so is used as additional data, then edoc will search for a suppressions file called libstdc++.so.eds and if it exists it will use it, unless the user runs edoc with the option: --disable-auto-suppressions

See the later sections for information about what is contained in the suppression files.

Quick Start Guides

In the following few sections we provide examples of using suppressions in common situations.

Suppressing WUNIMPL messages

When it is decided that including the EDoc++ data for a library is not a good idea or the data is not available, the next best thing is to suppress the warnings/errors that may occur as a result of that data being missing. There are a number of ways that this can be achieved, however the best is to find a way of identifying all data that belongs to that library. Some it may be by a prefix for all items in the library because they are in a namespace, others it may be due to the fact that all data is identified as coming from a common directory.

To identify what data might be common, the easiest way is to get EDoc++ to generate a list of Error/Warning suppressions. This can be done by creating a suppressions file like below and running the edoc application as shown for the application: (Note: We are using the library_user application for an example but we are not including the additional library data for the moment).

# -- file: gen_supp.eds --
import eh
import sys

def DisplayNotification(event):
   print >>sys.stderr, "if event." + event.GenMatch() + ": return False"
   return True

Run the edoc application using this suppressions file. We will disable the use of standard suppressions here for demonstration purposes.

edoc --check --without-def-supp library_user ../lib/libmyshared.so.0 gen_supp.eds

This will produce an output that looks something like:

edoc --disable-auto-import --check --disable-default-suppressions library_user ../lib/libmyshared.so.0 gen_supp.eds
if event.Match(literal=True, event='WDIFF_THROW', function='memset', decl_function='memset(void*, int, size_t)', file='/usr/include/string.h', line='59', rfile='/usr/include/string.h', rline='59'): return False
Logs going to file: /tmp/edoc_tCV5xH
if event.Match(literal=True, event='WDIFF_THROW', function='strcmp', decl_function='strcmp(char const*, char const*)', file='/usr/include/string.h', line='100', rfile='<built-in>', rline='0'): return False
if event.Match(literal=True, event='WDIFF_THROW', function='strlen', decl_function='strlen(char const*)', file='/usr/include/string.h', line='243', rfile='/usr/include/string.h', rline='243'): return False
if event.Match(literal=True, event='WUNUSED_CATCH', function='_ZNKSt6locale5facet19_M_remove_referenceEv:7:/home/bcosta/build/edoc/dist/src/example-0.2.1/src/libs/myshared/myshared.cpp', decl_function='std::locale::facet::_M_remove_reference() const', file='/home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h', line='412', rline='0', type='...'): return False
if event.Match(literal=True, event='WUNUSED_CATCH', function='_ZNKSt6locale5facet19_M_remove_referenceEv:2:/home/bcosta/build/edoc/dist/src/example-0.2.1/src/apps/library_user/main.cpp', decl_function='std::locale::facet::_M_remove_reference() const', file='/home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h', line='412', rline='0', type='...'): return False
if event.Match(literal=True, event='WUNUSED_CATCH', function='_ZNKSt6locale5facet19_M_remove_referenceEv:3:/home/bcosta/build/edoc/dist/src/example-0.2.1/src/libs/mystatic/mystatic.cpp', decl_function='std::locale::facet::_M_remove_reference() const', file='/home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h', line='412', rline='0', type='...'): return False
if event.Match(literal=True, event='WUNUSED_CATCH', function='_ZNSt6locale5_Impl19_M_remove_referenceEv:7:/home/bcosta/build/edoc/dist/src/example-0.2.1/src/libs/myshared/myshared.cpp', decl_function='std::locale::_Impl::_M_remove_reference()', file='/home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h', line='517', rline='0', type='...'): return False
if event.Match(literal=True, event='WUNUSED_CATCH', function='_ZNSt6locale5_Impl19_M_remove_referenceEv:3:/home/bcosta/build/edoc/dist/src/example-0.2.1/src/libs/mystatic/mystatic.cpp', decl_function='std::locale::_Impl::_M_remove_reference()', file='/home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h', line='517', rline='0', type='...'): return False
if event.Match(literal=True, event='WUNUSED_CATCH', function='_ZNSt6locale5_Impl19_M_remove_referenceEv:2:/home/bcosta/build/edoc/dist/src/example-0.2.1/src/apps/library_user/main.cpp', decl_function='std::locale::_Impl::_M_remove_reference()', file='/home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h', line='517', rline='0', type='...'): return False
if event.Match(literal=True, event='WUNIMPL', function='_Jv_RegisterClasses', decl_function='_Jv_RegisterClasses(void*)', file='/home/bcosta/build/edoc/edoc/gcc-4.0.4/gcc/crtstuff.c', line='137', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='__cxa_finalize', decl_function='__cxa_finalize(void*)', file='/home/bcosta/build/edoc/edoc/gcc-4.0.4/gcc/crtstuff.c', line='235', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_', decl_function='std::endl<char,std::char_traits<char> >(std::basic_ostream<char,std::char_traits<char> >&)', file='/home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/ostream', line='517', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc', decl_function='std::operator <<<std::char_traits<char> >(std::basic_ostream<char,std::char_traits<char> >&, char const*)', file='/home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/ostream.tcc', line='616', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='memset', decl_function='memset(void*, int, size_t)', file='/usr/include/string.h', line='59', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='__assert_fail', decl_function='__assert_fail(char*, char*, unsigned int, char*)', file='/usr/include/assert.h', line='73', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='strlen', decl_function='strlen(char const*)', file='/usr/include/string.h', line='243', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='strcpy', decl_function='strcpy(char*, char*)', file='/usr/include/string.h', line='85', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='argz_create_sep', decl_function='argz_create_sep(char*, int, char**, size_t*)', file='/usr/include/argz.h', line='57', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='argz_insert', decl_function='argz_insert(char**, size_t*, char*, char*)', file='/usr/include/argz.h', line='127', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='argz_append', decl_function='argz_append(char**, size_t*, char*, size_t)', file='/usr/include/argz.h', line='85', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='argz_stringify', decl_function='argz_stringify(char*, size_t, int)', file='/usr/include/argz.h', line='75', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='strcmp', decl_function='strcmp(char const*, char const*)', file='/usr/include/string.h', line='100', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='strrchr', decl_function='__builtin_strrchr(char const*, int)', file='<built-in>', line='0', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='strncpy', decl_function='__builtin_strncpy(char*, char*, unsigned int)', file='<built-in>', line='0', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='__ctype_b_loc', decl_function='__ctype_b_loc()', file='/usr/include/ctype.h', line='82', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='__rawmemchr', decl_function='__rawmemchr(void*, int)', file='/usr/include/bits/string2.h', line='394', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='fopen', decl_function='fopen(char*, char*)', file='/usr/include/stdio.h', line='250', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='access', decl_function='access(char*, int)', file='/usr/include/unistd.h', line='258', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='opendir', decl_function='opendir(char*)', file='/usr/include/dirent.h', line='135', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='__builtin_constant_p', decl_function='__builtin_constant_p(...)', file='<built-in>', line='0', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='strchr', decl_function='__builtin_strchr(char*, int)', file='<built-in>', line='0', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='strcat', decl_function='strcat(char*, char*)', file='/usr/include/string.h', line='93', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='strncat', decl_function='__builtin_strncat(char*, char*, unsigned int)', file='<built-in>', line='0', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='readdir', decl_function='readdir(DIR*)', file='/usr/include/dirent.h', line='163', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='closedir', decl_function='closedir(DIR*)', file='/usr/include/dirent.h', line='150', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='pthread_cancel', decl_function='pthread_cancel(pthread_t)', file='/usr/include/pthread.h', line='485', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='getenv', decl_function='getenv(char*)', file='/usr/include/stdlib.h', line='545', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='fclose', decl_function='fclose(FILE*)', file='/usr/include/stdio.h', line='214', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='fgets', decl_function='fgets(char*, int, FILE*)', file='/usr/include/stdio.h', line='601', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='feof', decl_function='feof(FILE*)', file='/usr/include/stdio.h', line='797', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='strncmp', decl_function='strncmp(char*, char*, size_t)', file='/usr/include/string.h', line='103', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='sprintf', decl_function='sprintf(char*, char*, ...)', file='/usr/include/stdio.h', line='340', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='_ZN11PluginIFace8FunctionEv', decl_function='PluginIFace::Function()', file='/home/bcosta/build/edoc/dist/src/example-0.2.1/src/include/mystatic.h', line='64', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='__cxa_begin_catch', decl_function='__cxa_begin_catch(void*)', file='/home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h', line='412', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='__cxa_end_catch', decl_function='__cxa_end_catch()', file='/home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h', line='412', rline='0'): return False
WARNING(WDIFF_THROW): Function has differing throw specifiers. :Function: memset, Declared Name: memset(void*, int, size_t), Left Spec:  throws(), Right Spec: 
WARNING(WDIFF_THROW): Function has differing throw specifiers. :Function: strcmp, Declared Name: strcmp(char const*, char const*), Left Spec:  throws(), Right Spec: 
WARNING(WDIFF_THROW): Function has differing throw specifiers. :Function: strlen, Declared Name: strlen(char const*), Left Spec:  throws(), Right Spec: 
WARNING(WUNUSED_CATCH): Catch block never entered. :Catch block with type: ..., at location: /home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h:412 is unable to catch any exceptions thrown from try block.
WARNING(WUNUSED_CATCH): Catch block never entered. :Catch block with type: ..., at location: /home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h:412 is unable to catch any exceptions thrown from try block.
WARNING(WUNUSED_CATCH): Catch block never entered. :Catch block with type: ..., at location: /home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h:412 is unable to catch any exceptions thrown from try block.
WARNING(WUNUSED_CATCH): Catch block never entered. :Catch block with type: ..., at location: /home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h:517 is unable to catch any exceptions thrown from try block.
WARNING(WUNUSED_CATCH): Catch block never entered. :Catch block with type: ..., at location: /home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h:517 is unable to catch any exceptions thrown from try block.
WARNING(WUNUSED_CATCH): Catch block never entered. :Catch block with type: ..., at location: /home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h:517 is unable to catch any exceptions thrown from try block.
WARNING(WUNIMPL): Function used but no implementation found : _Jv_RegisterClasses(void*)
WARNING(WUNIMPL): Function used but no implementation found : __cxa_finalize(void*)
WARNING(WUNIMPL): Function used but no implementation found : std::endl<char,std::char_traits<char> >(std::basic_ostream<char,std::char_traits<char> >&)
WARNING(WUNIMPL): Function used but no implementation found : std::operator <<<std::char_traits<char> >(std::basic_ostream<char,std::char_traits<char> >&, char const*)
WARNING(WUNIMPL): Function used but no implementation found : memset(void*, int, size_t)
WARNING(WUNIMPL): Function used but no implementation found : __assert_fail(char*, char*, unsigned int, char*)
WARNING(WUNIMPL): Function used but no implementation found : strlen(char const*)
WARNING(WUNIMPL): Function used but no implementation found : strcpy(char*, char*)
WARNING(WUNIMPL): Function used but no implementation found : argz_create_sep(char*, int, char**, size_t*)
WARNING(WUNIMPL): Function used but no implementation found : argz_insert(char**, size_t*, char*, char*)
WARNING(WUNIMPL): Function used but no implementation found : argz_append(char**, size_t*, char*, size_t)
WARNING(WUNIMPL): Function used but no implementation found : argz_stringify(char*, size_t, int)
WARNING(WUNIMPL): Function used but no implementation found : strcmp(char const*, char const*)
WARNING(WUNIMPL): Function used but no implementation found : __builtin_strrchr(char const*, int)
WARNING(WUNIMPL): Function used but no implementation found : __builtin_strncpy(char*, char*, unsigned int)
WARNING(WUNIMPL): Function used but no implementation found : __ctype_b_loc()
WARNING(WUNIMPL): Function used but no implementation found : __rawmemchr(void*, int)
WARNING(WUNIMPL): Function used but no implementation found : fopen(char*, char*)
WARNING(WUNIMPL): Function used but no implementation found : access(char*, int)
WARNING(WUNIMPL): Function used but no implementation found : opendir(char*)
WARNING(WUNIMPL): Function used but no implementation found : __builtin_constant_p(...)
WARNING(WUNIMPL): Function used but no implementation found : __builtin_strchr(char*, int)
WARNING(WUNIMPL): Function used but no implementation found : strcat(char*, char*)
WARNING(WUNIMPL): Function used but no implementation found : __builtin_strncat(char*, char*, unsigned int)
WARNING(WUNIMPL): Function used but no implementation found : readdir(DIR*)
WARNING(WUNIMPL): Function used but no implementation found : closedir(DIR*)
WARNING(WUNIMPL): Function used but no implementation found : pthread_cancel(pthread_t)
WARNING(WUNIMPL): Function used but no implementation found : getenv(char*)
WARNING(WUNIMPL): Function used but no implementation found : fclose(FILE*)
WARNING(WUNIMPL): Function used but no implementation found : fgets(char*, int, FILE*)
WARNING(WUNIMPL): Function used but no implementation found : feof(FILE*)
WARNING(WUNIMPL): Function used but no implementation found : strncmp(char*, char*, size_t)
WARNING(WUNIMPL): Function used but no implementation found : sprintf(char*, char*, ...)
WARNING(WUNIMPL): Function used but no implementation found : PluginIFace::Function()
WARNING(WUNIMPL): Function used but no implementation found : __cxa_begin_catch(void*)
WARNING(WUNIMPL): Function used but no implementation found : __cxa_end_catch()

We are only looking at the WUNIMPL messages at the moment. There are a few things we can do:

  1. Use the suppressions as generated

    This will be the easiest option but is not very maintainable. Basically you would create a .eds suppressions file by copying into it all the code generated from that run of EDoc++. This can get VERY cumbersome for large projects and may slow down the execution of EDoc++ a little.

  2. Find a common pattern for the items we wish to suppress

    This requires looking at the generated suppression data and looking for a common pattern. In particular we see that for the functions generating WUNIMPL messages there are a few groupings:

    • builtins

      These are identified by the double underscore starting the function name like: __cxa_begin_catch

    • libc functions

      These can be identified in the above by the location of the header files that defined the function prototypes. In particular these functions are found in files residing in the directory structure: /usr/include/

    • libstdc++ functions

      These can be identified in the above by the location of the header files that defined the function prototypes. In particular these functions are found in files residing in the directory structure: /home/bcosta/build/install/edoc_gcc/lib

So lets generate a suppressions file for these un-implemented functions:

# lu_supp1.eds
import eh
import sys

def DisplayNotification(event):
   # Filter out all WUNIMPL messages for <builtin> functions.
   if event.Match(event='WUNIMPL', file='<built-in>'): return False

   # Some builtins will be missed by the above, so lets also filter
   # based on leadinf double underscore of function names.
   if event.Match(event='WUNIMPL', function='^__.*'): return False

   # Lets filter out all functions defined in headers installed under /usr/include
   if event.Match(event='WUNIMPL', file='^/usr/include/.*'): return False
   
   # Just for the sake of demonstration lets print out suppressions for all 
   # errors/warnings that escaped the filters.
   print >>sys.stderr, "if event." + event.GenMatch() + ": return False"

   return True

So lets re-run edoc with those suppressions:

edoc --disable-auto-import --check --disable-default-suppressions library_user ../lib/libmyshared.so.0 lu_supp1.eds
if event.Match(literal=True, event='WDIFF_THROW', function='memset', decl_function='memset(void*, int, size_t)', file='/usr/include/string.h', line='59', rfile='/usr/include/string.h', rline='59'): return False
Logs going to file: /tmp/edoc_iHwm0l
if event.Match(literal=True, event='WDIFF_THROW', function='strcmp', decl_function='strcmp(char const*, char const*)', file='/usr/include/string.h', line='100', rfile='<built-in>', rline='0'): return False
if event.Match(literal=True, event='WDIFF_THROW', function='strlen', decl_function='strlen(char const*)', file='/usr/include/string.h', line='243', rfile='/usr/include/string.h', rline='243'): return False
if event.Match(literal=True, event='WUNUSED_CATCH', function='_ZNKSt6locale5facet19_M_remove_referenceEv:7:/home/bcosta/build/edoc/dist/src/example-0.2.1/src/libs/myshared/myshared.cpp', decl_function='std::locale::facet::_M_remove_reference() const', file='/home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h', line='412', rline='0', type='...'): return False
if event.Match(literal=True, event='WUNUSED_CATCH', function='_ZNKSt6locale5facet19_M_remove_referenceEv:2:/home/bcosta/build/edoc/dist/src/example-0.2.1/src/apps/library_user/main.cpp', decl_function='std::locale::facet::_M_remove_reference() const', file='/home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h', line='412', rline='0', type='...'): return False
if event.Match(literal=True, event='WUNUSED_CATCH', function='_ZNKSt6locale5facet19_M_remove_referenceEv:3:/home/bcosta/build/edoc/dist/src/example-0.2.1/src/libs/mystatic/mystatic.cpp', decl_function='std::locale::facet::_M_remove_reference() const', file='/home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h', line='412', rline='0', type='...'): return False
if event.Match(literal=True, event='WUNUSED_CATCH', function='_ZNSt6locale5_Impl19_M_remove_referenceEv:7:/home/bcosta/build/edoc/dist/src/example-0.2.1/src/libs/myshared/myshared.cpp', decl_function='std::locale::_Impl::_M_remove_reference()', file='/home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h', line='517', rline='0', type='...'): return False
if event.Match(literal=True, event='WUNUSED_CATCH', function='_ZNSt6locale5_Impl19_M_remove_referenceEv:3:/home/bcosta/build/edoc/dist/src/example-0.2.1/src/libs/mystatic/mystatic.cpp', decl_function='std::locale::_Impl::_M_remove_reference()', file='/home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h', line='517', rline='0', type='...'): return False
if event.Match(literal=True, event='WUNUSED_CATCH', function='_ZNSt6locale5_Impl19_M_remove_referenceEv:2:/home/bcosta/build/edoc/dist/src/example-0.2.1/src/apps/library_user/main.cpp', decl_function='std::locale::_Impl::_M_remove_reference()', file='/home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h', line='517', rline='0', type='...'): return False
if event.Match(literal=True, event='WUNIMPL', function='_Jv_RegisterClasses', decl_function='_Jv_RegisterClasses(void*)', file='/home/bcosta/build/edoc/edoc/gcc-4.0.4/gcc/crtstuff.c', line='137', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_', decl_function='std::endl<char,std::char_traits<char> >(std::basic_ostream<char,std::char_traits<char> >&)', file='/home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/ostream', line='517', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc', decl_function='std::operator <<<std::char_traits<char> >(std::basic_ostream<char,std::char_traits<char> >&, char const*)', file='/home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/ostream.tcc', line='616', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='_ZN11PluginIFace8FunctionEv', decl_function='PluginIFace::Function()', file='/home/bcosta/build/edoc/dist/src/example-0.2.1/src/include/mystatic.h', line='64', rline='0'): return False
WARNING(WDIFF_THROW): Function has differing throw specifiers. :Function: memset, Declared Name: memset(void*, int, size_t), Left Spec:  throws(), Right Spec: 
WARNING(WDIFF_THROW): Function has differing throw specifiers. :Function: strcmp, Declared Name: strcmp(char const*, char const*), Left Spec:  throws(), Right Spec: 
WARNING(WDIFF_THROW): Function has differing throw specifiers. :Function: strlen, Declared Name: strlen(char const*), Left Spec:  throws(), Right Spec: 
WARNING(WUNUSED_CATCH): Catch block never entered. :Catch block with type: ..., at location: /home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h:412 is unable to catch any exceptions thrown from try block.
WARNING(WUNUSED_CATCH): Catch block never entered. :Catch block with type: ..., at location: /home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h:412 is unable to catch any exceptions thrown from try block.
WARNING(WUNUSED_CATCH): Catch block never entered. :Catch block with type: ..., at location: /home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h:412 is unable to catch any exceptions thrown from try block.
WARNING(WUNUSED_CATCH): Catch block never entered. :Catch block with type: ..., at location: /home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h:517 is unable to catch any exceptions thrown from try block.
WARNING(WUNUSED_CATCH): Catch block never entered. :Catch block with type: ..., at location: /home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h:517 is unable to catch any exceptions thrown from try block.
WARNING(WUNUSED_CATCH): Catch block never entered. :Catch block with type: ..., at location: /home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/locale_classes.h:517 is unable to catch any exceptions thrown from try block.
WARNING(WUNIMPL): Function used but no implementation found : _Jv_RegisterClasses(void*)
WARNING(WUNIMPL): Function used but no implementation found : std::endl<char,std::char_traits<char> >(std::basic_ostream<char,std::char_traits<char> >&)
WARNING(WUNIMPL): Function used but no implementation found : std::operator <<<std::char_traits<char> >(std::basic_ostream<char,std::char_traits<char> >&, char const*)
WARNING(WUNIMPL): Function used but no implementation found : PluginIFace::Function()

You can see that all but a few of the WUNIMPL messages have been suppressed. One thing to note is that one of the left-over WUNIMPL functions is for PluginIFace::Function() function. This would be provided by the plugin: myplugin, however we are not including that for the moment. The others are from libstdc++ and one (RegisterClasses) is part of the GCC standard libraries used for all apps.

Suppressing WUNUSED_CATCH warnings

In the above example we still have a number of other warnings, in particular the WUNUSED_CATCH warning. This warning is when a user provides a catch handler but it will never be executed. Generally this is NOT a bad thing and is often placed there as a security blanket in case someone changes the code and an exception might be thrown later etc. So quite often it is desirable to just suppress this warning unconditionally. So lets add a suppression for this warning to the suppression file:

# lu_supp2.eds
import eh
import sys

def DisplayNotification(event):

   # Filter out ALL WUNUSED_CATCH warnings as we really dont care about them
   if event.Match(event='WUNUSED_CATCH'): return False

   # Filter out all WUNIMPL messages for <builtin> functions.
   if event.Match(event='WUNIMPL', file='<built-in>'): return False

   # Some builtins will be missed by the above, so lets also filter
   # based on leadinf double underscore of function names.
   if event.Match(event='WUNIMPL', function='^__.*'): return False

   # Lets filter out all functions defined in headers installed under /usr/include
   if event.Match(event='WUNIMPL', file='^/usr/include/.*'): return False
   
   # Just for the sake of demonstration lets print out suppressions for all 
   # errors/warnings that escaped the filters.
   print >>sys.stderr, "if event." + event.GenMatch() + ": return False"

   return True

If you re-run the edoc application providing this suppressions file you will notice that no WUNUSED_CATCH warnings are shown:

edoc --disable-auto-import --check --disable-default-suppressions library_user ../lib/libmyshared.so.0 lu_supp2.eds
if event.Match(literal=True, event='WDIFF_THROW', function='memset', decl_function='memset(void*, int, size_t)', file='/usr/include/string.h', line='59', rfile='/usr/include/string.h', rline='59'): return False
Logs going to file: /tmp/edoc_4GNNxM
if event.Match(literal=True, event='WDIFF_THROW', function='strcmp', decl_function='strcmp(char const*, char const*)', file='/usr/include/string.h', line='100', rfile='<built-in>', rline='0'): return False
if event.Match(literal=True, event='WDIFF_THROW', function='strlen', decl_function='strlen(char const*)', file='/usr/include/string.h', line='243', rfile='/usr/include/string.h', rline='243'): return False
if event.Match(literal=True, event='WUNIMPL', function='_Jv_RegisterClasses', decl_function='_Jv_RegisterClasses(void*)', file='/home/bcosta/build/edoc/edoc/gcc-4.0.4/gcc/crtstuff.c', line='137', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_', decl_function='std::endl<char,std::char_traits<char> >(std::basic_ostream<char,std::char_traits<char> >&)', file='/home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/ostream', line='517', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc', decl_function='std::operator <<<std::char_traits<char> >(std::basic_ostream<char,std::char_traits<char> >&, char const*)', file='/home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/ostream.tcc', line='616', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='_ZN11PluginIFace8FunctionEv', decl_function='PluginIFace::Function()', file='/home/bcosta/build/edoc/dist/src/example-0.2.1/src/include/mystatic.h', line='64', rline='0'): return False
WARNING(WDIFF_THROW): Function has differing throw specifiers. :Function: memset, Declared Name: memset(void*, int, size_t), Left Spec:  throws(), Right Spec: 
WARNING(WDIFF_THROW): Function has differing throw specifiers. :Function: strcmp, Declared Name: strcmp(char const*, char const*), Left Spec:  throws(), Right Spec: 
WARNING(WDIFF_THROW): Function has differing throw specifiers. :Function: strlen, Declared Name: strlen(char const*), Left Spec:  throws(), Right Spec: 
WARNING(WUNIMPL): Function used but no implementation found : _Jv_RegisterClasses(void*)
WARNING(WUNIMPL): Function used but no implementation found : std::endl<char,std::char_traits<char> >(std::basic_ostream<char,std::char_traits<char> >&)
WARNING(WUNIMPL): Function used but no implementation found : std::operator <<<std::char_traits<char> >(std::basic_ostream<char,std::char_traits<char> >&, char const*)
WARNING(WUNIMPL): Function used but no implementation found : PluginIFace::Function()

Fixing WDIFF_THROW warnings

This warning is generated when two function definitions are found both with different throws() clauses. It is not very common and should not occur in your own code unless either you know what you are doing and i don't need to be explaining this to you, or you have most likely made a mistake somewhere in your code.

Unfortunately however, it seems to occur sometimes in system code, so they often need to be suppressed. Again a good way of doing this is based on the location of the header file that included it. So lets suppress all WDIFF_THROW warnings for functions declared in system header (/usr/include)

# lu_supp3.eds
import eh
import sys

def DisplayNotification(event):

   # Filter out ALL WUNUSED_CATCH warnings as we really dont care about them
   if event.Match(event='WUNUSED_CATCH'): return False

   # Filter out all WUNIMPL messages for <builtin> functions.
   if event.Match(event='WUNIMPL', file='<built-in>'): return False

   # Some builtins will be missed by the above, so lets also filter
   # based on leadinf double underscore of function names.
   if event.Match(event='WUNIMPL', function='^__.*'): return False

   # Lets filter out all functions defined in headers installed under /usr/include
   if event.Match(event='WUNIMPL', file='^/usr/include/.*'): return False

   # Lets filter out all WDIFF_THROW warnings for functions defined in 
   # headers installed under /usr/include
   if event.Match(event='WDIFF_THROW', file='^/usr/include/.*'): return False
   
   # Just for the sake of demonstration lets print out suppressions for all 
   # errors/warnings that escaped the filters.
   print >>sys.stderr, "if event." + event.GenMatch() + ": return False"

   return True

And again lets re-run the application:

edoc --disable-auto-import --check --disable-default-suppressions library_user ../lib/libmyshared.so.0 lu_supp3.eds
Logs going to file: /tmp/edoc_gjc9Al
if event.Match(literal=True, event='WUNIMPL', function='_Jv_RegisterClasses', decl_function='_Jv_RegisterClasses(void*)', file='/home/bcosta/build/edoc/edoc/gcc-4.0.4/gcc/crtstuff.c', line='137', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_', decl_function='std::endl<char,std::char_traits<char> >(std::basic_ostream<char,std::char_traits<char> >&)', file='/home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/ostream', line='517', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc', decl_function='std::operator <<<std::char_traits<char> >(std::basic_ostream<char,std::char_traits<char> >&, char const*)', file='/home/bcosta/build/edoc/install/edoc_patched/include/c++/4.0.4/bits/ostream.tcc', line='616', rline='0'): return False
if event.Match(literal=True, event='WUNIMPL', function='_ZN11PluginIFace8FunctionEv', decl_function='PluginIFace::Function()', file='/home/bcosta/build/edoc/dist/src/example-0.2.1/src/include/mystatic.h', line='64', rline='0'): return False
WARNING(WUNIMPL): Function used but no implementation found : _Jv_RegisterClasses(void*)
WARNING(WUNIMPL): Function used but no implementation found : std::endl<char,std::char_traits<char> >(std::basic_ostream<char,std::char_traits<char> >&)
WARNING(WUNIMPL): Function used but no implementation found : std::operator <<<std::char_traits<char> >(std::basic_ostream<char,std::char_traits<char> >&, char const*)
WARNING(WUNIMPL): Function used but no implementation found : PluginIFace::Function()

Now we have only relevant warnings/errors.

Suppressing exceptions derived from a type

Following on from the previous section, we will now look at the actual exceptions. So lets re-run the application generating the exception information in the "simple" format.

edoc --format simple --without-def-supp library_user ../lib/libmyshared.so.0 lu_supp3.eds

This will generate exception information like:

edoc --disable-auto-import --format simple --disable-default-suppressions library_user ../lib/libmyshared.so.0 lu_supp3.eds
F: GetLTError()
O: 	Exception

F: MyStatic()
O: 	BugException

F: SomeClass::Check()
O: 	BugException

F: SomeClass::Function()
O: 	BugException
O: 	ExampleException

Notice that the BugException is thrown in a lot of places. In some projects there are exceptions like this "BugException" where the whole point of the exception as in this case is to handle a failed assertion. This is one situation where the user really does not need to know that this exception may occur. So we will remove it from the output along with all exceptions derived from BugException.

In Java there is an equivalent concept called "Runtime Exceptions". Runtime exceptions do not need to be explicitly stated as being thrown by functions. This is mostly because they can occur almost anywhere and if they occur it is usually a big problem that should close the program. On the other hand it is also POSSIBLE but very unlikely that a user may wish to handle these types of exceptions.

Lets add a suppression for this to the previous suppressions file: lu_supp.eds

# lu_supp.eds
import eh
import sys

def DisplayNotification(event):

   # Filter out ALL WUNUSED_CATCH warnings as we really dont care about them
   if event.Match(event='WUNUSED_CATCH'): return False

   # Filter out all WUNIMPL messages for <builtin> functions.
   if event.Match(event='WUNIMPL', file='<built-in>'): return False

   # Some builtins will be missed by the above, so lets also filter
   # based on leadinf double underscore of function names.
   if event.Match(event='WUNIMPL', function='^__.*'): return False

   # Lets filter out all functions defined in headers installed under /usr/include
   if event.Match(event='WUNIMPL', file='^/usr/include/.*'): return False

   # Lets filter out all WDIFF_THROW warnings for functions defined in 
   # headers installed under /usr/include
   if event.Match(event='WDIFF_THROW', file='^/usr/include/.*'): return False
   
   # Just for the sake of demonstration lets print out suppressions for all 
   # errors/warnings that escaped the filters.
   print >>sys.stderr, "if event." + event.GenMatch() + ": return False"

   return True

def PreExpansion():
   # Suppress all exceptions of type BugException or its derivatives.
   eh.types.CaughtBy(eh.types.MatchesDeclared('BugException')).Suppress()

Now if you re-run the edoc application using this suppression file you will notice that no functions seem to throw the BugException. They have all been suppressed:

edoc --disable-auto-import --format simple --disable-default-suppressions library_user ../lib/libmyshared.so.0 lu_supp.eds
F: GetLTError()
O: 	Exception

F: SomeClass::Function()
O: 	ExampleException

Restricting call graph for possible function pointers

For this we will use the function_pointer application from the example project.

The small test program looks like:

typedef void(*FuncPtr)();

void Function1()
{
   throw 1;
}

void Function2()
{
   throw 2.0f;
}

void Function3()
{
   FuncPtr fp = &Function1;
   fp();
}

void Function4()
{
   FuncPtr fp = &Function2;
   fp();
}

int main()
{
   try
   {
      Function3();
      Function4();
   }
   catch(...)
   {
      return 1;
   }
   return 0;
}

In this program we have two function pointer calls. We also know that the call in Function3() will only ever call Function1() and likewise Function4() will only ever call Function2(). This is a simplified example in order to demonstrate. If we use EDoc++ on this small application we will get the following:

g++ -fedoc-embed main.cpp -o function_pointer
edoc --disable-auto-import --format simple function_pointer
F: Function1()
O: 	int

F: Function2()
O: 	float

F: Function3()
P: 	int  -  Function1()
P: 	float  -  Function2()

F: Function4()
P: 	int  -  Function1()
P: 	float  -  Function2()

You will notice that Functions 3 and 4 BOTH throw an int and a float type exception as possible exceptions. Where in reality we know that Function3() should only ever throw an exception of type int and Function4() of type float. This has occurred because when expanding the function pointers, EDoc++ takes the safe approach and creates a pessimistic call graph. In order to solve this problem we can introduce a suppressions file.

So lets create a suppressions file, look at the results and explain what it is doing. So create a suppressions file: fprest.eds

# fprest.eds
import eh

def PostExpansion():
   eh.functions.MatchesDeclared('Function3', mtype=eh.Contains).Flat().ErasePossCalls('Function2', mtype=eh.Contains)
   eh.functions.MatchesDeclared('Function4', mtype=eh.Contains).Flat().ErasePossCalls('Function1', mtype=eh.Contains)

g++ -fedoc-embed main.cpp -o function_pointer
edoc --disable-auto-import --format simple function_pointer fprest.eds
F: Function1()
O: 	int

F: Function2()
O: 	float

F: Function3()
P: 	int  -  Function1()

F: Function4()
P: 	float  -  Function2()

As you can see the additional function calls have been suppressed. So in the suppressions file we see two lines. These are both pretty much doing the same thing so I will go through the top line:

eh.functions.MatchesDeclared('Function3', mtype=eh.Contains)

This is matching a list of all functions whose Function::GetDeclaredName() contains the string Function3.

The result of the MatchesDeclared() is a FunctionMap class instance. This is a map of one or more functions that matched the search criteria. Then we call on that:

Flat()

The Flat() function will return a list of all CodeBlock instances that describe the implementation of the matching functions. This is called Flat() because it returns them in a "flat file" style where the hierarchy information about what CodeBlocks are inside what try/catch blocks is not preserved. We do this to simplify finding of certain bits of code inside a function regardless of how many try blocks it is inside.

So this returns an instance of the CodeBlockList class on which we call:

ErasePossCalls('Function2', mtype=Contains)

The ErasePossCalls function will go through all CodeBlock instances that are included in the list and look at their CodeBlock::possible_function_calls attributes erasing any references to functions whose names match the pattern, in this case 'Function2'. So simply what that says is to erase any references to functions whose names contain the string Function2.

Adding address taken for function obtained using lt_dlsym() or equivalent

@@@Brendon TODO Writeme.

Renaming a functions Declared Name

@@@Brendon TODO Writeme.

Helpers available

The suppressions framework is implemented by using python to manipulate the EDoc++ data. The functionality of libEDoc as used in the edoc application should be available to the python suppressions script through the use of a SWIG wrapper. This means that practically anything you could do in C++ using the libEDoc API can also be achieved in the suppression files using python. For this reason writing suppression files will often require the user to look at the libEDoc API documentation to know what attributes and function calls are available on what objects.

In addition to the raw API of libEDoc, there is also some native python helper code that can be used to simplify common operations performed by the suppressions file. This additional python code can be found in src/python/eh/__init__.py. There exists python API documentation for the helpers defined in that module at the following link:

http://edoc.sourceforge.net/EDocPyAPI/html/index.html

All EDoc::File, EDoc::Type, EDoc::FunctionType, EDoc::Function instances for the active dictionary can be found from within a suppressions file as variables in the eh module. For example:

# Import the base EDoc Helper module
import eh

# The current dictionary can be accessed in attribute: ed
print "Active Dictionary: " + str(eh.ed)

# The list of files can be accessed in attribute: files
print "Files: " + str(eh.files)

# The list of types can be accessed in attribute: types
print "Types: " + str(eh.types)

# The list of files can be accessed in attribute: function_types
print "FunctionTypes: " + str(eh.function_types)

# The list of functions can be accessed in attribute: functions
print "Functions: " + str(eh.functions)

These attributes of the eh module are special container objects. For example the eh.functions attribute is a special Map like container where the key is the EDoc::Function::GetKeyName() and the value is the Edoc::Function instance. These containers are special in that they are designed for performing common operations on a collection of objects. For example if you want to call the EDoc::Function::GetDeclaredName() function on every function in the attribute just do the following:

result = eh.functions.GetDeclaredName()

This will call GetDeclaredName() on every function and return the result of each call in a special list. This list is similar to the eh.functions list and can be used in the same way. So for example the following code:

eh.functions.function_pointer_type.Validate()

The above example will do the following:

  1. For each function instance get its function_pointer_type attribute

  2. For each function_pointer_type attribute will call Validate() on its instance

You should be able to see how this simplifies performing an operation on multiple objects.

Another VERY useful feature of these special containers is that they provide builtin functionality for searching for matches to a particular pattern. Currently the following match types are supported:

  • eh.Exact : Matches any items where the identifier exactly matches the match_str

  • eh.Contains : Matches any items where the identifier contains the match_str

  • eh.Regexp : Matches any items where the identifier matches the regular expression defined by match_str

The identifier is obtained using a small function or by using one of the "built-in" match types. For example the following are equivalent:

# Returns a list of functions whose declared name contains PatternToMatch
matches = eh.functions.MatchesDeclared("PatternToMatch", mtype=eh.Contains)

# Returns a list of functions whose declared name contains PatternToMatch
def ObtainDeclaredName(x) return x.GetDeclaredName()
matches = eh.functions.Matches(ObtainDeclaredName, "PatternToMatch", mtype=eh.Contains)

# Returns a list of functions whose declared name contains PatternToMatch
matches = eh.functions.Matches(lambda x: x.GetDeclaredName(), "PatternToMatch", mtype=eh.Contains)

All three above are identical. Looking at the second example the function: ObtainDeclaredName() is passed a EDoc::Function instance and returns a string with the functions declared name. The Matches() function will use this function for every function instance to obtain the "identifier" for the function instance that is to be compared to the match string (In this case "PatternToMatch"). This is very flexible as you can perform complex matches quite simply. For example:

matches = eh.functions.Matches(lambda x: x.loc.file.GetName(), ".*\.cpp$")

This above will match any functions which were declared in (I.e. The loc attribute of the function) a filename that ends in ".cpp".

With the above basic concepts on how to use these special containers, and the examples provided throughput this manual it should be possible to perform most operations you may wish to perform in suppression files. For further information refer to the documentation for the following two APIs:

Interactive Suppressions

When creating or debugging a suppression file, it may be helpful to be able to use the suppressions interactively. This can be helpful for trying different things and experimenting. In order to do this you can use a standard python module called code. An example suppressions file is shown below that will break into an interactive session at the start of the Pre Expansion stage.

import eh
import code

def PreExpansion():
   # Opens an interactive python shell that can be used for experimenting.
   code.interact(local=globals())

Suppression Functions

There are a few stages in processing in which suppressions can be applied. These stages correspond to the stages that the edoc application goes through while processing its data. Certain operations can only be performed in particular stages due to the amount of data that is available during that stage.

Following is a list of the various stages

  • Startup / Setting up Display Notifications

  • Pre Expansion

  • Post Expansion

  • Post Calculation

Each stage is implemented as a user provided function call of a specified name. If the user defines a python function of the correct name within a suppression file, then that function is called at the given stage in the processing. Following is a list of the function calls that may be defined for the various stages of compilation.

DisplayNotification(event)

This function must return a value of True or False indicating True if the notification event (Warning or Error) should be displayed to the user OR False if the Warning/Error should be suppressed.

This function may be called by the edoc application at any time during its processing. The function should NOT make use of the variables defined in the eh module like eh.functions. It should make use of the event object passed as the only parameter into the function in order to identify particular notification events that may be suppressed. See the python class: Notification in the libEDocPy API documentation for more information

PreExpansion()

This function is called after the edoc application has loaded all data from the EDoc++ data files but before it expands all function pointer or virtual function calls into a number of possible function calls.

This means that the user should NOT make any references to possible function call objects (See CodeBlock::possible_function_calls in the libEDoc API) or any information that is generated during the calculation of PropogatingExceptions (See below for more information on what that includes). A full list of data that should not be modified/used during this stage includes:

  • Function::derived_virtuals

  • CodeBlock::possible_function_calls

  • CodeBlock::AllFunctionCalls()

  • FunctionType::equivilant

  • FunctionType::addressed_functions

  • Function::propogating_exceptions

  • Function::filtered_exceptions

Primarily this call-back is used for adding/removing function pointer and virtual function calls manually to a functions implementation. For example if somewhere you have inline assembly that makes a call to a function pointer, then it will not have been picked up by the GCC Modification, so it would need to be added manually to the call graph. This is the place where that function pointer call would have to be automatically added to the call graph.

This call-back is also often used to "hide" certain exception types. For example this call-back is a good location in order to suppress all exceptions of a particular type by getting a reference to the type instance and setting its Type::visible flag to false. There are also helper functions that help with this. For more information see Suppressing exceptions derived from a type

PostExpansion()

This function is called just after the edoc application has expanded all function pointer and virtual function calls into a list of possible function calls.

The user can make use of all data available in the PreExpansion stage and additionally may also make use of the following data items:

  • Function::derived_virtuals

  • CodeBlock::possible_function_calls

  • CodeBlock::AllFunctionCalls()

  • FunctionType::equivilant

  • FunctionType::addressed_functions

Generally this stage is used to restrict the call graph that was expanded for function pointer and virtual function calls. For example a function pointer call expands into a possible function call to EVERY function whose address has been taken at one point in the program and whose function pointer type matches that of the function pointer being called.

Obviously this is very likely to include function calls that the user knows are not possibly going to be called. In this situation the user may choose to restrict the call graph by erasing the possible calls that resulted from an expansion of the function pointer that they know will not be used. The same also applies to the virtual function calls.

PostCalculation()

This function is called after the edoc application has calculated the list of all PropogatingExceptions but has not yet displayed the data to the user.

At this stage in the program execution the user has access to ALL data.

Suppressions applied at this stage are usually used for hiding particular propagating exceptions. This can be achieved by setting the PropogatingException::visible field to false for a particular propagating exceptions instance. Note however that this visibility will only be effective for the instance modified, not all instances in other functions that exist as a result of it too.

If the desire is to filter out a particular exception you can hide the originating exception using Exception::visible.

Generating suppressions

There exists some functionality at the moment to get the suppressions framework to automatically produce a set of suppressions for you. This functionality is still very basic. However you can automatically generate suppressions for all Errors/Warnings. Below is an example of a suppressions script that does not suppress any Errors/Warnings but will generate code to suppress all the Events/Warnings that are encountered. Its then a matter of going through the generated code and removing the suppressions that you don't want.

import eh
import sys

def DisplayNotification(event):
   print >>sys.stderr, "if event." + event.GenMatch() + ": return False"
   return True

Accessing other suppression modules

All suppression files are loaded by the python interpreter embedded within the edoc application as normal python modules. These modules are standard python modules in all but their names. It may be desirable for a user to access the modules for other suppression files that may be being used. In order to do this it is first necessary to obtain the python modules instance.

All suppression files loaded as modules are added to the python package eh.eds as sub-modules. So for example a suppression file called "mysupp.eds" will exist as a module that can be imported using:

import eh.eds.mysupp

The difficulty with this however is for files that do not follow standard python module naming conventions. For example libstdc++.so.eds which would be given the module name:

import eh.eds.libstdc___so

All non-alphanumeric characters in the suppression file name are replaced with an underscore '_'. In addition to this there also exists a function in the eh.eds module called: GetEDSModules(). This function will return a standard python map that maps suppression file name to module instance and can be used to otherwise locate a particular modules instance.