Bug in Spider


How am i supposed to finish the game? despite having good enough slots to complete the last set of cards :-(



The deal should have been allowed when there aren't enough cards fill up the empty slots...

Accessing Global variables across files

In some projects in C, it becomes necessary to share and access global variables across file(s). In such cases, developers tend to declare the variable as global in a master source file and declare it as extern in other files. This works fine, but it is a good practice to keep all declarations in a header file. But if we keep it the declaration in a header file and include the header file in more than one file,

[code]

common.h

int gvalue;

it would result in a linker error saying gvalue has been redefined.

The work around is to use the #define macro in the header file,

[code]

common.h

#if OWNER 1
#define EXTERN
#else
#define EXTERN extern
#endif

EXTERN int gvalue;

source1.c

#define OWNER 1
#include "common.h" // gvalue is a global variable defined in source1.c
...

source2.c

#include "common.h" // gvalue is a global variable decalred as extern in source2.c
...

Debugging breakages

Breakages are seen quite often in a large project with many developers, especially when there is a dependency between various components in the project. A change in one component could have a negative impact on other dependent ones. It gets the developer/sustainer baffled, specially when some of his/her genuine changes are released and are available in latest labels, and consequently there is a immediate urge to find out the root cause as soon as possible.

A direct approach to setup a debugger like ddd/gdb on the label having the breakage can help identify the bug and solve the same. However, it requires some time to setup and to debug, especially in embedded systems. Hence, other debugging approaches can save a lot of time in such cases.

* Most systems have a well defined logging functions in place. Functions have an entry and exit logs. Logs could be taken from both working and non-working builds and they could be compared to get a rough idea as to where the code flow is deviating in the buggy build. Thats the right place to start and to identify any recent changes in that flow.

* Once the bug is found, one could perform a binary search on the release branch so as to identify the particular change which introduced the bug.

If one has a good knowledge on the code and its flow, a direct binary search on the release branch for recent changes can reveal the bug instantly. Breakages always adds on to the valuable time and effort spent by the developers and ultimately affects the delivery. The lesser the time spent on identifying such issues, the better it is for the delivery.

Wrapper functions on malloc, free

Memory leak is a challenge that awaits any developer working in c. There are many tools, which perform both static and dynamic (run-time) analysis of the source code. These tools report memory leaks, if any. Klocwork is one such tool that can do. However, these are tools which require license fees. There are quite a few open-source projects which basically wraps all calls to malloc and free to custom functions. These functions monitor the usage of memory and finally call the actual memory allocation/deallocation routines.


[Code]

#include

int main()
{
int *ptr = (int*)malloc(sizeof(int)*32);
return(0);
}


Few tools have a macro,

#define malloc custom_malloc
#define free custom_free

It is this custom_malloc, which gets invoked,

void* custom_malloc(size_t size)
{
// Update report with the requested size
return(malloc(size));
}

And once the program is executed, the developer gets a chance to have a look at the report (stored in a file) along with other details like line number in the code, file etc. This information is good enough for the developer to start working on the leak.

This sounds fine, but they have one problem. These tools tend to modify the files of the project. These files have to be re-build and linked. This would be fine for a small project which might not require a lot of time, however large projects, like that of embedded systems which require cross-compilation might take quite a lot of time (I have worked on projects taking 30 minutes to produce a executable link format file).


So here comes an alternative, called library inter positioning. This works for APIs provided in a shared library. malloc is often implemented as a shared library by various vendors in libc. Any call to malloc is resolved by the dynamic linker/loader. We can have a custom function with the same name as that of malloc and create a shared library, memory.so. The functionality of this custom malloc would be same as that of the previous approach [Details shown below]. Once the shared object is created, LD_PRELOAD environment variable can be set with the appropriate values. The dynamic linker searches for the shared objects identified by LD_PRELOAD first followed by other shared objects identified by LD_LIBRARY_PATH.

Now, as the shared object (having new malloc) is registered, we can execute our program to have the dynamic linker resolve all calls of malloc to the malloc, defined in memory.so. There isn't any need to re-link the entire program [Advantage offered by shared library]. As earlier, once the program finishes, we would have the report having all the memory usage. Once the leak is identified and fixed, we can remove the memory.so. Again, there isn't any need to re-link the entire code.

------------------------------------------------------------------------------------------------

void *malloc(size_t size)
{
static void * (*func)();

if(!func)
func = (void *(*)()) dlsym(RTLD_NEXT, "malloc");
printf("malloc(%d) is called\n", size);
return(func(size));
}

Note that the actual malloc should be called only using function pointers. A direct call to malloc would become a recursive call to the very same function.
-----------------------------------------------------------------------------------------------

Working code isn't necessarily bug free

There is always a perception that a working code is considered very stable and free of bugs. Quite a few decisions like estimation for a new feature, estimation for resources to support that code are taken merely based on that very illusion. I happened to work on one issue, which proves otherwise,

encoding_library(void *ptr, unsigned int length)
{
// Parameter check
// ptr points to a chunk of memory supposed to have encoded data
// Invoke a function to perform a part of the encoding
encode_partial(ptr, &length);
// Invoke another function to continue encoding on the same buffer
encode_complete(ptr, &length);
}


encode_partial(void *ptr, unsigned int* length)
{
// This function fills the buffer with the encoded data and as and when the memory of buffer is finished, it passes the memory to the caller and requests for a new chunk of memory. This happens until the encoding corresponding to this function is finished...
}

encode_complete(void *ptr, unsigned int* length)
{
// Finishes the encoding and conveys the same to the caller.
}

It is anyone's guess that encode_partial should have accepted a pointer to the pointer type, as the location where the ptr is pointing to, is being changed in the function and the same should be passed to the parent function. However, the above code was working fine without any segmentation fault... I was puzzled initially, it didn't make any sense at all...

Finally i realized that the new chunk of memory allocated happened to be at the exact same address as that of the previous chunk, and thats height of coincidence. This code was working on ARM processor with VRTX (Versatile real time executive operating system). It might have crashed had it been ported to some other platform or for that matter, when the memory allocation library of the current platform were to be modified.

Best way to avoid such bugs is probably a proper code walk through.
I was working on a feature (to be developed in c++), which wasn't yet committed to any products :-( but had a high probability to get approved. Accordingly, i was expected to work in the test environment with temporary resources like conditional compilation and other resources specific to the platform.

Naturally, there is a tendency to develop the code and have a temporary hack like

#define NEW_FEATURE_NUMBER TRUE

The code was finished, the testing was done, everything is cool. We are just waiting for the approval from management :-). However, the temporary hacks are still present in the code and as the work was completed, i was asked to move on to other projects.
From here on, as and when the feature is approved, i would be expected to complete the formalities and have the changes in the main release line. Here comes the problem, there is a high probability that i might forget to remove the temporary hacks and have the code released with these hacks, and might have to think about an excuse...

Good that i have the #error feature to help me out... causing the compiler to give an error with a custom message,

#error "Warning: Temp conditional compilation enabled"
#define NEW_FEATURE_NUMBER TRUE

Now i can't get this file compiled and consequently can't have it released too :-). Further more, it would indicate the nature of the hack to any developer working on this file. A very nice way to put things on hold when moving to a different file.

error response to users

I was going through news articles this morning, just like any other day, and landed up with some errors on http://economictimes.indiatimes.com

Internal Server Error 500


Exception: EAccessViolation
Message: Access violation at address 01BA25CC in module 'cms.dll'. Write of address 01C13804


===================================================================
Microsoft OLE DB Provider for SQL Server
error '80040e57'

String or binary data would be truncated.

/OCT/hit_counter.asp, line 27

====================================================================================

Good enough to conclude on what database they are working on ;-) Wish i could get the version info, to search for some vulnerability...