Print

Print


Hi Gregory,

Once again, thanks. The memory leak has already been fixed (uncovered by
one of your previous comments -- thanks again). The other issues look
problematic as well and will be fixed. BTW please thank Chris as well.

Andy

On Fri, 20 Aug 2004, Gregory J. Sharp wrote:

> Folks,
>
> Chris Jones is going through looking at all the uses of malloc (since
> C++ code that calls malloc makes him very nervous, and not without
> cause...).  Here are a few more things that seem like they might be a
> bug or not portable.
>
> Begin forwarded message:
>
> > From: Chris Jones <[log in to unmask]>
> > Date: August 20, 2004 8:20:11 AM EDT
> > To: Gregory Sharp <[log in to unmask]>
> > Subject: Another xrootd potential problem
> >
> > Greg,
> > 	I found another potential 'string not terminated' problem.
> >
> > 	XrdXrClientWorker.cc line 646
> >
> >   if (dlen) {
> >     char* buff = (char*) malloc(dlen*sizeof(kXR_char));
> >     rc = lp->Recv(buff, dlen*sizeof(kXR_char));
> >
> >     // Convert the buffer into the stat structure
> >     //
> >     union {long long uuid; struct {long hi; long lo;} id;} Dev;
> >     char *temp = strtok(buff, (const char*) " ");
> >
> >
> > The problem is strtok requires that the char array (in this case buff)
> > is null terminated.  As far as I can see, that isn't guaranteed
> > programatically (although it might be part of the protocol from
> > whatever we are talking with over the 'lp->Recv(...)' call.
> >
> > For safety, I'd up the malloc by 1 and then force a '\0' at the end of
> > the buffer after the transfer
> >
> >   if (dlen) {
> >     //CDJ: pad buffer by 1 for null character
> >     char* buff = (char*) malloc((dlen+1)*sizeof(kXR_char));
> >     rc = lp->Recv(buff, dlen*sizeof(kXR_char));
> >     buff[rc] = '\0';
> >
> >     // Convert the buffer into the stat structure
> >     //
> >     union {long long uuid; struct {long hi; long lo;} id;} Dev;
> >     char *temp = strtok(buff, (const char*) " ");
>
> I would add, at this point, that if there is some chance this code is
> called in a multi-threaded environment that calling strtok_r might be
> worth considering. I don't know if it is available on all platforms,
> alas.
>
> >
> > Looking over this code (actually, I'm checking all uses of malloc) and
> > I came across this
> >
> > 	XrdXrClientWorker.cc line 921
> >
> > [Look at the very bottom in the 'switch' statement in the redirect
> > case]
> >
> > /**
> >  * Receive an error response from the server and put the result into an
> >  * internal error structure
> >  *
> >  * Input:  dlen   - length of error message to be received from the
> > server
> >  *         staus  - error type. Can be kXR_redirect, kXR_wait etc.
> >  *         method - method from where the error occured
> >  *
> >  * Output: return negative error number
> >  */
> > int XrdXrClientWorker::handleError(kXR_int32      dlen,
> > 				   kXR_int16      status,
> > 				   char          *method)
> > {
> >   ServerResponseBody_Error error;
> >   int                      rc    = 0;
> >
> >   rc = lp->Recv((char*)&error,
> > 		sizeof(kXR_int32) + (dlen-4)*sizeof(kXR_char));
> >
> >   // Check if message has been received correctly
> >   //
> >   if (rc != (int)(sizeof(kXR_int32) + (dlen-4)*sizeof(kXR_char))) {
> >     XrEroute.Emsg(method,
> > 		(char *)"Error message not received correctly.");
> >   }
> >
> >   // If error type is kXR_error, print the error message. For kXR_wait
> > and
> >   // kXR_redirect assign the respective variables
> >   //
> >   switch(status) {
> >   case kXR_error:    XrEroute.Emsg(method, error.errmsg); break;
> >   case kXR_wait:     waitTime     = ntohl(error.errnum);  break;
> >   case kXR_redirect: redirectPort = ntohl(error.errnum);
> >                      redirectHost = (char*) malloc(rc - 3);
> > 		     memcpy((char *) redirectHost, error.errmsg, rc - 3);
> > 		     *(redirectHost+(rc-4)) = '\0';
> > 		     redirect = 1;
> > 		     break;
> >   }
> >
> >   return -status;
> > } // handleError
>
> I would prefer to see something like
> 	size_t sz = rc - 3;  rather that repeating the subtractions all the
> time in the code. The sz-1 subraction will always do the right thing.
> That way you only have one place where you need to get the size right
> if you need to make the sort of change Chris proposes below.
> >
> > 1) if redirectHost has ever been set before, then the memory allocated
> > to the previous time is lost (we have a memory leak)
> > 2) There is a definite assumption about padding between the items in
> > the ServerResponseBody_Error struct
> >
> > 	struct ServerResponseBody_Error {
> >   		kXR_int32 errnum;
> >   		char errmsg[4096]; // Should be sufficient for every use
> > 	};
> >    this could lead to a porting problem
> > 3) I believe we are copying data 1 beyond the end of the message since
> > the 'memcpy' is of length rc-4, even though if you remove the first
> > kXR_int32 size (which you assume is size 4) then the remaining errmsg
> > would be of length rc-4.  Therefore I believe the memcpy should be
> > 		     memcpy((char *) redirectHost, error.errmsg, rc - 4);
> >
> > This actually brings up a question about endian.  Is the server
> > supposed to always send messages to the client in the clients endian?
> > Or is it just assumed that the client and server are the same endian?
>
> --
> Gregory J. Sharp                   email: [log in to unmask]
> Wilson Synchrotron Laboratory      url:
> http://www.lepp.cornell.edu/~gregor
> Dryden Rd                          ph:  +1 607 255 4882
> Ithaca, NY 14853                   fax: +1 607 255 8062
>
>