[jcifs] problem with TransactNamedPipeInputStream

Michael B. Allen miallen at eskimo.com
Fri Sep 27 19:56:42 EST 2002


On Thu, 26 Sep 2002 12:48:06 -0700 (PDT)
sharath reddy <sharathreddy at yahoo.com> wrote:

> 
> Hi Michael,
> 
> I was experimenting with some DCE/RPC stuff and I ran
> across the following problem:
> 
> I'm using named pipes and ran into a problem when I do
> consecutive reads from TransactNamedPipeInputStream.
> Here's what (i think) happens:
> 
> The first time I read data from the pipe, I retrieve
> 68 bytes of data from the pipe. This sets the value
> of the variables: beg_idx = nxt_idx = 68.
> 
> The next time data is being written into the pipe (via
> the 'receive' funtion), turns out the buffer is too
> small. So a new, larger  buffer is created, and the
> data is copied over from the old buffer into the new:
> 
> System.arraycopy( tmp, beg_idx, pipe_buf, 0, used );
> beg_idx = 0;
> 
> However, when I do another read from the pipe, I seem
> to have 68 bytes of zeros, then my data. The last
> 68 bytes of my data is missing. 
> 
> I was able to fix this by adding the following line:
> nxt_idx -= beg_idx;
> 
> before setting beg_idx to zero, after resizing the
> buffer.

I  have  just  looked  at  this more closely. I have found two bugs, one of
which  is  the one you describe. Just to clarify and describe the bugs I'll
inline the code with little annotations: 

  58   public int read( byte[] b, int off, int len ) throws IOException {
  59     int result = -1;
  60     int i;
  61 
  62     if( len <= 0 ) {
  63       return 0;
  64     }
  65     synchronized( lock ) {
  66       try {
  67         while( used == 0 ) {
  68           lock.wait();
  69         }
  70       } catch( InterruptedException ie ) {
  71         throw new IOException( ie.getMessage() );
  72       }

We've  woken  up because we've received some data so let's copy it into the
callers  buffer. This pipe (like most pipes I imagine) is a circular buffer
so  you  have two cases; one where all data is in one segment and two where
there's  a  tail  fragment and a beginning fragement. Note if there are two
fragments they have to be on the ends or the data would not be continuous.

Apparently  i  is  the  length  of  the tail region. The result variable is
either everything we've got to give or the exact length they asked for. 

  73       i = pipe_buf.length - beg_idx;
  74       result = len > used ? used : len;

used  is how much data is in the buffer. If there's more in the buffer than
what's  the  tail  then this is the second case so we need to copy from the
tail  and  then  the  head  fragment  with separate copys. Unless of course
result is not that much in which case we can do a single copy. 

  75       if( used > i && result > i ) {
  76         System.arraycopy( pipe_buf, beg_idx, b, off, i );
  77         off += i;

Here's  a  bug. After copy the tail over we proceed to copy the full result
amount. This sound be result - i:

       System.arraycopy( pipe_buf, 0, b, off, result - i );

and not just result. 

  78         System.arraycopy( pipe_buf, 0, b, off, result );
  79       } else {
  80         System.arraycopy( pipe_buf, beg_idx, b, off, result );
  81       }

We  decrement  used  and  increase  beg_idx  accordingly. No need to update
nxt_idx  here. It's the beginning of the free area and we have only removed
data  before  it  (and  possibly  right up to it like you described in your
scenario). 

  82       used -= result;
  83       beg_idx = ( beg_idx + result ) % pipe_buf.length;
  84     }
  85     return result;
  86   }
  92   int receive( byte[] b, int off, int len ) {
  93     int i;

This  method is called by a different thread when there's data to be placed
into  the  pipe.  Another  thread  is  used  because the caller is blocked.
Classic  reader/writer  problem.

If the len being put in exceeds our buffer increase to accomodate. 

  94 
  95     if( len > ( pipe_buf.length - used )) {
  96       byte[] tmp;
  97       int new_size;
  98 
  99       new_size = pipe_buf.length * 2;
 100       if( len > ( new_size - used )) {
 101         new_size = len + used;
 102       }
 103       tmp = pipe_buf;
 104       pipe_buf = new byte[new_size];
 105       i = pipe_buf.length - beg_idx;

Same  sort of thing as before. i is the length of the tail fragment. If the
amount  of  data  in  the buffer exceeds that tail fragment then we have to
copy  the  tail  and then the head with two separate arraycopies. Notice we
*do*  subtract  i  from  the  total  copy amount unlike the analygous buggy
operation above. 

 106       if( used > i ) {
 107         System.arraycopy( tmp, beg_idx, pipe_buf, 0, i );
 108         System.arraycopy( tmp, 0, pipe_buf, i, used - i );

Here  is  the problem. We just reordered the two fragments to the beginning
of the new bigger array. We moved the tail. So if we moved the tail we need
to  make nxt_idx point at the end of it. If all the data's at the beginning
of the array now that position is simply: 

      nxt_idx = used;

 109       } else {
 110         System.arraycopy( tmp, beg_idx, pipe_buf, 0, used );
 111       }
 112       beg_idx = 0;
 114       tmp = null;
 115     }
 116 
 117     i = pipe_buf.length - nxt_idx;
 118     if( len > i ) {
 119       System.arraycopy( b, off, pipe_buf, nxt_idx, i );
 120       off += i;
 121       System.arraycopy( b, off, pipe_buf, 0, len - i );
 122     } else {
 123       System.arraycopy( b, off, pipe_buf, nxt_idx, len );
 124     }
 125     nxt_idx = ( nxt_idx + len ) % pipe_buf.length;
 126     used += len;
 127     return len;
 128   }



> 
> Please let me know if I am missing something.
> BTW, your method 'Log.printHexDump' is very cool!
> 
> Regards,
> Sharath
> 
> 
> =====
> Sharath Reddy
> Cell : 512 689 4360
> 
> __________________________________________________
> Do you Yahoo!?
> New DSL Internet Access from SBC & Yahoo!
> http://sbc.yahoo.com


-- 
A  program should be written to model the concepts of the task it
performs rather than the physical world or a process because this
maximizes  the  potential  for it to be applied to tasks that are
conceptually  similar and more importantly to tasks that have not
yet been conceived. 



More information about the jcifs mailing list