A Tale of Two Bugs
Sunday, May 25th, 2008It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the age of bug-hunting!
Recently I fixed 2 bugs, yeah, I know I spent a lot of time fixing bugs but this 2 were quite interesting to me, not because of the bugs itself, but rather because of some stuff I learned in the process like the implementation of variadic functions and how the C++ compiler optimizes certain stuff unveiling odd bugs.
Bug 1
Let’s analyze the first one, it was a bug I had with some Unicall R2 installation in 64 bits. The problem was simple, as soon as I loaded chan_unicall.so Asterisk crashed ![]()
After running Asterisk with gdb I found the crash happened inside libc function strlen that was being called by uc_log(), the Unicall logging function. As most logging C functions, uc_log is a variadic function. uc_log does not do any complicated stuff, is mostly just a wrapper to vsnprintf and the variable arguments were just passed on to vsnprintf and there the crash was occurring, so, how can one see the arguments a variadic function receives using gdb? First, one must know how variadic functions are implemented by the compiler and platform you are working on.
Most common implementation of variadic functions in C is just to define va_list as an unsigned char* pointing to the last argument of the function and each call to va_arg() retrieves the next chunk of memory of the specified size and increment va_list to point to the start of the next argument, therefore, displaying arguments is just matter of printing the memory area after the last argument. However, AMD64 has a different implementation, va_list is an array of 1 structure with members:
.gp_offset
.fp_offset
.overflow_arg_area
.reg_save_area
gp_offset is how many bytes after reg_save_area the first argument is. To print the first variable argument that we know is an “int” we do:
(gdb) p *(int *)(((char *)arg_ptr[0].reg_save_area)+arg_ptr[0].gp_offset)
however, gp_offset will be only incremented after calling va_arg() macro, if you want to see more arguments you must increment reg_save_area by the number of bytes you know arguments take, in the case of uc_log, initial value of gp_offset is 24, probably because it receive 3 fixed arguments (8 bytes * 3). So, the first variable argument starts at .reg_save_area + 24, the second at .reg_save_area + 32 (we’re in a 64 bit machine).
So, what about .fp_offset and .overflow_arg_area?, well, it seems .reg_save_area is quite limited (possibly limited by the number of the processor registers) and you can never go beyond .gp_offset == 40, therefore that will only work for up to 6 arguments (including the fixed ones). .overflow_arg_area is used for any subsequent argument and .fp_offset is the pointer to the next argument on that memory area. Well, that’s enough, let’s get straight to the point, the crash was caused because unicall.h include the following prototype:
extern const char *uc_statet2str(int state);
That function returned the value passed to uc_log(…., uc_state2str()) … so what’s the issue? well, read once again the prototype and how uc_log used it. Is not a typo here in my blog, the prototype really is uc_statet2str, and the function call is uc_state2str, indeed there is a typo in the header file causing the compiler to default to the return value “int” and not const char* when compiling libmfcr2, for 64 bit platform there is 4 bytes of difference between char* and int causing a crash due to invalid memory read.
Bug 2
This one is easier to explain with a chunk of code, can you tell what’s wrong with it and what possible outputs will have when running it as “./test t”?
#include <stdio.h> #include <string.h> #define SIZE 100 int main(int argc, char *argv[]) { char *bufptr = NULL; if (argc == 2) { char inblock_buff[SIZE]; bufptr = inblock_buff; strcpy(bufptr, “some buffer”); } printf(“buffer: %sn”, bufptr); if (argc == 2 && argv[1][0] == ‘t’) { char otherbuff[SIZE]; otherbuff[0] = 0; } printf(“buffer: %sn”, bufptr); return 0; }
Indeed, the output will depend on how you compile it and even probably will depend on the compiler implementation? The thing is, that if you compile this code in Linux with gcc 4.1.2 as gcc -O2 bug.c -o bug, and then run it as ./bug t
The output is:
buffer: some buffer
buffer: some buffer
But, compiling without optimizations gcc -O0 bug.c -o bug the output is:
buffer: some buffer
buffer:
When the second if() block is optimized-out the value of the block variable inblock_buff is not overwritten and therefore bufptr remains pointing to “some buffer” and the code seems to “work”, but when -O0 the second if() block is not optimized and the bug arise, bufptr will point to char 0 printing nothing. In my particular case this buffer was the input of the keyboard of a 5250 session, hence, in some cases the keyboard input was just ignored.Paregoric
Bad side effects of viagra
Phentermine sale
Thiphenamil
Phentermine in the uk
Mesalamine
Generic cialis online
Adipex p phentermine
Meridia weight loss pill
Lincomycin
Online consultations and prescriptions phentermine
Xanax anxiety relief pills order here
Natural viagra substitutes
Generic cialis price
Cheap phentermine no prescription
Taking xanax while pregnant
Sulindac
Xanax xr 3 mg
Prozac soma
Tramadol narcotic
Phendimetrazine versus phentermine
Carteolol
Mivial valve prolapse viagra
Glucotrol
Free viagra without a perscription
Cialis drug impotence
Norethindrone
Capoten
Generic cialis india
Does phentermine speed up metabolism
Aminophylline
Pal pay phentermine
Flavoxate
Mail order viagra
Xanax dosage
Buy viagra online
Viagra and levivia
Guanethidine
Phentermine 180
Viagra results
Phentermine 37.5 no prescription
Methantheline
Fluvastatin
Celiprolol
Buy cialis in uk
Ecotrin
Discount online viagra
Low cost phentermine
Accutane
Natural supplement for viagra
Canada generic viagra
Dovonex
Long term side effects of phentermine
Gemfibrozil
Vicodin picture
Phentermine by cod
Liothyronine
Nitroglycerin
Mexican pharmacy viagra
Xanax prescription online
Xanax online cheap
Enoxacin
Levivia viagra
Xanax anxiety
Xanax no prescription required
Chep phentermine
Ambien addiction
Ethosuximide
Motrin
Tetrabenazine
Cheapest phentermine pills
Phenprocoumon
Cefatrizine
Book hydrocodone sport
Free ambien
Cheap phentermine canada
Phentermine overnight shipping
Phentermine pharmacies online
Viagra buy viagra
Cialis info
Asparaginase
Xanax online without prescription
Pediacare
Furazolidone
Amphetamine
Use of viagra
Diovan
Echinacea
Imuran
Information medical phentermine
Delavirdine
Vicodin and alcohol
Chlorthalidone
Alternative viagra
Tramadol cod
Mixing cocaine and viagra
From generic india viagra
Klonopin versus xanax
Viagra patent infringement reexam
Buy Zyban
Buprenorphine
Norvasc
Free viagra sample before buying
Losartan
Overnight shipping viagra
Maker of viagra
Language phentermine ru
Viagra online consultation
Aspirin
Cheep tramadol paris france
Tramadol uses
Hydrocodone
Restoril
Tramadol hc
Buy discount viagra online
Discount generic cialis
Phentermine drug test
Hydrocodone bitartrate
Recreational viagra use
Xanax pills
Imdur
Clonidine
Discount hydrocodone
Overnight viagra
Luvox
Fluorouracil
Diet hcl phentermine pill
Phenytoin
Taking phentermine with antidepressants
First viagra commercial network tv
Phentermine hoodia
Viagra herbal
Dyazide
Klonopin vs xanax dosage
Impotence pill viagra
Isotretinoin
Phentermine free consultation
Buy tramadol online without a prescription
Cefpodoxime
Oxycontin xanax bars percasettes and lor tabs
Isosorbide
Levivia versus viagra
Canada xanax
Ionamin
Nadroparin
Drug test tramadol
Novobiocin
Xanax lethal dose
Pictures of mylan xanax
Fluvoxamine