You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2282 lines
61 KiB

26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
Bug#34043: Server loops excessively in _checkchunk() when safemalloc is enabled Essentially, the problem is that safemalloc is excruciatingly slow as it checks all allocated blocks for overrun at each memory management primitive, yielding a almost exponential slowdown for the memory management functions (malloc, realloc, free). The overrun check basically consists of verifying some bytes of a block for certain magic keys, which catches some simple forms of overrun. Another minor problem is violation of aliasing rules and that its own internal list of blocks is prone to corruption. Another issue with safemalloc is rather the maintenance cost as the tool has a significant impact on the server code. Given the magnitude of memory debuggers available nowadays, especially those that are provided with the platform malloc implementation, maintenance of a in-house and largely obsolete memory debugger becomes a burden that is not worth the effort due to its slowness and lack of support for detecting more common forms of heap corruption. Since there are third-party tools that can provide the same functionality at a lower or comparable performance cost, the solution is to simply remove safemalloc. Third-party tools can provide the same functionality at a lower or comparable performance cost. The removal of safemalloc also allows a simplification of the malloc wrappers, removing quite a bit of kludge: redefinition of my_malloc, my_free and the removal of the unused second argument of my_free. Since free() always check whether the supplied pointer is null, redudant checks are also removed. Also, this patch adds unit testing for my_malloc and moves my_realloc implementation into the same file as the other memory allocation primitives.
16 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
Bug #46165 server crash in dbug This crash occured if the same debug trace file was closed twice, leading to the same memory being free'd twice. This could occur if the "debug" server system variable refered to the same trace file in both global and session scope. Example of an order of events that would lead to a crash: 1) Enable debug tracing to a trace file (global scope) 2) Enable debug tracing to the same trace file (session scope) 3) Reset debug settings (global scope) 4) Reset debug settings (session scope) This caused a crash because the trace file was, by mistake, closed in 3), leading to the same memory being free'd twice when the file was closed again in 4). Internally, the debug settings are stored in a stack, with session settings (if any) on top and the global settings below. Each connection has its own stack. When a set of settings is changed, it must be determined if its debug trace file is to be closed. Before, this was done by only checking below on the settings stack. So if the global settings were changed, an existing debug trace file reference in session settings would be missed. This caused the file to be closed even if it was in use, leading to a crash later when it was closed again. This patch fixes the problem by preventing the trace file from being shared between global and session settings. If session debug settings are set without specifying a new trace file, stderr is used for output. This is a change in behaviour and should be reflected in the documentation. Test case added to variables.test.
15 years ago
Bug #46165 server crash in dbug This crash occured if the same debug trace file was closed twice, leading to the same memory being free'd twice. This could occur if the "debug" server system variable refered to the same trace file in both global and session scope. Example of an order of events that would lead to a crash: 1) Enable debug tracing to a trace file (global scope) 2) Enable debug tracing to the same trace file (session scope) 3) Reset debug settings (global scope) 4) Reset debug settings (session scope) This caused a crash because the trace file was, by mistake, closed in 3), leading to the same memory being free'd twice when the file was closed again in 4). Internally, the debug settings are stored in a stack, with session settings (if any) on top and the global settings below. Each connection has its own stack. When a set of settings is changed, it must be determined if its debug trace file is to be closed. Before, this was done by only checking below on the settings stack. So if the global settings were changed, an existing debug trace file reference in session settings would be missed. This caused the file to be closed even if it was in use, leading to a crash later when it was closed again. This patch fixes the problem by preventing the trace file from being shared between global and session settings. If session debug settings are set without specifying a new trace file, stderr is used for output. This is a change in behaviour and should be reflected in the documentation. Test case added to variables.test.
15 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
WL#4828 and BUG#45747 NOTE: Backporting the patch to next-mr. WL#4828 Augment DBUG_ENTER/DBUG_EXIT to crash MySQL in different functions ------- The assessment of the replication code in the presence of faults is extremely import to increase reliability. In particular, one needs to know if servers will either correctly recovery or print out appropriate error messages thus avoiding unexpected problems in a production environment. In order to accomplish this, the current patch refactories the debug macros already provided in the source code and introduces three new macros that allows to inject faults, specifically crashes, while entering or exiting a function or method. For instance, to crash a server while returning from the init_slave function (see module sql/slave.cc), one needs to do what follows: 1 - Modify the source replacing DBUG_RETURN by DBUG_CRASH_RETURN; DBUG_CRASH_RETURN(0); 2 - Use the debug variable to activate dbug instructions: SET SESSION debug="+d,init_slave_crash_return"; The new macros are briefly described below: DBUG_CRASH_ENTER (function) is equivalent to DBUG_ENTER which registers the beginning of a function but in addition to it allows for crashing the server while entering the function if the appropriate dbug instruction is activate. In this case, the dbug instruction should be "+d,function_crash_enter". DBUG_CRASH_RETURN (value) is equivalent to DBUG_RETURN which notifies the end of a function but in addition to it allows for crashing the server while returning from the function if the appropriate dbug instruction is activate. In this case, the dbug instruction should be "+d,function_crash_return". Note that "function" should be the same string used by either the DBUG_ENTER or DBUG_CRASH_ENTER. DBUG_CRASH_VOID_RETURN (value) is equivalent to DBUG_VOID_RETURN which notifies the end of a function but in addition to it allows for crashing the server while returning from the function if the appropriate dbug instruction is activate. In this case, the dbug instruction should be "+d,function_crash_return". Note that "function" should be the same string used by either the DBUG_ENTER or DBUG_CRASH_ENTER. To inject other faults, for instance, wrong return values, one should rely on the macros already available. The current patch also removes a set of macros that were either not being used or were redundant as other macros could be used to provide the same feature. In the future, we also consider dynamic instrumentation of the code. BUG#45747 DBUG_CRASH_* is not setting the strict option --------- When combining DBUG_CRASH_* with "--debug=d:t:i:A,file" the server crashes due to a call to the abort function in the DBUG_CRASH_* macro althought the appropriate keyword has not been set.
16 years ago
WL#4828 and BUG#45747 NOTE: Backporting the patch to next-mr. WL#4828 Augment DBUG_ENTER/DBUG_EXIT to crash MySQL in different functions ------- The assessment of the replication code in the presence of faults is extremely import to increase reliability. In particular, one needs to know if servers will either correctly recovery or print out appropriate error messages thus avoiding unexpected problems in a production environment. In order to accomplish this, the current patch refactories the debug macros already provided in the source code and introduces three new macros that allows to inject faults, specifically crashes, while entering or exiting a function or method. For instance, to crash a server while returning from the init_slave function (see module sql/slave.cc), one needs to do what follows: 1 - Modify the source replacing DBUG_RETURN by DBUG_CRASH_RETURN; DBUG_CRASH_RETURN(0); 2 - Use the debug variable to activate dbug instructions: SET SESSION debug="+d,init_slave_crash_return"; The new macros are briefly described below: DBUG_CRASH_ENTER (function) is equivalent to DBUG_ENTER which registers the beginning of a function but in addition to it allows for crashing the server while entering the function if the appropriate dbug instruction is activate. In this case, the dbug instruction should be "+d,function_crash_enter". DBUG_CRASH_RETURN (value) is equivalent to DBUG_RETURN which notifies the end of a function but in addition to it allows for crashing the server while returning from the function if the appropriate dbug instruction is activate. In this case, the dbug instruction should be "+d,function_crash_return". Note that "function" should be the same string used by either the DBUG_ENTER or DBUG_CRASH_ENTER. DBUG_CRASH_VOID_RETURN (value) is equivalent to DBUG_VOID_RETURN which notifies the end of a function but in addition to it allows for crashing the server while returning from the function if the appropriate dbug instruction is activate. In this case, the dbug instruction should be "+d,function_crash_return". Note that "function" should be the same string used by either the DBUG_ENTER or DBUG_CRASH_ENTER. To inject other faults, for instance, wrong return values, one should rely on the macros already available. The current patch also removes a set of macros that were either not being used or were redundant as other macros could be used to provide the same feature. In the future, we also consider dynamic instrumentation of the code. BUG#45747 DBUG_CRASH_* is not setting the strict option --------- When combining DBUG_CRASH_* with "--debug=d:t:i:A,file" the server crashes due to a call to the abort function in the DBUG_CRASH_* macro althought the appropriate keyword has not been set.
16 years ago
WL#4828 and BUG#45747 NOTE: Backporting the patch to next-mr. WL#4828 Augment DBUG_ENTER/DBUG_EXIT to crash MySQL in different functions ------- The assessment of the replication code in the presence of faults is extremely import to increase reliability. In particular, one needs to know if servers will either correctly recovery or print out appropriate error messages thus avoiding unexpected problems in a production environment. In order to accomplish this, the current patch refactories the debug macros already provided in the source code and introduces three new macros that allows to inject faults, specifically crashes, while entering or exiting a function or method. For instance, to crash a server while returning from the init_slave function (see module sql/slave.cc), one needs to do what follows: 1 - Modify the source replacing DBUG_RETURN by DBUG_CRASH_RETURN; DBUG_CRASH_RETURN(0); 2 - Use the debug variable to activate dbug instructions: SET SESSION debug="+d,init_slave_crash_return"; The new macros are briefly described below: DBUG_CRASH_ENTER (function) is equivalent to DBUG_ENTER which registers the beginning of a function but in addition to it allows for crashing the server while entering the function if the appropriate dbug instruction is activate. In this case, the dbug instruction should be "+d,function_crash_enter". DBUG_CRASH_RETURN (value) is equivalent to DBUG_RETURN which notifies the end of a function but in addition to it allows for crashing the server while returning from the function if the appropriate dbug instruction is activate. In this case, the dbug instruction should be "+d,function_crash_return". Note that "function" should be the same string used by either the DBUG_ENTER or DBUG_CRASH_ENTER. DBUG_CRASH_VOID_RETURN (value) is equivalent to DBUG_VOID_RETURN which notifies the end of a function but in addition to it allows for crashing the server while returning from the function if the appropriate dbug instruction is activate. In this case, the dbug instruction should be "+d,function_crash_return". Note that "function" should be the same string used by either the DBUG_ENTER or DBUG_CRASH_ENTER. To inject other faults, for instance, wrong return values, one should rely on the macros already available. The current patch also removes a set of macros that were either not being used or were redundant as other macros could be used to provide the same feature. In the future, we also consider dynamic instrumentation of the code. BUG#45747 DBUG_CRASH_* is not setting the strict option --------- When combining DBUG_CRASH_* with "--debug=d:t:i:A,file" the server crashes due to a call to the abort function in the DBUG_CRASH_* macro althought the appropriate keyword has not been set.
16 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
WL#4828 and BUG#45747 NOTE: Backporting the patch to next-mr. WL#4828 Augment DBUG_ENTER/DBUG_EXIT to crash MySQL in different functions ------- The assessment of the replication code in the presence of faults is extremely import to increase reliability. In particular, one needs to know if servers will either correctly recovery or print out appropriate error messages thus avoiding unexpected problems in a production environment. In order to accomplish this, the current patch refactories the debug macros already provided in the source code and introduces three new macros that allows to inject faults, specifically crashes, while entering or exiting a function or method. For instance, to crash a server while returning from the init_slave function (see module sql/slave.cc), one needs to do what follows: 1 - Modify the source replacing DBUG_RETURN by DBUG_CRASH_RETURN; DBUG_CRASH_RETURN(0); 2 - Use the debug variable to activate dbug instructions: SET SESSION debug="+d,init_slave_crash_return"; The new macros are briefly described below: DBUG_CRASH_ENTER (function) is equivalent to DBUG_ENTER which registers the beginning of a function but in addition to it allows for crashing the server while entering the function if the appropriate dbug instruction is activate. In this case, the dbug instruction should be "+d,function_crash_enter". DBUG_CRASH_RETURN (value) is equivalent to DBUG_RETURN which notifies the end of a function but in addition to it allows for crashing the server while returning from the function if the appropriate dbug instruction is activate. In this case, the dbug instruction should be "+d,function_crash_return". Note that "function" should be the same string used by either the DBUG_ENTER or DBUG_CRASH_ENTER. DBUG_CRASH_VOID_RETURN (value) is equivalent to DBUG_VOID_RETURN which notifies the end of a function but in addition to it allows for crashing the server while returning from the function if the appropriate dbug instruction is activate. In this case, the dbug instruction should be "+d,function_crash_return". Note that "function" should be the same string used by either the DBUG_ENTER or DBUG_CRASH_ENTER. To inject other faults, for instance, wrong return values, one should rely on the macros already available. The current patch also removes a set of macros that were either not being used or were redundant as other macros could be used to provide the same feature. In the future, we also consider dynamic instrumentation of the code. BUG#45747 DBUG_CRASH_* is not setting the strict option --------- When combining DBUG_CRASH_* with "--debug=d:t:i:A,file" the server crashes due to a call to the abort function in the DBUG_CRASH_* macro althought the appropriate keyword has not been set.
16 years ago
WL#4828 and BUG#45747 NOTE: Backporting the patch to next-mr. WL#4828 Augment DBUG_ENTER/DBUG_EXIT to crash MySQL in different functions ------- The assessment of the replication code in the presence of faults is extremely import to increase reliability. In particular, one needs to know if servers will either correctly recovery or print out appropriate error messages thus avoiding unexpected problems in a production environment. In order to accomplish this, the current patch refactories the debug macros already provided in the source code and introduces three new macros that allows to inject faults, specifically crashes, while entering or exiting a function or method. For instance, to crash a server while returning from the init_slave function (see module sql/slave.cc), one needs to do what follows: 1 - Modify the source replacing DBUG_RETURN by DBUG_CRASH_RETURN; DBUG_CRASH_RETURN(0); 2 - Use the debug variable to activate dbug instructions: SET SESSION debug="+d,init_slave_crash_return"; The new macros are briefly described below: DBUG_CRASH_ENTER (function) is equivalent to DBUG_ENTER which registers the beginning of a function but in addition to it allows for crashing the server while entering the function if the appropriate dbug instruction is activate. In this case, the dbug instruction should be "+d,function_crash_enter". DBUG_CRASH_RETURN (value) is equivalent to DBUG_RETURN which notifies the end of a function but in addition to it allows for crashing the server while returning from the function if the appropriate dbug instruction is activate. In this case, the dbug instruction should be "+d,function_crash_return". Note that "function" should be the same string used by either the DBUG_ENTER or DBUG_CRASH_ENTER. DBUG_CRASH_VOID_RETURN (value) is equivalent to DBUG_VOID_RETURN which notifies the end of a function but in addition to it allows for crashing the server while returning from the function if the appropriate dbug instruction is activate. In this case, the dbug instruction should be "+d,function_crash_return". Note that "function" should be the same string used by either the DBUG_ENTER or DBUG_CRASH_ENTER. To inject other faults, for instance, wrong return values, one should rely on the macros already available. The current patch also removes a set of macros that were either not being used or were redundant as other macros could be used to provide the same feature. In the future, we also consider dynamic instrumentation of the code. BUG#45747 DBUG_CRASH_* is not setting the strict option --------- When combining DBUG_CRASH_* with "--debug=d:t:i:A,file" the server crashes due to a call to the abort function in the DBUG_CRASH_* macro althought the appropriate keyword has not been set.
16 years ago
26 years ago
  1. /******************************************************************************
  2. * *
  3. * N O T I C E *
  4. * *
  5. * Copyright Abandoned, 1987, Fred Fish *
  6. * *
  7. * *
  8. * This previously copyrighted work has been placed into the public *
  9. * domain by the author and may be freely used for any purpose, *
  10. * private or commercial. *
  11. * *
  12. * Because of the number of inquiries I was receiving about the use *
  13. * of this product in commercially developed works I have decided to *
  14. * simply make it public domain to further its unrestricted use. I *
  15. * specifically would be most happy to see this material become a *
  16. * part of the standard Unix distributions by AT&T and the Berkeley *
  17. * Computer Science Research Group, and a standard part of the GNU *
  18. * system from the Free Software Foundation. *
  19. * *
  20. * I would appreciate it, as a courtesy, if this notice is left in *
  21. * all copies and derivative works. Thank you. *
  22. * *
  23. * The author makes no warranty of any kind with respect to this *
  24. * product and explicitly disclaims any implied warranties of mer- *
  25. * chantability or fitness for any particular purpose. *
  26. * *
  27. ******************************************************************************
  28. */
  29. /*
  30. * FILE
  31. *
  32. * dbug.c runtime support routines for dbug package
  33. *
  34. * SCCS
  35. *
  36. * @(#)dbug.c 1.25 7/25/89
  37. *
  38. * DESCRIPTION
  39. *
  40. * These are the runtime support routines for the dbug package.
  41. * The dbug package has two main components; the user include
  42. * file containing various macro definitions, and the runtime
  43. * support routines which are called from the macro expansions.
  44. *
  45. * Externally visible functions in the runtime support module
  46. * use the naming convention pattern "_db_xx...xx_", thus
  47. * they are unlikely to collide with user defined function names.
  48. *
  49. * AUTHOR(S)
  50. *
  51. * Fred Fish (base code)
  52. * Enhanced Software Technologies, Tempe, AZ
  53. * asuvax!mcdphx!estinc!fnf
  54. *
  55. * Binayak Banerjee (profiling enhancements)
  56. * seismo!bpa!sjuvax!bbanerje
  57. *
  58. * Michael Widenius:
  59. * DBUG_DUMP - To dump a block of memory.
  60. * PUSH_FLAG "O" - To be used insted of "o" if we
  61. * want flushing after each write
  62. * PUSH_FLAG "A" - as 'O', but we will append to the out file instead
  63. * of creating a new one.
  64. * Check of malloc on entry/exit (option "S")
  65. *
  66. * Sergei Golubchik:
  67. * DBUG_EXECUTE_IF
  68. * incremental mode (-#+t:-d,info ...)
  69. * DBUG_SET, _db_explain_
  70. * thread-local settings
  71. * negative lists (-#-d,info => everything but "info")
  72. *
  73. * function/ syntax
  74. * (the logic is - think of a call stack as of a path.
  75. * "function" means only this function, "function/" means the hierarchy.
  76. * in the future, filters like function1/function2 could be supported.
  77. * following this logic glob(7) wildcards are supported.)
  78. *
  79. */
  80. /*
  81. We can't have SAFE_MUTEX defined here as this will cause recursion
  82. in pthread_mutex_lock
  83. */
  84. #undef SAFE_MUTEX
  85. #include <my_global.h>
  86. #include <m_string.h>
  87. #include <errno.h>
  88. #ifdef HAVE_FNMATCH_H
  89. #include <fnmatch.h>
  90. #else
  91. #define fnmatch(A,B,C) strcmp(A,B)
  92. #endif
  93. #if defined(__WIN__)
  94. #include <process.h>
  95. #endif
  96. #ifndef DBUG_OFF
  97. /*
  98. * Manifest constants which may be "tuned" if desired.
  99. */
  100. #define PRINTBUF 1024 /* Print buffer size */
  101. #define INDENT 2 /* Indentation per trace level */
  102. #define MAXDEPTH 200 /* Maximum trace depth default */
  103. /*
  104. * The following flags are used to determine which
  105. * capabilities the user has enabled with the settings
  106. * push macro.
  107. *
  108. * TRACE_ON is also used in _db_stack_frame_->level
  109. * (until we add flags to _db_stack_frame_, increasing it by 4 bytes)
  110. */
  111. #define DEBUG_ON (1 << 1) /* Debug enabled */
  112. #define FILE_ON (1 << 2) /* File name print enabled */
  113. #define LINE_ON (1 << 3) /* Line number print enabled */
  114. #define DEPTH_ON (1 << 4) /* Function nest level print enabled */
  115. #define PROCESS_ON (1 << 5) /* Process name print enabled */
  116. #define NUMBER_ON (1 << 6) /* Number each line of output */
  117. #define PROFILE_ON (1 << 7) /* Print out profiling code */
  118. #define PID_ON (1 << 8) /* Identify each line with process id */
  119. #define TIMESTAMP_ON (1 << 9) /* timestamp every line of output */
  120. #define FLUSH_ON_WRITE (1 << 10) /* Flush on every write */
  121. #define OPEN_APPEND (1 << 11) /* Open for append */
  122. #define TRACE_ON ((uint)1 << 31) /* Trace enabled. MUST be the highest bit!*/
  123. #define TRACING (cs->stack->flags & TRACE_ON)
  124. #define DEBUGGING (cs->stack->flags & DEBUG_ON)
  125. #define PROFILING (cs->stack->flags & PROFILE_ON)
  126. /*
  127. * Typedefs to make things more obvious.
  128. */
  129. #define BOOLEAN my_bool
  130. /*
  131. * Make it easy to change storage classes if necessary.
  132. */
  133. #define IMPORT extern /* Names defined externally */
  134. #define EXPORT /* Allocated here, available globally */
  135. #define AUTO auto /* Names to be allocated on stack */
  136. #define REGISTER register /* Names to be placed in registers */
  137. /*
  138. * The default file for profiling. Could also add another flag
  139. * (G?) which allowed the user to specify this.
  140. *
  141. * If the automatic variables get allocated on the stack in
  142. * reverse order from their declarations, then define AUTOS_REVERSE to 1.
  143. * This is used by the code that keeps track of stack usage. For
  144. * forward allocation, the difference in the dbug frame pointers
  145. * represents stack used by the callee function. For reverse allocation,
  146. * the difference represents stack used by the caller function.
  147. *
  148. */
  149. #define PROF_FILE "dbugmon.out"
  150. #define PROF_EFMT "E\t%ld\t%s\n"
  151. #define PROF_SFMT "S\t%lx\t%lx\t%s\n"
  152. #define PROF_XFMT "X\t%ld\t%s\n"
  153. #ifdef M_I386 /* predefined by xenix 386 compiler */
  154. #define AUTOS_REVERSE 1
  155. #else
  156. #define AUTOS_REVERSE 0
  157. #endif
  158. /*
  159. * Externally supplied functions.
  160. */
  161. #ifndef HAVE_PERROR
  162. static void perror(); /* Fake system/library error print routine */
  163. #endif
  164. /*
  165. * The user may specify a list of functions to trace or
  166. * debug. These lists are kept in a linear linked list,
  167. * a very simple implementation.
  168. */
  169. struct link {
  170. struct link *next_link; /* Pointer to the next link */
  171. char flags;
  172. char str[1]; /* Pointer to link's contents */
  173. };
  174. /* flags for struct link and return flags of InList */
  175. #define SUBDIR 1 /* this MUST be 1 */
  176. #define INCLUDE 2
  177. #define EXCLUDE 4
  178. /* this is not a struct link flag, but only a return flags of InList */
  179. #define MATCHED 65536
  180. #define NOT_MATCHED 0
  181. /*
  182. * Debugging settings can be pushed or popped off of a
  183. * stack which is implemented as a linked list. Note
  184. * that the head of the list is the current settings and the
  185. * stack is pushed by adding a new settings to the head of the
  186. * list or popped by removing the first link.
  187. *
  188. * Note: if out_file is NULL, the other fields are not initialized at all!
  189. */
  190. struct settings {
  191. uint flags; /* Current settings flags */
  192. uint maxdepth; /* Current maximum trace depth */
  193. uint delay; /* Delay after each output line */
  194. uint sub_level; /* Sub this from code_state->level */
  195. FILE *out_file; /* Current output stream */
  196. FILE *prof_file; /* Current profiling stream */
  197. char name[FN_REFLEN]; /* Name of output file */
  198. struct link *functions; /* List of functions */
  199. struct link *p_functions; /* List of profiled functions */
  200. struct link *keywords; /* List of debug keywords */
  201. struct link *processes; /* List of process names */
  202. struct settings *next; /* Next settings in the list */
  203. };
  204. #define is_shared(S, V) ((S)->next && (S)->next->V == (S)->V)
  205. /*
  206. * Local variables not seen by user.
  207. */
  208. static BOOLEAN init_done= FALSE; /* Set to TRUE when initialization done */
  209. static struct settings init_settings;
  210. static const char *db_process= 0;/* Pointer to process name; argv[0] */
  211. my_bool _dbug_on_= TRUE; /* FALSE if no debugging at all */
  212. typedef struct _db_code_state_ {
  213. const char *process; /* Pointer to process name; usually argv[0] */
  214. const char *func; /* Name of current user function */
  215. const char *file; /* Name of current user file */
  216. struct _db_stack_frame_ *framep; /* Pointer to current frame */
  217. struct settings *stack; /* debugging settings */
  218. const char *jmpfunc; /* Remember current function for setjmp */
  219. const char *jmpfile; /* Remember current file for setjmp */
  220. int lineno; /* Current debugger output line number */
  221. uint level; /* Current function nesting level */
  222. int jmplevel; /* Remember nesting level at setjmp() */
  223. /*
  224. * The following variables are used to hold the state information
  225. * between the call to _db_pargs_() and _db_doprnt_(), during
  226. * expansion of the DBUG_PRINT macro. This is the only macro
  227. * that currently uses these variables.
  228. *
  229. * These variables are currently used only by _db_pargs_() and
  230. * _db_doprnt_().
  231. */
  232. uint u_line; /* User source code line number */
  233. int locked; /* If locked with _db_lock_file_ */
  234. const char *u_keyword; /* Keyword for current macro */
  235. } CODE_STATE;
  236. /*
  237. The test below is so we could call functions with DBUG_ENTER before
  238. my_thread_init().
  239. */
  240. #define get_code_state_if_not_set_or_return if (!cs && !((cs=code_state()))) return
  241. #define get_code_state_or_return if (!((cs=code_state()))) return
  242. /* Handling lists */
  243. #define ListAdd(A,B,C) ListAddDel(A,B,C,INCLUDE)
  244. #define ListDel(A,B,C) ListAddDel(A,B,C,EXCLUDE)
  245. static struct link *ListAddDel(struct link *, const char *, const char *, int);
  246. static struct link *ListCopy(struct link *);
  247. static int InList(struct link *linkp,const char *cp);
  248. static uint ListFlags(struct link *linkp);
  249. static void FreeList(struct link *linkp);
  250. /* OpenClose debug output stream */
  251. static void DBUGOpenFile(CODE_STATE *,const char *, const char *, int);
  252. static void DBUGCloseFile(CODE_STATE *cs, FILE *fp);
  253. /* Push current debug settings */
  254. static void PushState(CODE_STATE *cs);
  255. /* Free memory associated with debug state. */
  256. static void FreeState (CODE_STATE *cs, struct settings *state, int free_state);
  257. /* Test for tracing enabled */
  258. static int DoTrace(CODE_STATE *cs);
  259. /*
  260. return values of DoTrace.
  261. Can also be used as bitmask: ret & DO_TRACE
  262. */
  263. #define DO_TRACE 1
  264. #define DONT_TRACE 2
  265. #define ENABLE_TRACE 3
  266. #define DISABLE_TRACE 4
  267. /* Test to see if file is writable */
  268. #if defined(HAVE_ACCESS)
  269. static BOOLEAN Writable(const char *pathname);
  270. /* Change file owner and group */
  271. static void ChangeOwner(CODE_STATE *cs, char *pathname);
  272. /* Allocate memory for runtime support */
  273. #endif
  274. static void DoPrefix(CODE_STATE *cs, uint line);
  275. static char *DbugMalloc(size_t size);
  276. static const char *BaseName(const char *pathname);
  277. static void Indent(CODE_STATE *cs, int indent);
  278. static void DbugFlush(CODE_STATE *);
  279. static void DbugExit(const char *why);
  280. static const char *DbugStrTok(const char *s);
  281. static void DbugVfprintf(FILE *stream, const char* format, va_list args);
  282. /*
  283. * Miscellaneous printf format strings.
  284. */
  285. #define ERR_MISSING_RETURN "missing DBUG_RETURN or DBUG_VOID_RETURN macro in function \"%s\"\n"
  286. #define ERR_OPEN "%s: can't open debug output stream \"%s\": "
  287. #define ERR_CLOSE "%s: can't close debug file: "
  288. #define ERR_ABORT "%s: debugger aborting because %s\n"
  289. /*
  290. * Macros and defines for testing file accessibility under UNIX and MSDOS.
  291. */
  292. #undef EXISTS
  293. #if !defined(HAVE_ACCESS)
  294. #define EXISTS(pathname) (FALSE) /* Assume no existance */
  295. #define Writable(name) (TRUE)
  296. #else
  297. #define EXISTS(pathname) (access(pathname, F_OK) == 0)
  298. #define WRITABLE(pathname) (access(pathname, W_OK) == 0)
  299. #endif
  300. /*
  301. ** Macros to allow dbugging with threads
  302. */
  303. #include <my_pthread.h>
  304. static pthread_mutex_t THR_LOCK_dbug;
  305. static CODE_STATE *code_state(void)
  306. {
  307. CODE_STATE *cs, **cs_ptr;
  308. /*
  309. _dbug_on_ is reset if we don't plan to use any debug commands at all and
  310. we want to run on maximum speed
  311. */
  312. if (!_dbug_on_)
  313. return 0;
  314. if (!init_done)
  315. {
  316. init_done=TRUE;
  317. pthread_mutex_init(&THR_LOCK_dbug, NULL);
  318. bzero(&init_settings, sizeof(init_settings));
  319. init_settings.out_file=stderr;
  320. init_settings.flags=OPEN_APPEND;
  321. }
  322. if (!(cs_ptr= (CODE_STATE**) my_thread_var_dbug()))
  323. return 0; /* Thread not initialised */
  324. if (!(cs= *cs_ptr))
  325. {
  326. cs=(CODE_STATE*) DbugMalloc(sizeof(*cs));
  327. bzero((uchar*) cs,sizeof(*cs));
  328. cs->process= db_process ? db_process : "dbug";
  329. cs->func="?func";
  330. cs->file="?file";
  331. cs->stack=&init_settings;
  332. *cs_ptr= cs;
  333. }
  334. return cs;
  335. }
  336. /*
  337. * Translate some calls among different systems.
  338. */
  339. #ifdef HAVE_SLEEP
  340. /* sleep() wants seconds */
  341. #define Delay(A) sleep(((uint) A)/10)
  342. #else
  343. #define Delay(A) (0)
  344. #endif
  345. /*
  346. * FUNCTION
  347. *
  348. * _db_process_ give the name to the current process/thread
  349. *
  350. * SYNOPSIS
  351. *
  352. * VOID _process_(name)
  353. * char *name;
  354. *
  355. */
  356. void _db_process_(const char *name)
  357. {
  358. CODE_STATE *cs;
  359. if (!db_process)
  360. db_process= name;
  361. get_code_state_or_return;
  362. cs->process= name;
  363. }
  364. /*
  365. * FUNCTION
  366. *
  367. * DbugParse parse control string and set current debugger settings
  368. *
  369. * DESCRIPTION
  370. *
  371. * Given pointer to a debug control string in "control",
  372. * parses the control string, and sets
  373. * up a current debug settings.
  374. *
  375. * The debug control string is a sequence of colon separated fields
  376. * as follows:
  377. *
  378. * [+]<field_1>:<field_2>:...:<field_N>
  379. *
  380. * Each field consists of a mandatory flag character followed by
  381. * an optional "," and comma separated list of modifiers:
  382. *
  383. * [sign]flag[,modifier,modifier,...,modifier]
  384. *
  385. * See the manual for the list of supported signs, flags, and modifiers
  386. *
  387. * For convenience, any leading "-#" is stripped off.
  388. *
  389. * RETURN
  390. * 1 - a list of functions ("f" flag) was possibly changed
  391. * 0 - a list of functions was not changed
  392. */
  393. int DbugParse(CODE_STATE *cs, const char *control)
  394. {
  395. const char *end;
  396. int rel, f_used=0;
  397. struct settings *stack;
  398. stack= cs->stack;
  399. if (control[0] == '-' && control[1] == '#')
  400. control+=2;
  401. rel= control[0] == '+' || control[0] == '-';
  402. if ((!rel || (!stack->out_file && !stack->next)))
  403. {
  404. /* Free memory associated with the state before resetting its members */
  405. FreeState(cs, stack, 0);
  406. stack->flags= 0;
  407. stack->delay= 0;
  408. stack->maxdepth= 0;
  409. stack->sub_level= 0;
  410. stack->out_file= stderr;
  411. stack->prof_file= NULL;
  412. stack->functions= NULL;
  413. stack->p_functions= NULL;
  414. stack->keywords= NULL;
  415. stack->processes= NULL;
  416. }
  417. else if (!stack->out_file)
  418. {
  419. stack->flags= stack->next->flags;
  420. stack->delay= stack->next->delay;
  421. stack->maxdepth= stack->next->maxdepth;
  422. stack->sub_level= stack->next->sub_level;
  423. strcpy(stack->name, stack->next->name);
  424. stack->prof_file= stack->next->prof_file;
  425. if (stack->next == &init_settings)
  426. {
  427. /*
  428. Never share with the global parent - it can change under your feet.
  429. Reset out_file to stderr to prevent sharing of trace files between
  430. global and session settings.
  431. */
  432. stack->out_file= stderr;
  433. stack->functions= ListCopy(init_settings.functions);
  434. stack->p_functions= ListCopy(init_settings.p_functions);
  435. stack->keywords= ListCopy(init_settings.keywords);
  436. stack->processes= ListCopy(init_settings.processes);
  437. }
  438. else
  439. {
  440. stack->out_file= stack->next->out_file;
  441. stack->functions= stack->next->functions;
  442. stack->p_functions= stack->next->p_functions;
  443. stack->keywords= stack->next->keywords;
  444. stack->processes= stack->next->processes;
  445. }
  446. }
  447. end= DbugStrTok(control);
  448. while (control < end)
  449. {
  450. int c, sign= (*control == '+') ? 1 : (*control == '-') ? -1 : 0;
  451. if (sign) control++;
  452. c= *control++;
  453. if (*control == ',') control++;
  454. /* XXX when adding new cases here, don't forget _db_explain_ ! */
  455. switch (c) {
  456. case 'd':
  457. if (sign < 0 && control == end)
  458. {
  459. if (!is_shared(stack, keywords))
  460. FreeList(stack->keywords);
  461. stack->keywords=NULL;
  462. stack->flags &= ~DEBUG_ON;
  463. break;
  464. }
  465. if (rel && is_shared(stack, keywords))
  466. stack->keywords= ListCopy(stack->keywords);
  467. if (sign < 0)
  468. {
  469. if (DEBUGGING)
  470. stack->keywords= ListDel(stack->keywords, control, end);
  471. break;
  472. }
  473. stack->keywords= ListAdd(stack->keywords, control, end);
  474. stack->flags |= DEBUG_ON;
  475. break;
  476. case 'D':
  477. stack->delay= atoi(control);
  478. break;
  479. case 'f':
  480. f_used= 1;
  481. if (sign < 0 && control == end)
  482. {
  483. if (!is_shared(stack,functions))
  484. FreeList(stack->functions);
  485. stack->functions=NULL;
  486. break;
  487. }
  488. if (rel && is_shared(stack,functions))
  489. stack->functions= ListCopy(stack->functions);
  490. if (sign < 0)
  491. stack->functions= ListDel(stack->functions, control, end);
  492. else
  493. stack->functions= ListAdd(stack->functions, control, end);
  494. break;
  495. case 'F':
  496. if (sign < 0)
  497. stack->flags &= ~FILE_ON;
  498. else
  499. stack->flags |= FILE_ON;
  500. break;
  501. case 'i':
  502. if (sign < 0)
  503. stack->flags &= ~PID_ON;
  504. else
  505. stack->flags |= PID_ON;
  506. break;
  507. case 'L':
  508. if (sign < 0)
  509. stack->flags &= ~LINE_ON;
  510. else
  511. stack->flags |= LINE_ON;
  512. break;
  513. case 'n':
  514. if (sign < 0)
  515. stack->flags &= ~DEPTH_ON;
  516. else
  517. stack->flags |= DEPTH_ON;
  518. break;
  519. case 'N':
  520. if (sign < 0)
  521. stack->flags &= ~NUMBER_ON;
  522. else
  523. stack->flags |= NUMBER_ON;
  524. break;
  525. case 'A':
  526. case 'O':
  527. stack->flags |= FLUSH_ON_WRITE;
  528. /* fall through */
  529. case 'a':
  530. case 'o':
  531. if (sign < 0)
  532. {
  533. if (!is_shared(stack, out_file))
  534. DBUGCloseFile(cs, stack->out_file);
  535. stack->flags &= ~FLUSH_ON_WRITE;
  536. stack->out_file= stderr;
  537. break;
  538. }
  539. if (c == 'a' || c == 'A')
  540. stack->flags |= OPEN_APPEND;
  541. else
  542. stack->flags &= ~OPEN_APPEND;
  543. if (control != end)
  544. DBUGOpenFile(cs, control, end, stack->flags & OPEN_APPEND);
  545. else
  546. DBUGOpenFile(cs, "-",0,0);
  547. break;
  548. case 'p':
  549. if (sign < 0 && control == end)
  550. {
  551. if (!is_shared(stack,processes))
  552. FreeList(stack->processes);
  553. stack->processes=NULL;
  554. break;
  555. }
  556. if (rel && is_shared(stack, processes))
  557. stack->processes= ListCopy(stack->processes);
  558. if (sign < 0)
  559. stack->processes= ListDel(stack->processes, control, end);
  560. else
  561. stack->processes= ListAdd(stack->processes, control, end);
  562. break;
  563. case 'P':
  564. if (sign < 0)
  565. stack->flags &= ~PROCESS_ON;
  566. else
  567. stack->flags |= PROCESS_ON;
  568. break;
  569. case 'r':
  570. stack->sub_level= cs->level;
  571. break;
  572. case 't':
  573. if (sign < 0)
  574. {
  575. if (control != end)
  576. stack->maxdepth-= atoi(control);
  577. else
  578. stack->maxdepth= 0;
  579. }
  580. else
  581. {
  582. if (control != end)
  583. stack->maxdepth+= atoi(control);
  584. else
  585. stack->maxdepth= MAXDEPTH;
  586. }
  587. if (stack->maxdepth > 0)
  588. stack->flags |= TRACE_ON;
  589. else
  590. stack->flags &= ~TRACE_ON;
  591. break;
  592. case 'T':
  593. if (sign < 0)
  594. stack->flags &= ~TIMESTAMP_ON;
  595. else
  596. stack->flags |= TIMESTAMP_ON;
  597. break;
  598. }
  599. if (!*end)
  600. break;
  601. control=end+1;
  602. end= DbugStrTok(control);
  603. }
  604. return !rel || f_used;
  605. }
  606. #define framep_trace_flag(cs, frp) (frp ? \
  607. frp->level & TRACE_ON : \
  608. (ListFlags(cs->stack->functions) & INCLUDE) ? \
  609. 0 : (uint)TRACE_ON)
  610. void FixTraceFlags_helper(CODE_STATE *cs, const char *func,
  611. struct _db_stack_frame_ *framep)
  612. {
  613. if (framep->prev)
  614. FixTraceFlags_helper(cs, framep->func, framep->prev);
  615. cs->func= func;
  616. cs->level= framep->level & ~TRACE_ON;
  617. framep->level= cs->level | framep_trace_flag(cs, framep->prev);
  618. /*
  619. we don't set cs->framep correctly, even though DoTrace uses it.
  620. It's ok, because cs->framep may only affect DO_TRACE/DONT_TRACE return
  621. values, but we ignore them here anyway
  622. */
  623. switch(DoTrace(cs)) {
  624. case ENABLE_TRACE:
  625. framep->level|= TRACE_ON;
  626. break;
  627. case DISABLE_TRACE:
  628. framep->level&= ~TRACE_ON;
  629. break;
  630. }
  631. }
  632. #define fflags(cs) cs->stack->out_file ? ListFlags(cs->stack->functions) : TRACE_ON;
  633. void FixTraceFlags(uint old_fflags, CODE_STATE *cs)
  634. {
  635. const char *func;
  636. uint new_fflags, traceon, level;
  637. struct _db_stack_frame_ *framep;
  638. /*
  639. first (a.k.a. safety) check:
  640. if we haven't started tracing yet, no call stack at all - we're safe.
  641. */
  642. framep=cs->framep;
  643. if (framep == 0)
  644. return;
  645. /*
  646. Ok, the tracing has started, call stack isn't empty.
  647. second check: does the new list have a SUBDIR rule ?
  648. */
  649. new_fflags=fflags(cs);
  650. if (new_fflags & SUBDIR)
  651. goto yuck;
  652. /*
  653. Ok, new list doesn't use SUBDIR.
  654. third check: we do NOT need to re-scan if
  655. neither old nor new lists used SUBDIR flag and if a default behavior
  656. (whether an unlisted function is traced) hasn't changed.
  657. Default behavior depends on whether there're INCLUDE elements in the list.
  658. */
  659. if (!(old_fflags & SUBDIR) && !((new_fflags^old_fflags) & INCLUDE))
  660. return;
  661. /*
  662. Ok, old list may've used SUBDIR, or defaults could've changed.
  663. fourth check: are we inside a currently active SUBDIR rule ?
  664. go up the call stack, if TRACE_ON flag ever changes its value - we are.
  665. */
  666. for (traceon=framep->level; framep; framep=framep->prev)
  667. if ((traceon ^ framep->level) & TRACE_ON)
  668. goto yuck;
  669. /*
  670. Ok, TRACE_ON flag doesn't change in the call stack.
  671. fifth check: but is the top-most value equal to a default one ?
  672. */
  673. if (((traceon & TRACE_ON) != 0) == ((new_fflags & INCLUDE) == 0))
  674. return;
  675. yuck:
  676. /*
  677. Yuck! function list was changed, and one of the currently active rules
  678. was possibly affected. For example, a tracing could've been enabled or
  679. disabled for a function somewhere up the call stack.
  680. To react correctly, we must go up the call stack all the way to
  681. the top and re-match rules to set TRACE_ON bit correctly.
  682. We must traverse the stack forwards, not backwards.
  683. That's what a recursive helper is doing.
  684. It'll destroy two CODE_STATE fields, save them now.
  685. */
  686. func= cs->func;
  687. level= cs->level;
  688. FixTraceFlags_helper(cs, func, cs->framep);
  689. /* now we only need to restore CODE_STATE fields, and we're done */
  690. cs->func= func;
  691. cs->level= level;
  692. }
  693. /*
  694. * FUNCTION
  695. *
  696. * _db_set_ set current debugger settings
  697. *
  698. * SYNOPSIS
  699. *
  700. * VOID _db_set_(control)
  701. * char *control;
  702. *
  703. * DESCRIPTION
  704. *
  705. * Given pointer to a debug control string in "control",
  706. * parses the control string, and sets up a current debug
  707. * settings. Pushes a new debug settings if the current is
  708. * set to the initial debugger settings.
  709. *
  710. */
  711. void _db_set_(const char *control)
  712. {
  713. CODE_STATE *cs;
  714. uint old_fflags;
  715. get_code_state_or_return;
  716. old_fflags=fflags(cs);
  717. if (cs->stack == &init_settings)
  718. PushState(cs);
  719. if (DbugParse(cs, control))
  720. FixTraceFlags(old_fflags, cs);
  721. }
  722. /*
  723. * FUNCTION
  724. *
  725. * _db_push_ push current debugger settings and set up new one
  726. *
  727. * SYNOPSIS
  728. *
  729. * VOID _db_push_(control)
  730. * char *control;
  731. *
  732. * DESCRIPTION
  733. *
  734. * Given pointer to a debug control string in "control", pushes
  735. * the current debug settings, parses the control string, and sets
  736. * up a new debug settings with DbugParse()
  737. *
  738. */
  739. void _db_push_(const char *control)
  740. {
  741. CODE_STATE *cs;
  742. uint old_fflags;
  743. get_code_state_or_return;
  744. old_fflags=fflags(cs);
  745. PushState(cs);
  746. if (DbugParse(cs, control))
  747. FixTraceFlags(old_fflags, cs);
  748. }
  749. /**
  750. Returns TRUE if session-local settings have been set.
  751. */
  752. int _db_is_pushed_()
  753. {
  754. CODE_STATE *cs= NULL;
  755. get_code_state_or_return FALSE;
  756. return (cs->stack != &init_settings);
  757. }
  758. /*
  759. * FUNCTION
  760. *
  761. * _db_set_init_ set initial debugger settings
  762. *
  763. * SYNOPSIS
  764. *
  765. * VOID _db_set_init_(control)
  766. * char *control;
  767. *
  768. * DESCRIPTION
  769. * see _db_set_
  770. *
  771. */
  772. void _db_set_init_(const char *control)
  773. {
  774. CODE_STATE tmp_cs;
  775. bzero((uchar*) &tmp_cs, sizeof(tmp_cs));
  776. tmp_cs.stack= &init_settings;
  777. tmp_cs.process= db_process ? db_process : "dbug";
  778. DbugParse(&tmp_cs, control);
  779. }
  780. /*
  781. * FUNCTION
  782. *
  783. * _db_pop_ pop the debug stack
  784. *
  785. * DESCRIPTION
  786. *
  787. * Pops the debug stack, returning the debug settings to its
  788. * condition prior to the most recent _db_push_ invocation.
  789. * Note that the pop will fail if it would remove the last
  790. * valid settings from the stack. This prevents user errors
  791. * in the push/pop sequence from screwing up the debugger.
  792. * Maybe there should be some kind of warning printed if the
  793. * user tries to pop too many states.
  794. *
  795. */
  796. void _db_pop_()
  797. {
  798. struct settings *discard;
  799. uint old_fflags;
  800. CODE_STATE *cs;
  801. get_code_state_or_return;
  802. discard= cs->stack;
  803. if (discard != &init_settings)
  804. {
  805. old_fflags=fflags(cs);
  806. cs->stack= discard->next;
  807. FreeState(cs, discard, 1);
  808. FixTraceFlags(old_fflags, cs);
  809. }
  810. }
  811. /*
  812. * FUNCTION
  813. *
  814. * _db_explain_ generates 'control' string for the current settings
  815. *
  816. * RETURN
  817. * 0 - ok
  818. * 1 - buffer too short, output truncated
  819. *
  820. */
  821. /* helper macros */
  822. #define char_to_buf(C) do { \
  823. *buf++=(C); \
  824. if (buf >= end) goto overflow; \
  825. } while (0)
  826. #define str_to_buf(S) do { \
  827. char_to_buf(','); \
  828. buf=strnmov(buf, (S), len+1); \
  829. if (buf >= end) goto overflow; \
  830. } while (0)
  831. #define list_to_buf(l, f) do { \
  832. struct link *listp=(l); \
  833. while (listp) \
  834. { \
  835. if (listp->flags & (f)) \
  836. { \
  837. str_to_buf(listp->str); \
  838. if (listp->flags & SUBDIR) \
  839. char_to_buf('/'); \
  840. } \
  841. listp=listp->next_link; \
  842. } \
  843. } while (0)
  844. #define int_to_buf(i) do { \
  845. char b[50]; \
  846. int10_to_str((i), b, 10); \
  847. str_to_buf(b); \
  848. } while (0)
  849. #define colon_to_buf do { \
  850. if (buf != start) char_to_buf(':'); \
  851. } while(0)
  852. #define op_int_to_buf(C, val, def) do { \
  853. if ((val) != (def)) \
  854. { \
  855. colon_to_buf; \
  856. char_to_buf((C)); \
  857. int_to_buf(val); \
  858. } \
  859. } while (0)
  860. #define op_intf_to_buf(C, val, def, cond) do { \
  861. if ((cond)) \
  862. { \
  863. colon_to_buf; \
  864. char_to_buf((C)); \
  865. if ((val) != (def)) int_to_buf(val); \
  866. } \
  867. } while (0)
  868. #define op_str_to_buf(C, val, cond) do { \
  869. if ((cond)) \
  870. { \
  871. char *s=(val); \
  872. colon_to_buf; \
  873. char_to_buf((C)); \
  874. if (*s) str_to_buf(s); \
  875. } \
  876. } while (0)
  877. #define op_list_to_buf(C, val, cond) do { \
  878. if ((cond)) \
  879. { \
  880. int f=ListFlags(val); \
  881. colon_to_buf; \
  882. char_to_buf((C)); \
  883. if (f & INCLUDE) \
  884. list_to_buf(val, INCLUDE); \
  885. if (f & EXCLUDE) \
  886. { \
  887. colon_to_buf; \
  888. char_to_buf('-'); \
  889. char_to_buf((C)); \
  890. list_to_buf(val, EXCLUDE); \
  891. } \
  892. } \
  893. } while (0)
  894. #define op_bool_to_buf(C, cond) do { \
  895. if ((cond)) \
  896. { \
  897. colon_to_buf; \
  898. char_to_buf((C)); \
  899. } \
  900. } while (0)
  901. int _db_explain_ (CODE_STATE *cs, char *buf, size_t len)
  902. {
  903. char *start=buf, *end=buf+len-4;
  904. get_code_state_if_not_set_or_return *buf=0;
  905. op_list_to_buf('d', cs->stack->keywords, DEBUGGING);
  906. op_int_to_buf ('D', cs->stack->delay, 0);
  907. op_list_to_buf('f', cs->stack->functions, cs->stack->functions);
  908. op_bool_to_buf('F', cs->stack->flags & FILE_ON);
  909. op_bool_to_buf('i', cs->stack->flags & PID_ON);
  910. op_list_to_buf('g', cs->stack->p_functions, PROFILING);
  911. op_bool_to_buf('L', cs->stack->flags & LINE_ON);
  912. op_bool_to_buf('n', cs->stack->flags & DEPTH_ON);
  913. op_bool_to_buf('N', cs->stack->flags & NUMBER_ON);
  914. op_str_to_buf(
  915. ((cs->stack->flags & FLUSH_ON_WRITE ? 0 : 32) |
  916. (cs->stack->flags & OPEN_APPEND ? 'A' : 'O')),
  917. cs->stack->name, cs->stack->out_file != stderr);
  918. op_list_to_buf('p', cs->stack->processes, cs->stack->processes);
  919. op_bool_to_buf('P', cs->stack->flags & PROCESS_ON);
  920. op_bool_to_buf('r', cs->stack->sub_level != 0);
  921. op_intf_to_buf('t', cs->stack->maxdepth, MAXDEPTH, TRACING);
  922. op_bool_to_buf('T', cs->stack->flags & TIMESTAMP_ON);
  923. *buf= '\0';
  924. return 0;
  925. overflow:
  926. *end++= '.';
  927. *end++= '.';
  928. *end++= '.';
  929. *end= '\0';
  930. return 1;
  931. }
  932. #undef char_to_buf
  933. #undef str_to_buf
  934. #undef list_to_buf
  935. #undef int_to_buf
  936. #undef colon_to_buf
  937. #undef op_int_to_buf
  938. #undef op_intf_to_buf
  939. #undef op_str_to_buf
  940. #undef op_list_to_buf
  941. #undef op_bool_to_buf
  942. /*
  943. * FUNCTION
  944. *
  945. * _db_explain_init_ explain initial debugger settings
  946. *
  947. * DESCRIPTION
  948. * see _db_explain_
  949. */
  950. int _db_explain_init_(char *buf, size_t len)
  951. {
  952. CODE_STATE cs;
  953. bzero((uchar*) &cs,sizeof(cs));
  954. cs.stack=&init_settings;
  955. return _db_explain_(&cs, buf, len);
  956. }
  957. /*
  958. * FUNCTION
  959. *
  960. * _db_enter_ process entry point to user function
  961. *
  962. * SYNOPSIS
  963. *
  964. * VOID _db_enter_(_func_, _file_, _line_, _stack_frame_)
  965. * char *_func_; points to current function name
  966. * char *_file_; points to current file name
  967. * int _line_; called from source line number
  968. * struct _db_stack_frame_ allocated on the caller's stack
  969. *
  970. * DESCRIPTION
  971. *
  972. * Called at the beginning of each user function to tell
  973. * the debugger that a new function has been entered.
  974. * Note that the pointers to the previous user function
  975. * name and previous user file name are stored on the
  976. * caller's stack (this is why the ENTER macro must be
  977. * the first "executable" code in a function, since it
  978. * allocates these storage locations). The previous nesting
  979. * level is also stored on the callers stack for internal
  980. * self consistency checks.
  981. *
  982. * Also prints a trace line if tracing is enabled and
  983. * increments the current function nesting depth.
  984. *
  985. * Note that this mechanism allows the debugger to know
  986. * what the current user function is at all times, without
  987. * maintaining an internal stack for the function names.
  988. *
  989. */
  990. void _db_enter_(const char *_func_, const char *_file_,
  991. uint _line_, struct _db_stack_frame_ *_stack_frame_)
  992. {
  993. int save_errno;
  994. CODE_STATE *cs;
  995. if (!((cs=code_state())))
  996. {
  997. _stack_frame_->level= 0; /* Set to avoid valgrind warnings if dbug is enabled later */
  998. _stack_frame_->prev= 0;
  999. return;
  1000. }
  1001. save_errno= errno;
  1002. _stack_frame_->func= cs->func;
  1003. _stack_frame_->file= cs->file;
  1004. cs->func= _func_;
  1005. cs->file= _file_;
  1006. _stack_frame_->prev= cs->framep;
  1007. _stack_frame_->level= ++cs->level | framep_trace_flag(cs, cs->framep);
  1008. cs->framep= _stack_frame_;
  1009. switch (DoTrace(cs)) {
  1010. case ENABLE_TRACE:
  1011. cs->framep->level|= TRACE_ON;
  1012. if (!TRACING) break;
  1013. /* fall through */
  1014. case DO_TRACE:
  1015. if (TRACING)
  1016. {
  1017. if (!cs->locked)
  1018. pthread_mutex_lock(&THR_LOCK_dbug);
  1019. DoPrefix(cs, _line_);
  1020. Indent(cs, cs->level);
  1021. (void) fprintf(cs->stack->out_file, ">%s\n", cs->func);
  1022. DbugFlush(cs); /* This does a unlock */
  1023. }
  1024. break;
  1025. case DISABLE_TRACE:
  1026. cs->framep->level&= ~TRACE_ON;
  1027. /* fall through */
  1028. case DONT_TRACE:
  1029. break;
  1030. }
  1031. errno=save_errno;
  1032. }
  1033. /*
  1034. * FUNCTION
  1035. *
  1036. * _db_return_ process exit from user function
  1037. *
  1038. * SYNOPSIS
  1039. *
  1040. * VOID _db_return_(_line_, _stack_frame_)
  1041. * int _line_; current source line number
  1042. * struct _db_stack_frame_ allocated on the caller's stack
  1043. *
  1044. * DESCRIPTION
  1045. *
  1046. * Called just before user function executes an explicit or implicit
  1047. * return. Prints a trace line if trace is enabled, decrements
  1048. * the current nesting level, and restores the current function and
  1049. * file names from the defunct function's stack.
  1050. *
  1051. */
  1052. void _db_return_(uint _line_, struct _db_stack_frame_ *_stack_frame_)
  1053. {
  1054. int save_errno=errno;
  1055. uint _slevel_= _stack_frame_->level & ~TRACE_ON;
  1056. CODE_STATE *cs;
  1057. get_code_state_or_return;
  1058. if (cs->framep != _stack_frame_)
  1059. {
  1060. char buf[512];
  1061. my_snprintf(buf, sizeof(buf), ERR_MISSING_RETURN, cs->func);
  1062. DbugExit(buf);
  1063. }
  1064. if (DoTrace(cs) & DO_TRACE)
  1065. {
  1066. if (TRACING)
  1067. {
  1068. if (!cs->locked)
  1069. pthread_mutex_lock(&THR_LOCK_dbug);
  1070. DoPrefix(cs, _line_);
  1071. Indent(cs, cs->level);
  1072. (void) fprintf(cs->stack->out_file, "<%s\n", cs->func);
  1073. DbugFlush(cs);
  1074. }
  1075. }
  1076. /*
  1077. Check to not set level < 0. This can happen if DBUG was disabled when
  1078. function was entered and enabled in function.
  1079. */
  1080. cs->level= _slevel_ != 0 ? _slevel_ - 1 : 0;
  1081. cs->func= _stack_frame_->func;
  1082. cs->file= _stack_frame_->file;
  1083. if (cs->framep != NULL)
  1084. cs->framep= cs->framep->prev;
  1085. errno=save_errno;
  1086. }
  1087. /*
  1088. * FUNCTION
  1089. *
  1090. * _db_pargs_ log arguments for subsequent use by _db_doprnt_()
  1091. *
  1092. * SYNOPSIS
  1093. *
  1094. * VOID _db_pargs_(_line_, keyword)
  1095. * int _line_;
  1096. * char *keyword;
  1097. *
  1098. * DESCRIPTION
  1099. *
  1100. * The new universal printing macro DBUG_PRINT, which replaces
  1101. * all forms of the DBUG_N macros, needs two calls to runtime
  1102. * support routines. The first, this function, remembers arguments
  1103. * that are used by the subsequent call to _db_doprnt_().
  1104. *
  1105. */
  1106. void _db_pargs_(uint _line_, const char *keyword)
  1107. {
  1108. CODE_STATE *cs;
  1109. get_code_state_or_return;
  1110. cs->u_line= _line_;
  1111. cs->u_keyword= keyword;
  1112. }
  1113. /*
  1114. * FUNCTION
  1115. *
  1116. * _db_doprnt_ handle print of debug lines
  1117. *
  1118. * SYNOPSIS
  1119. *
  1120. * VOID _db_doprnt_(format, va_alist)
  1121. * char *format;
  1122. * va_dcl;
  1123. *
  1124. * DESCRIPTION
  1125. *
  1126. * When invoked via one of the DBUG macros, tests the current keyword
  1127. * set by calling _db_pargs_() to see if that macro has been selected
  1128. * for processing via the debugger control string, and if so, handles
  1129. * printing of the arguments via the format string. The line number
  1130. * of the DBUG macro in the source is found in u_line.
  1131. *
  1132. * Note that the format string SHOULD NOT include a terminating
  1133. * newline, this is supplied automatically.
  1134. *
  1135. */
  1136. #include <stdarg.h>
  1137. void _db_doprnt_(const char *format,...)
  1138. {
  1139. va_list args;
  1140. CODE_STATE *cs;
  1141. get_code_state_or_return;
  1142. va_start(args,format);
  1143. if (_db_keyword_(cs, cs->u_keyword, 0))
  1144. {
  1145. int save_errno=errno;
  1146. if (!cs->locked)
  1147. pthread_mutex_lock(&THR_LOCK_dbug);
  1148. DoPrefix(cs, cs->u_line);
  1149. if (TRACING)
  1150. Indent(cs, cs->level + 1);
  1151. else
  1152. (void) fprintf(cs->stack->out_file, "%s: ", cs->func);
  1153. (void) fprintf(cs->stack->out_file, "%s: ", cs->u_keyword);
  1154. DbugVfprintf(cs->stack->out_file, format, args);
  1155. DbugFlush(cs);
  1156. errno=save_errno;
  1157. }
  1158. va_end(args);
  1159. }
  1160. /*
  1161. * This function is intended as a
  1162. * vfprintf clone with consistent, platform independent output for
  1163. * problematic formats like %p, %zd and %lld.
  1164. */
  1165. static void DbugVfprintf(FILE *stream, const char* format, va_list args)
  1166. {
  1167. char cvtbuf[1024];
  1168. (void) my_vsnprintf(cvtbuf, sizeof(cvtbuf), format, args);
  1169. (void) fprintf(stream, "%s\n", cvtbuf);
  1170. }
  1171. /*
  1172. * FUNCTION
  1173. *
  1174. * _db_dump_ dump a string in hex
  1175. *
  1176. * SYNOPSIS
  1177. *
  1178. * void _db_dump_(_line_,keyword,memory,length)
  1179. * int _line_; current source line number
  1180. * char *keyword;
  1181. * char *memory; Memory to print
  1182. * int length; Bytes to print
  1183. *
  1184. * DESCRIPTION
  1185. * Dump N characters in a binary array.
  1186. * Is used to examine corrupted memory or arrays.
  1187. */
  1188. void _db_dump_(uint _line_, const char *keyword,
  1189. const unsigned char *memory, size_t length)
  1190. {
  1191. int pos;
  1192. CODE_STATE *cs;
  1193. get_code_state_or_return;
  1194. if (_db_keyword_(cs, keyword, 0))
  1195. {
  1196. if (!cs->locked)
  1197. pthread_mutex_lock(&THR_LOCK_dbug);
  1198. DoPrefix(cs, _line_);
  1199. if (TRACING)
  1200. {
  1201. Indent(cs, cs->level + 1);
  1202. pos= min(max(cs->level-cs->stack->sub_level,0)*INDENT,80);
  1203. }
  1204. else
  1205. {
  1206. fprintf(cs->stack->out_file, "%s: ", cs->func);
  1207. }
  1208. (void) fprintf(cs->stack->out_file, "%s: Memory: 0x%lx Bytes: (%ld)\n",
  1209. keyword, (ulong) memory, (long) length);
  1210. pos=0;
  1211. while (length-- > 0)
  1212. {
  1213. uint tmp= *((unsigned char*) memory++);
  1214. if ((pos+=3) >= 80)
  1215. {
  1216. fputc('\n',cs->stack->out_file);
  1217. pos=3;
  1218. }
  1219. fputc(_dig_vec_upper[((tmp >> 4) & 15)], cs->stack->out_file);
  1220. fputc(_dig_vec_upper[tmp & 15], cs->stack->out_file);
  1221. fputc(' ',cs->stack->out_file);
  1222. }
  1223. (void) fputc('\n',cs->stack->out_file);
  1224. DbugFlush(cs);
  1225. }
  1226. }
  1227. /*
  1228. * FUNCTION
  1229. *
  1230. * ListAddDel modify the list according to debug control string
  1231. *
  1232. * DESCRIPTION
  1233. *
  1234. * Given pointer to a comma separated list of strings in "cltp",
  1235. * parses the list, and modifies "listp", returning a pointer
  1236. * to the new list.
  1237. *
  1238. * The mode of operation is defined by "todo" parameter.
  1239. *
  1240. * If it is INCLUDE, elements (strings from "cltp") are added to the
  1241. * list, they will have INCLUDE flag set. If the list already contains
  1242. * the string in question, new element is not added, but a flag of
  1243. * the existing element is adjusted (INCLUDE bit is set, EXCLUDE bit
  1244. * is removed).
  1245. *
  1246. * If it is EXCLUDE, elements are added to the list with the EXCLUDE
  1247. * flag set. If the list already contains the string in question,
  1248. * it is removed, new element is not added.
  1249. */
  1250. static struct link *ListAddDel(struct link *head, const char *ctlp,
  1251. const char *end, int todo)
  1252. {
  1253. const char *start;
  1254. struct link **cur;
  1255. size_t len;
  1256. int subdir;
  1257. ctlp--;
  1258. next:
  1259. while (++ctlp < end)
  1260. {
  1261. start= ctlp;
  1262. subdir=0;
  1263. while (ctlp < end && *ctlp != ',')
  1264. ctlp++;
  1265. len=ctlp-start;
  1266. if (start[len-1] == '/')
  1267. {
  1268. len--;
  1269. subdir=SUBDIR;
  1270. }
  1271. if (len == 0) continue;
  1272. for (cur=&head; *cur; cur=&((*cur)->next_link))
  1273. {
  1274. if (!strncmp((*cur)->str, start, len))
  1275. {
  1276. if ((*cur)->flags & todo) /* same action ? */
  1277. (*cur)->flags|= subdir; /* just merge the SUBDIR flag */
  1278. else if (todo == EXCLUDE)
  1279. {
  1280. struct link *delme=*cur;
  1281. *cur=(*cur)->next_link;
  1282. free((void*) delme);
  1283. }
  1284. else
  1285. {
  1286. (*cur)->flags&=~(EXCLUDE & SUBDIR);
  1287. (*cur)->flags|=INCLUDE | subdir;
  1288. }
  1289. goto next;
  1290. }
  1291. }
  1292. *cur= (struct link *) DbugMalloc(sizeof(struct link)+len);
  1293. memcpy((*cur)->str, start, len);
  1294. (*cur)->str[len]=0;
  1295. (*cur)->flags=todo | subdir;
  1296. (*cur)->next_link=0;
  1297. }
  1298. return head;
  1299. }
  1300. /*
  1301. * FUNCTION
  1302. *
  1303. * ListCopy make a copy of the list
  1304. *
  1305. * SYNOPSIS
  1306. *
  1307. * static struct link *ListCopy(orig)
  1308. * struct link *orig;
  1309. *
  1310. * DESCRIPTION
  1311. *
  1312. * Given pointer to list, which contains a copy of every element from
  1313. * the original list.
  1314. *
  1315. * the orig pointer can be NULL
  1316. *
  1317. * Note that since each link is added at the head of the list,
  1318. * the final list will be in "reverse order", which is not
  1319. * significant for our usage here.
  1320. *
  1321. */
  1322. static struct link *ListCopy(struct link *orig)
  1323. {
  1324. struct link *new_malloc;
  1325. struct link *head;
  1326. size_t len;
  1327. head= NULL;
  1328. while (orig != NULL)
  1329. {
  1330. len= strlen(orig->str);
  1331. new_malloc= (struct link *) DbugMalloc(sizeof(struct link)+len);
  1332. memcpy(new_malloc->str, orig->str, len);
  1333. new_malloc->str[len]= 0;
  1334. new_malloc->flags=orig->flags;
  1335. new_malloc->next_link= head;
  1336. head= new_malloc;
  1337. orig= orig->next_link;
  1338. }
  1339. return head;
  1340. }
  1341. /*
  1342. * FUNCTION
  1343. *
  1344. * InList test a given string for member of a given list
  1345. *
  1346. * DESCRIPTION
  1347. *
  1348. * Tests the string pointed to by "cp" to determine if it is in
  1349. * the list pointed to by "linkp". Linkp points to the first
  1350. * link in the list. If linkp is NULL or contains only EXCLUDE
  1351. * elements then the string is treated as if it is in the list.
  1352. * This may seem rather strange at first but leads to the desired
  1353. * operation if no list is given. The net effect is that all
  1354. * strings will be accepted when there is no list, and when there
  1355. * is a list, only those strings in the list will be accepted.
  1356. *
  1357. * RETURN
  1358. * combination of SUBDIR, INCLUDE, EXCLUDE, MATCHED flags
  1359. *
  1360. */
  1361. static int InList(struct link *linkp, const char *cp)
  1362. {
  1363. int result;
  1364. for (result=MATCHED; linkp != NULL; linkp= linkp->next_link)
  1365. {
  1366. if (!fnmatch(linkp->str, cp, 0))
  1367. return linkp->flags;
  1368. if (!(linkp->flags & EXCLUDE))
  1369. result=NOT_MATCHED;
  1370. if (linkp->flags & SUBDIR)
  1371. result|=SUBDIR;
  1372. }
  1373. return result;
  1374. }
  1375. /*
  1376. * FUNCTION
  1377. *
  1378. * ListFlags returns aggregated list flags (ORed over all elements)
  1379. *
  1380. */
  1381. static uint ListFlags(struct link *linkp)
  1382. {
  1383. uint f;
  1384. for (f=0; linkp != NULL; linkp= linkp->next_link)
  1385. f|= linkp->flags;
  1386. return f;
  1387. }
  1388. /*
  1389. * FUNCTION
  1390. *
  1391. * PushState push current settings onto stack and set up new one
  1392. *
  1393. * SYNOPSIS
  1394. *
  1395. * static VOID PushState()
  1396. *
  1397. * DESCRIPTION
  1398. *
  1399. * Pushes the current settings on the settings stack, and creates
  1400. * a new settings. The new settings is NOT initialized
  1401. *
  1402. * The settings stack is a linked list of settings, with the new
  1403. * settings added at the head. This allows the stack to grow
  1404. * to the limits of memory if necessary.
  1405. *
  1406. */
  1407. static void PushState(CODE_STATE *cs)
  1408. {
  1409. struct settings *new_malloc;
  1410. new_malloc= (struct settings *) DbugMalloc(sizeof(struct settings));
  1411. bzero(new_malloc, sizeof(struct settings));
  1412. new_malloc->next= cs->stack;
  1413. cs->stack= new_malloc;
  1414. }
  1415. /*
  1416. * FUNCTION
  1417. *
  1418. * FreeState Free memory associated with a struct state.
  1419. *
  1420. * SYNOPSIS
  1421. *
  1422. * static void FreeState (state)
  1423. * struct state *state;
  1424. * int free_state;
  1425. *
  1426. * DESCRIPTION
  1427. *
  1428. * Deallocates the memory allocated for various information in a
  1429. * state. If free_state is set, also free 'state'
  1430. *
  1431. */
  1432. static void FreeState(CODE_STATE *cs, struct settings *state, int free_state)
  1433. {
  1434. if (!is_shared(state, keywords))
  1435. FreeList(state->keywords);
  1436. if (!is_shared(state, functions))
  1437. FreeList(state->functions);
  1438. if (!is_shared(state, processes))
  1439. FreeList(state->processes);
  1440. if (!is_shared(state, p_functions))
  1441. FreeList(state->p_functions);
  1442. if (!is_shared(state, out_file))
  1443. DBUGCloseFile(cs, state->out_file);
  1444. else
  1445. (void) fflush(state->out_file);
  1446. if (!is_shared(state, prof_file))
  1447. DBUGCloseFile(cs, state->prof_file);
  1448. else
  1449. (void) fflush(state->prof_file);
  1450. if (free_state)
  1451. free((void*) state);
  1452. }
  1453. /*
  1454. * FUNCTION
  1455. *
  1456. * _db_end_ End debugging, freeing state stack memory.
  1457. *
  1458. * SYNOPSIS
  1459. *
  1460. * static VOID _db_end_ ()
  1461. *
  1462. * DESCRIPTION
  1463. *
  1464. * Ends debugging, de-allocating the memory allocated to the
  1465. * state stack.
  1466. *
  1467. * To be called at the very end of the program.
  1468. *
  1469. */
  1470. void _db_end_()
  1471. {
  1472. struct settings *discard;
  1473. static struct settings tmp;
  1474. CODE_STATE *cs;
  1475. /*
  1476. Set _dbug_on_ to be able to do full reset even when DEBUGGER_OFF was
  1477. called after dbug was initialized
  1478. */
  1479. _dbug_on_= 1;
  1480. get_code_state_or_return;
  1481. while ((discard= cs->stack))
  1482. {
  1483. if (discard == &init_settings)
  1484. break;
  1485. cs->stack= discard->next;
  1486. FreeState(cs, discard, 1);
  1487. }
  1488. tmp= init_settings;
  1489. /* Use mutex lock to make it less likely anyone access out_file */
  1490. pthread_mutex_lock(&THR_LOCK_dbug);
  1491. init_settings.flags= OPEN_APPEND;
  1492. init_settings.out_file= stderr;
  1493. init_settings.prof_file= stderr;
  1494. init_settings.maxdepth= 0;
  1495. init_settings.delay= 0;
  1496. init_settings.sub_level= 0;
  1497. init_settings.functions= 0;
  1498. init_settings.p_functions= 0;
  1499. init_settings.keywords= 0;
  1500. init_settings.processes= 0;
  1501. pthread_mutex_unlock(&THR_LOCK_dbug);
  1502. FreeState(cs, &tmp, 0);
  1503. }
  1504. /*
  1505. * FUNCTION
  1506. *
  1507. * DoTrace check to see if tracing is current enabled
  1508. *
  1509. * DESCRIPTION
  1510. *
  1511. * Checks to see if dbug in this function is enabled based on
  1512. * whether the maximum trace depth has been reached, the current
  1513. * function is selected, and the current process is selected.
  1514. *
  1515. */
  1516. static int DoTrace(CODE_STATE *cs)
  1517. {
  1518. if ((cs->stack->maxdepth == 0 || cs->level <= cs->stack->maxdepth) &&
  1519. InList(cs->stack->processes, cs->process) & (MATCHED|INCLUDE))
  1520. switch(InList(cs->stack->functions, cs->func)) {
  1521. case INCLUDE|SUBDIR: return ENABLE_TRACE;
  1522. case INCLUDE: return DO_TRACE;
  1523. case MATCHED|SUBDIR:
  1524. case NOT_MATCHED|SUBDIR:
  1525. case MATCHED: return framep_trace_flag(cs, cs->framep) ?
  1526. DO_TRACE : DONT_TRACE;
  1527. case EXCLUDE:
  1528. case NOT_MATCHED: return DONT_TRACE;
  1529. case EXCLUDE|SUBDIR: return DISABLE_TRACE;
  1530. }
  1531. return DONT_TRACE;
  1532. }
  1533. FILE *_db_fp_(void)
  1534. {
  1535. CODE_STATE *cs;
  1536. get_code_state_or_return NULL;
  1537. return cs->stack->out_file;
  1538. }
  1539. /*
  1540. * FUNCTION
  1541. *
  1542. * _db_keyword_ test keyword for member of keyword list
  1543. *
  1544. * DESCRIPTION
  1545. *
  1546. * Test a keyword to determine if it is in the currently active
  1547. * keyword list. If strict=0, a keyword is accepted
  1548. * if the list is null, otherwise it must match one of the list
  1549. * members. When debugging is not on, no keywords are accepted.
  1550. * After the maximum trace level is exceeded, no keywords are
  1551. * accepted (this behavior subject to change). Additionally,
  1552. * the current function and process must be accepted based on
  1553. * their respective lists.
  1554. *
  1555. * Returns TRUE if keyword accepted, FALSE otherwise.
  1556. *
  1557. */
  1558. BOOLEAN _db_keyword_(CODE_STATE *cs, const char *keyword, int strict)
  1559. {
  1560. get_code_state_if_not_set_or_return FALSE;
  1561. strict=strict ? INCLUDE : INCLUDE|MATCHED;
  1562. return DEBUGGING && DoTrace(cs) & DO_TRACE &&
  1563. InList(cs->stack->keywords, keyword) & strict;
  1564. }
  1565. /*
  1566. * FUNCTION
  1567. *
  1568. * Indent indent a line to the given indentation level
  1569. *
  1570. * SYNOPSIS
  1571. *
  1572. * static VOID Indent(indent)
  1573. * int indent;
  1574. *
  1575. * DESCRIPTION
  1576. *
  1577. * Indent a line to the given level. Note that this is
  1578. * a simple minded but portable implementation.
  1579. * There are better ways.
  1580. *
  1581. * Also, the indent must be scaled by the compile time option
  1582. * of character positions per nesting level.
  1583. *
  1584. */
  1585. static void Indent(CODE_STATE *cs, int indent)
  1586. {
  1587. REGISTER int count;
  1588. indent= max(indent-1-cs->stack->sub_level,0)*INDENT;
  1589. for (count= 0; count < indent ; count++)
  1590. {
  1591. if ((count % INDENT) == 0)
  1592. fputc('|',cs->stack->out_file);
  1593. else
  1594. fputc(' ',cs->stack->out_file);
  1595. }
  1596. }
  1597. /*
  1598. * FUNCTION
  1599. *
  1600. * FreeList free all memory associated with a linked list
  1601. *
  1602. * SYNOPSIS
  1603. *
  1604. * static VOID FreeList(linkp)
  1605. * struct link *linkp;
  1606. *
  1607. * DESCRIPTION
  1608. *
  1609. * Given pointer to the head of a linked list, frees all
  1610. * memory held by the list and the members of the list.
  1611. *
  1612. */
  1613. static void FreeList(struct link *linkp)
  1614. {
  1615. REGISTER struct link *old;
  1616. while (linkp != NULL)
  1617. {
  1618. old= linkp;
  1619. linkp= linkp->next_link;
  1620. free((void*) old);
  1621. }
  1622. }
  1623. /*
  1624. * FUNCTION
  1625. *
  1626. * DoPrefix print debugger line prefix prior to indentation
  1627. *
  1628. * SYNOPSIS
  1629. *
  1630. * static VOID DoPrefix(_line_)
  1631. * int _line_;
  1632. *
  1633. * DESCRIPTION
  1634. *
  1635. * Print prefix common to all debugger output lines, prior to
  1636. * doing indentation if necessary. Print such information as
  1637. * current process name, current source file name and line number,
  1638. * and current function nesting depth.
  1639. *
  1640. */
  1641. static void DoPrefix(CODE_STATE *cs, uint _line_)
  1642. {
  1643. cs->lineno++;
  1644. if (cs->stack->flags & PID_ON)
  1645. {
  1646. (void) fprintf(cs->stack->out_file, "%-7s: ", my_thread_name());
  1647. }
  1648. if (cs->stack->flags & NUMBER_ON)
  1649. (void) fprintf(cs->stack->out_file, "%5d: ", cs->lineno);
  1650. if (cs->stack->flags & TIMESTAMP_ON)
  1651. {
  1652. #ifdef __WIN__
  1653. /* FIXME This doesn't give microseconds as in Unix case, and the resolution is
  1654. in system ticks, 10 ms intervals. See my_getsystime.c for high res */
  1655. SYSTEMTIME loc_t;
  1656. GetLocalTime(&loc_t);
  1657. (void) fprintf (cs->stack->out_file,
  1658. /* "%04d-%02d-%02d " */
  1659. "%02d:%02d:%02d.%06d ",
  1660. /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
  1661. loc_t.wHour, loc_t.wMinute, loc_t.wSecond, loc_t.wMilliseconds);
  1662. #else
  1663. struct timeval tv;
  1664. struct tm *tm_p;
  1665. if (gettimeofday(&tv, NULL) != -1)
  1666. {
  1667. if ((tm_p= localtime((const time_t *)&tv.tv_sec)))
  1668. {
  1669. (void) fprintf (cs->stack->out_file,
  1670. /* "%04d-%02d-%02d " */
  1671. "%02d:%02d:%02d.%06d ",
  1672. /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
  1673. tm_p->tm_hour, tm_p->tm_min, tm_p->tm_sec,
  1674. (int) (tv.tv_usec));
  1675. }
  1676. }
  1677. #endif
  1678. }
  1679. if (cs->stack->flags & PROCESS_ON)
  1680. (void) fprintf(cs->stack->out_file, "%s: ", cs->process);
  1681. if (cs->stack->flags & FILE_ON)
  1682. (void) fprintf(cs->stack->out_file, "%14s: ", BaseName(cs->file));
  1683. if (cs->stack->flags & LINE_ON)
  1684. (void) fprintf(cs->stack->out_file, "%5d: ", _line_);
  1685. if (cs->stack->flags & DEPTH_ON)
  1686. (void) fprintf(cs->stack->out_file, "%4d: ", cs->level);
  1687. }
  1688. /*
  1689. * FUNCTION
  1690. *
  1691. * DBUGOpenFile open new output stream for debugger output
  1692. *
  1693. * SYNOPSIS
  1694. *
  1695. * static VOID DBUGOpenFile(name)
  1696. * char *name;
  1697. *
  1698. * DESCRIPTION
  1699. *
  1700. * Given name of a new file (or "-" for stdout) opens the file
  1701. * and sets the output stream to the new file.
  1702. *
  1703. */
  1704. static void DBUGOpenFile(CODE_STATE *cs,
  1705. const char *name,const char *end,int append)
  1706. {
  1707. REGISTER FILE *fp;
  1708. if (name != NULL)
  1709. {
  1710. if (end)
  1711. {
  1712. size_t len=end-name;
  1713. memcpy(cs->stack->name, name, len);
  1714. cs->stack->name[len]=0;
  1715. }
  1716. else
  1717. strmov(cs->stack->name,name);
  1718. name=cs->stack->name;
  1719. if (strcmp(name, "-") == 0)
  1720. {
  1721. cs->stack->out_file= stdout;
  1722. cs->stack->flags |= FLUSH_ON_WRITE;
  1723. cs->stack->name[0]=0;
  1724. }
  1725. else
  1726. {
  1727. if (!Writable(name))
  1728. {
  1729. (void) fprintf(stderr, ERR_OPEN, cs->process, name);
  1730. perror("");
  1731. fflush(stderr);
  1732. }
  1733. else
  1734. {
  1735. if (!(fp= fopen(name, append ? "a+" : "w")))
  1736. {
  1737. (void) fprintf(stderr, ERR_OPEN, cs->process, name);
  1738. perror("");
  1739. fflush(stderr);
  1740. }
  1741. else
  1742. {
  1743. cs->stack->out_file= fp;
  1744. }
  1745. }
  1746. }
  1747. }
  1748. }
  1749. /*
  1750. * FUNCTION
  1751. *
  1752. * DBUGCloseFile close the debug output stream
  1753. *
  1754. * SYNOPSIS
  1755. *
  1756. * static VOID DBUGCloseFile(fp)
  1757. * FILE *fp;
  1758. *
  1759. * DESCRIPTION
  1760. *
  1761. * Closes the debug output stream unless it is standard output
  1762. * or standard error.
  1763. *
  1764. */
  1765. static void DBUGCloseFile(CODE_STATE *cs, FILE *fp)
  1766. {
  1767. if (fp != NULL && fp != stderr && fp != stdout && fclose(fp) == EOF)
  1768. {
  1769. pthread_mutex_lock(&THR_LOCK_dbug);
  1770. (void) fprintf(cs->stack->out_file, ERR_CLOSE, cs->process);
  1771. perror("");
  1772. DbugFlush(cs);
  1773. }
  1774. }
  1775. /*
  1776. * FUNCTION
  1777. *
  1778. * DbugExit print error message and exit
  1779. *
  1780. * SYNOPSIS
  1781. *
  1782. * static VOID DbugExit(why)
  1783. * char *why;
  1784. *
  1785. * DESCRIPTION
  1786. *
  1787. * Prints error message using current process name, the reason for
  1788. * aborting (typically out of memory), and exits with status 1.
  1789. * This should probably be changed to use a status code
  1790. * defined in the user's debugger include file.
  1791. *
  1792. */
  1793. static void DbugExit(const char *why)
  1794. {
  1795. CODE_STATE *cs=code_state();
  1796. (void) fprintf(stderr, ERR_ABORT, cs ? cs->process : "(null)", why);
  1797. (void) fflush(stderr);
  1798. DBUG_ABORT();
  1799. }
  1800. /*
  1801. * FUNCTION
  1802. *
  1803. * DbugMalloc allocate memory for debugger runtime support
  1804. *
  1805. * SYNOPSIS
  1806. *
  1807. * static long *DbugMalloc(size)
  1808. * int size;
  1809. *
  1810. * DESCRIPTION
  1811. *
  1812. * Allocate more memory for debugger runtime support functions.
  1813. * Failure to to allocate the requested number of bytes is
  1814. * immediately fatal to the current process. This may be
  1815. * rather unfriendly behavior. It might be better to simply
  1816. * print a warning message, freeze the current debugger cs,
  1817. * and continue execution.
  1818. *
  1819. */
  1820. static char *DbugMalloc(size_t size)
  1821. {
  1822. register char *new_malloc;
  1823. if (!(new_malloc= (char*) malloc(size)))
  1824. DbugExit("out of memory");
  1825. return new_malloc;
  1826. }
  1827. /*
  1828. * strtok lookalike - splits on ':', magically handles ::, :\ and :/
  1829. */
  1830. static const char *DbugStrTok(const char *s)
  1831. {
  1832. while (s[0] && (s[0] != ':' ||
  1833. (s[1] == '\\' || s[1] == '/' || (s[1] == ':' && s++))))
  1834. s++;
  1835. return s;
  1836. }
  1837. /*
  1838. * FUNCTION
  1839. *
  1840. * BaseName strip leading pathname components from name
  1841. *
  1842. * SYNOPSIS
  1843. *
  1844. * static char *BaseName(pathname)
  1845. * char *pathname;
  1846. *
  1847. * DESCRIPTION
  1848. *
  1849. * Given pointer to a complete pathname, locates the base file
  1850. * name at the end of the pathname and returns a pointer to
  1851. * it.
  1852. *
  1853. */
  1854. static const char *BaseName(const char *pathname)
  1855. {
  1856. register const char *base;
  1857. base= strrchr(pathname, FN_LIBCHAR);
  1858. if (base++ == NullS)
  1859. base= pathname;
  1860. return base;
  1861. }
  1862. /*
  1863. * FUNCTION
  1864. *
  1865. * Writable test to see if a pathname is writable/creatable
  1866. *
  1867. * SYNOPSIS
  1868. *
  1869. * static BOOLEAN Writable(pathname)
  1870. * char *pathname;
  1871. *
  1872. * DESCRIPTION
  1873. *
  1874. * Because the debugger might be linked in with a program that
  1875. * runs with the set-uid-bit (suid) set, we have to be careful
  1876. * about opening a user named file for debug output. This consists
  1877. * of checking the file for write access with the real user id,
  1878. * or checking the directory where the file will be created.
  1879. *
  1880. * Returns TRUE if the user would normally be allowed write or
  1881. * create access to the named file. Returns FALSE otherwise.
  1882. *
  1883. */
  1884. #ifndef Writable
  1885. static BOOLEAN Writable(const char *pathname)
  1886. {
  1887. REGISTER BOOLEAN granted;
  1888. REGISTER char *lastslash;
  1889. granted= FALSE;
  1890. if (EXISTS(pathname))
  1891. {
  1892. if (WRITABLE(pathname))
  1893. granted= TRUE;
  1894. }
  1895. else
  1896. {
  1897. lastslash= strrchr(pathname, '/');
  1898. if (lastslash != NULL)
  1899. *lastslash= '\0';
  1900. else
  1901. pathname= ".";
  1902. if (WRITABLE(pathname))
  1903. granted= TRUE;
  1904. if (lastslash != NULL)
  1905. *lastslash= '/';
  1906. }
  1907. return granted;
  1908. }
  1909. #endif
  1910. /*
  1911. * FUNCTION
  1912. *
  1913. * _db_setjmp_ save debugger environment
  1914. *
  1915. * SYNOPSIS
  1916. *
  1917. * VOID _db_setjmp_()
  1918. *
  1919. * DESCRIPTION
  1920. *
  1921. * Invoked as part of the user's DBUG_SETJMP macro to save
  1922. * the debugger environment in parallel with saving the user's
  1923. * environment.
  1924. *
  1925. */
  1926. #ifdef HAVE_LONGJMP
  1927. EXPORT void _db_setjmp_()
  1928. {
  1929. CODE_STATE *cs;
  1930. get_code_state_or_return;
  1931. cs->jmplevel= cs->level;
  1932. cs->jmpfunc= cs->func;
  1933. cs->jmpfile= cs->file;
  1934. }
  1935. /*
  1936. * FUNCTION
  1937. *
  1938. * _db_longjmp_ restore previously saved debugger environment
  1939. *
  1940. * SYNOPSIS
  1941. *
  1942. * VOID _db_longjmp_()
  1943. *
  1944. * DESCRIPTION
  1945. *
  1946. * Invoked as part of the user's DBUG_LONGJMP macro to restore
  1947. * the debugger environment in parallel with restoring the user's
  1948. * previously saved environment.
  1949. *
  1950. */
  1951. EXPORT void _db_longjmp_()
  1952. {
  1953. CODE_STATE *cs;
  1954. get_code_state_or_return;
  1955. cs->level= cs->jmplevel;
  1956. if (cs->jmpfunc)
  1957. cs->func= cs->jmpfunc;
  1958. if (cs->jmpfile)
  1959. cs->file= cs->jmpfile;
  1960. }
  1961. #endif
  1962. /*
  1963. * FUNCTION
  1964. *
  1965. * perror perror simulation for systems that don't have it
  1966. *
  1967. * SYNOPSIS
  1968. *
  1969. * static VOID perror(s)
  1970. * char *s;
  1971. *
  1972. * DESCRIPTION
  1973. *
  1974. * Perror produces a message on the standard error stream which
  1975. * provides more information about the library or system error
  1976. * just encountered. The argument string s is printed, followed
  1977. * by a ':', a blank, and then a message and a newline.
  1978. *
  1979. * An undocumented feature of the unix perror is that if the string
  1980. * 's' is a null string (NOT a NULL pointer!), then the ':' and
  1981. * blank are not printed.
  1982. *
  1983. * This version just complains about an "unknown system error".
  1984. *
  1985. */
  1986. #ifndef HAVE_PERROR
  1987. static void perror(s)
  1988. char *s;
  1989. {
  1990. if (s && *s != '\0')
  1991. (void) fprintf(stderr, "%s: ", s);
  1992. (void) fprintf(stderr, "<unknown system error>\n");
  1993. }
  1994. #endif /* HAVE_PERROR */
  1995. /* flush dbug-stream, free mutex lock & wait delay */
  1996. /* This is because some systems (MSDOS!!) dosn't flush fileheader */
  1997. /* and dbug-file isn't readable after a system crash !! */
  1998. static void DbugFlush(CODE_STATE *cs)
  1999. {
  2000. if (cs->stack->flags & FLUSH_ON_WRITE)
  2001. {
  2002. (void) fflush(cs->stack->out_file);
  2003. if (cs->stack->delay)
  2004. (void) Delay(cs->stack->delay);
  2005. }
  2006. if (!cs->locked)
  2007. pthread_mutex_unlock(&THR_LOCK_dbug);
  2008. } /* DbugFlush */
  2009. /* For debugging */
  2010. void _db_flush_()
  2011. {
  2012. CODE_STATE *cs= NULL;
  2013. get_code_state_or_return;
  2014. (void) fflush(cs->stack->out_file);
  2015. }
  2016. #ifndef __WIN__
  2017. void _db_suicide_()
  2018. {
  2019. int retval;
  2020. sigset_t new_mask;
  2021. sigfillset(&new_mask);
  2022. fprintf(stderr, "SIGKILL myself\n");
  2023. fflush(stderr);
  2024. retval= kill(getpid(), SIGKILL);
  2025. assert(retval == 0);
  2026. retval= sigsuspend(&new_mask);
  2027. fprintf(stderr, "sigsuspend returned %d errno %d \n", retval, errno);
  2028. assert(FALSE); /* With full signal mask, we should never return here. */
  2029. }
  2030. #endif /* ! __WIN__ */
  2031. void _db_lock_file_()
  2032. {
  2033. CODE_STATE *cs;
  2034. get_code_state_or_return;
  2035. pthread_mutex_lock(&THR_LOCK_dbug);
  2036. cs->locked=1;
  2037. }
  2038. void _db_unlock_file_()
  2039. {
  2040. CODE_STATE *cs;
  2041. get_code_state_or_return;
  2042. cs->locked=0;
  2043. pthread_mutex_unlock(&THR_LOCK_dbug);
  2044. }
  2045. const char* _db_get_func_(void)
  2046. {
  2047. CODE_STATE *cs;
  2048. get_code_state_or_return NULL;
  2049. return cs->func;
  2050. }
  2051. #else
  2052. /*
  2053. * Dummy function, workaround for MySQL bug#14420 related
  2054. * build failure on a platform where linking with an empty
  2055. * archive fails.
  2056. *
  2057. * This block can be removed as soon as a fix for bug#14420
  2058. * is implemented.
  2059. */
  2060. int i_am_a_dummy_function() {
  2061. return 0;
  2062. }
  2063. #endif