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 > >