Subject: RE: [hackers-il] stop bashing debuggers!

From: Omer Musaev <[email-masked]>
Date: Mon, 7 May 2001 00:27:24 +0200

>
>
>-----Original Message-----
>From: mulix
>To: [email-masked]
>Sent: 05/06/2001 10:46 PM
>Subject: Re: [hackers-il] stop bashing debuggers!
>
>On Sun, 6 May 2001, guy keren wrote:
>

>> and btw, "writing code without using a debugger" doesn't strike as
>good
>> hackerism. and always knowing everything that is going on isn't quite
>> human. the programs are too large to be able to know everything about
>it,
>> and the interactions between its different modules. thus the debugger
>is a
>> tool that helps me, and i use it when its convinient. what next? i
>> shouldn't use purify cause i'm not supposed to write code that has
>memory
>> leaks or that has memory corruptions in the first place? ta! that's
>the
>> kind of speak of people who never realy wrote proper code in large
>> quantities. shu, shu! :)
>
>actually, guy, yes, one should strive to write code without memory
>leaks. maybe it's a close to impossible goal (i dont think it is), but
>it's a worthy one. such is the price of being a good programmer, taking
>care of the little details. or, using garbage collection, but that's
>another discussion.

Good programmer is firstly good engineer, and only later good artist.
The very core of engineering is reusing patterns that are considered
"good practice" and avoiding those that are not.

For example: You mentioned memory leeks. However, memory leeks come
in many various forms and shapes.  Some of them are obvious, but some
are not. For example, consider a program that constantly runs about
500 threads, each opens a socket, writes there a bit, reads a little
and continues in a loop. You can go out of file descriptors fairly easy.
Using Purify you will also know where.

The goal you mention is not close to impossible. However it is very
important to choose the best way to that goal.

I remember designing ultra-fast parser for a core part of real-time
networking code. Initialy the idea was to pre-compute all possible
states during compile time, and then using clever jumps into macro
generated code I would be going in O(1).

It was really surprising that using table-driven parser I can do in
same O(1) without heavy macro machinery.

The morale is that "true and pure" ways to achive desired results
are not always dependant on outstanding engineering - sometimes
old tricks will do again.

In that sense, debuggers, memory checkers etc are good old tricks
that served many programmers and certainly will.

>i have written large projects, i have worked with and without debugers
>and with and without purify. when i _consciously_ try to minimize memory
>leaks and smears, instead of relying on automated tools, i write better
>code. dont you?

How large is large? I remeber writing 10000 lines of code in a debugger-less
environmet ( Linux kernel ). There were bugs that I was looking for for
weeks. The whole project took over 4 months to be done.

This week I wrote 1000 lines of code in a 3 days, most of bugs were
caught during develpment by proper use of debugger.

....
>
>this strikes me as an unqualified statement. how does using the debugger
>make more sense then reading the code?
>

Get an example:

Consider following code ( should be portable to Linux, BSD, HP/UX,
Solaris 2.6, Solaris 2.8 and QNX )
There is a bug in it. Using debugger you will find it instantly.

in foo_goo.h

typedef struct foo {
  u_int32 sip ;
  u_int32 cip ;
  u_int16 spt ;
  u_int16 dpt ;
  u_int16 cnt ;
} tcp_link_cnt_t ;

typedef struct goo {
  u_int32 url_len ;
  char   *url ;
} url_info_t ;

....
in foo_goo.c

void foo_goo( void ) {
  char *buf ;
  tcp_link_cnt_t *tcp_ptr ;
  url_info_t     *url_ptr ;

  tcp_ptr = ( tcp_link_cnt_t * ) buf ;
  tcp_ptr->sip = in_aton( "127.0.0.1" ) ;
  tcp_ptr->dip = in_aton( "192.168.0.1" ) ;
  tcp_ptr->spt = ntohs( 80 ) ;
  tcp_ptr->dpt = ntohs( 3000 ) ;
  tcp_ptr->cnt = 0 ;

  url_ptr = ( url_info_t *) ( buf + sizeof( *tcp_ptr ) ) ;
  url_ptr->url_len = 4 ; /* for byte alignment */
  url_ptr->url = "/" ;
  memset( url_ptr->url + strlen( url_ptr->url ) , 0,
          url_ptr->url_len - strlen( url_ptr->url ) ) ;
}

Where this code will fail?

Regards, 
OmerM