Here are some of our most popular bugs that we know about in version 1.8; some include fixes. We're busy polishing version 2.0, so this is not as formal as we'd like --- but it's better than nothing.

Runtime Kernel Bugs

signed/unsigned bug in tcp.c:_tcp_WriteBuffer

This bug prevents write errors arising from broken TCP connections from being perceived and acted upon by ILU. Somewhere around line 341 of ${ILUSRC}/runtime/kernel/tcp.c, in procedure _tcp_WriteBuffer, there is a line that reads something like
    if ((i = _ilu_Write(self->tr_fd, p->buffer, size + 4)) < size + 4) {
Replace it with one that reads
    if ((i = _ilu_Write(self->tr_fd, p->buffer, size + 4)), i<0 || ((ilu_cardinal)i) < size + 4) {

Bugs in I/O registration table management in the BSD default Main Loop

In implementation terms, these bugs bite only when you have two or more connections at one time, and cause unwarranted calls on formerly registered I/O handlers. This can lead to a wide variety of user-observed symptoms, including wedged clients and servers, and unwarranted tranport errors. There are actually two bugs here. To fix the first, insert the statement
      if (lastIdx > nIdx)
	lastIdx = nIdx;
into procedures Default_UnregisterInputSource and Default_UnregisterOutputSource in ${ILUSRC}/runtime/kernel/bsdmnlp.c at the places illustrated here:
static ilu_boolean Default_UnregisterInputSource(int fd)
{
  register int    i;
  static ilu_boolean also = ilu_TRUE;
  if (extra_can_inp != NULLFN)
    also = (*extra_can_inp) (fd);
  for (i = 0; i < nIdx; i += 1)
    if ((IOTab[i].fd == fd) && IOTab[i].input) {
      nIdx--;
      if (lastIdx > nIdx)
	lastIdx = nIdx;
      if (i != nIdx) {
	IOTab[i].fd = IOTab[nIdx].fd;
	IOTab[i].input = IOTab[nIdx].input;
	IOTab[i].proc = IOTab[nIdx].proc;
	IOTab[i].rock = IOTab[nIdx].rock;
      }
      MaybeDumpIOTab();
      return (also);
    }
  DEBUG(MAINLOOP_DEBUG, (stderr,
		   "UnregisterInputSource: FD %d not in table!\n",
			 fd));
  return (ilu_FALSE);
}
...
static ilu_boolean Default_UnregisterOutputSource (int fd)
{
  register int    i;
  static ilu_boolean also = ilu_TRUE;
  if (extra_can_out != NULLFN)
    also = (*extra_can_out) (fd);
  for (i = 0; i < nIdx; i += 1)
    if ((IOTab[i].fd == fd) && !IOTab[i].input) {
      nIdx--;
      if (lastIdx > nIdx)
	lastIdx = nIdx;
      if (i != nIdx) {
	IOTab[i].fd = IOTab[nIdx].fd;
	IOTab[i].input = IOTab[nIdx].input;
	IOTab[i].proc = IOTab[nIdx].proc;
	IOTab[i].rock = IOTab[nIdx].rock;
      }
      MaybeDumpIOTab();
      return (also);
    }
  DEBUG(MAINLOOP_DEBUG, (stderr,
		  "UnregisterOutputSource: FD %d not in table!\n",
			 fd));
  return (ilu_FALSE);
}
The second bug is in procedure Default_RunMainLoop in bsdmnlp.c. To fix this bug, add a declaration
  struct io_reg   lastreg;
at the top of the procedure, and change the loop over /lastIdx/ to read as follows:
    while (lastIdx > 0) {
      ilu_boolean     forEx, forIo;
      fd_set         *iofds;
      --lastIdx;
      forEx = FD_ISSET(IOTab[lastIdx].fd, &excnfds) != 0;
      iofds = IOTab[lastIdx].input ? &readfds : &writefds;
      forIo = FD_ISSET(IOTab[lastIdx].fd, iofds) != 0;
      if (forEx || forIo) {
	lastreg = IOTab[lastIdx];
	DEBUG(MAINLOOP_DEBUG,
	      (stderr,
	       "Default MainLoop: calling IOTab[%d](%d,%d) = {%d, %d, %p, %p}\n",
	       lastIdx, forEx, forIo,
	       lastreg.fd,
	       lastreg.input,
	       lastreg.proc,
	       lastreg.rock));
	if (forIo)
	  FD_CLR(lastreg.fd, iofds);
	(*lastreg.proc) (lastreg.fd, lastreg.rock);
	goto next;
      }
    }

FoundFD in mainloop.c should unregister I/O handler

Failure to do this can cause busy waits, and can complete other bugs. The fix is a bunch of edits to $ILUSRC/runtime/kernel/mainloop.c. First, add a member to struct wait_frame_s:
struct wait_frame_s {		/* A chained stack frame */
  ...
  ilu_boolean     regd;		/* is FoundFD still registered? */
};
Then make every procedure that calls ilu_ExitMainLoop(&(a struct wait_frame_s).stop) also unregister the I/O handler. There are two such places. One is in TAInvoke:
static void TAInvoke(ilu_Alarmette a)
{
  WaitFrame      *wf = (WaitFrame *) a;
  while (wf->cooler != NIL)
    wf = wf->cooler;
  ((wf->input ? ilu_UnregisterInputSource : ilu_UnregisterOutputSource)
   (wf->fd));
  for (wf = wf; wf != NIL; wf = wf->hotter) {
    wf->sure = wf->regd = 0;
    ilu_ExitMainLoop(&(wf->stop));
  }
  return;
}
and the other is in FoundFD:
static void FoundFD(int fd, ilu_private rock)
{
  WaitFrame *wf = (WaitFrame *) rock; /* coolest frame in the stack */
  _ilu_Assert(wf->cooler == NIL, "mainloop.c:FoundFD");
  ((wf->input ? ilu_UnregisterInputSource : ilu_UnregisterOutputSource)
   (fd));
  for (wf = wf; wf != NIL; wf = wf->hotter) {
      wf->sure = (wf->hotter == NIL) && (wf->stop == 0);
      wf->regd = 0;
      ilu_ExitMainLoop(&(wf->stop));
    }
  return;
}
Finally, change IOWait to (a) re-register the I/O handler if necessary, and (b) assume the I/O unregistration has already happened by the time ilu_RunMainLoop has returned. It now looks like this:
static void IOWait(int fd, int input, ilu_boolean *sure,
		   ilu_FineTime *limit)
{
  ...
  this.hotter = NIL;
  this.regd = TRUE;
  for (pp = &wfs; (*pp) != NIL; pp = &((*pp)->fd_next) ) {
      if ( ((*pp)->fd == fd) && ((*pp)->input == input) ) {
          ...
          bottom = FALSE;
	  if (this.cooler->regd)
	    goto redy;
          goto regit;
        }
    }
  this.cooler = NIL;
  this.fd_next = wfs;
  wfs = &this;
  bottom = TRUE;
regit:
  if (input)
       ilu_RegisterInputSource (fd, FoundFD, (ilu_private) &this);
  else ilu_RegisterOutputSource(fd, FoundFD, (ilu_private) &this);
redy:
  this.fd = fd;
  this.input = input;
  this.stop = 0;
  this.sure = 2;
  if (_ilu_DebugLevel & MAINLOOP_DEBUG) {
    ...
  }
  if (limit != NIL)
      ilu_MXASet(&timeAlarm, &this.wake, *limit);
  ilu_RunMainLoop(&this.stop);
  *sure = this.sure;
  if (limit != NIL)
      ilu_MXAClear(&timeAlarm, &this.wake);
  if ( bottom ) {
      _ilu_Assert(wfs == &this, "IOWait: pop new");
      wfs = this.fd_next;
    }
  else {
      _ilu_Assert(this.cooler != NIL, "IOWait: this.cooler == NIL");
      _ilu_Assert(this.fd_next == this.cooler->fd_next,
		  "IOWait: pop old");
      *pp = this.cooler;
      (*pp)->hotter = NIL;
    }
  return;
}

Default_Unregister{Input,Output}Source should clear bits

In $ILUSRC/runtime/kernel/bsdmnlp.c, Default_Unregister{Input,Output}Source should clear the corresponding bits in the FD sets. Otherwise, you can see spurrious calls on newly registered I/O handlers; the consequences are described in the next entry. To fix, insert calls on FD_CLR as shown:
static ilu_boolean 
Default_UnregisterInputSource(int fd)
{
  register int    i;
  static ilu_boolean also = ilu_TRUE;
  if (extra_can_inp != NULLFN)
    also = (*extra_can_inp) (fd);
  FD_CLR(fd, &readfds);
  FD_CLR(fd, &excnfds);
  for (i = 0; i < nIdx; i += 1) ...
}
...
static ilu_boolean Default_UnregisterOutputSource (int fd)
{
  register int    i;
  static ilu_boolean also = ilu_TRUE;
  if (extra_can_out != NULLFN)
    also = (*extra_can_out) (fd);
  FD_CLR(fd, &writefds);
  for (i = 0; i < nIdx; i += 1) ...
}

Don't use ilu_AddRegisterersToDefault

Sorry, this doesn't work reliably; it doesn't really integrate the two main loops well enough to satisfy ILU's requirements on its main loop. In implementation terms, the problem is that a registered I/O handler may get spurrious calls. We've seen two symptoms of this problem. One symptom is the server spurriously closing an idle connection; fixing the next bug enables clients to recover from this scenario. Another symptom is a server getting blocked in a spurrious call on accept(). We recommend the following detection/defense for the latter scenario. First, modify procedure _ilu_tcp_CreateMooring in $ILUSRC/runtime/kernel/tcp.c, to set listening sockets non-blocking:
static ilu_Mooring _ilu_tcp_CreateMooring (ilu_private mooringInfo)
{
  int oflags;
  ...
  if (listen(skt, 4) < 0) {
    ...
  }

  if ((oflags = fcntl(skt, F_GETFL, 0)) < 0 ||
      fcntl(skt, F_SETFL, oflags | O_NDELAY) < 0) {
    int             theerr = errno;
    DEBUG((EXPORT_DEBUG | TCP_DEBUG),
	  (stderr,
	   "_tcp_CreateMooring:  fcntl(%d, F_SETFL, oflags|O_NDELAY) failed:  %s.\n",
	   skt, strerror(theerr)));
    close(skt);
    return (NIL);
  }

  self = (ilu_Mooring) ilu_must_malloc (sizeof(struct _ilu_Mooring_s));
  ...
}
This should work for SunOS 4.1, Solaris 2, and Linux; for other systems you may need a different flag or an entirely different way to set the socket non-blocking. Second, react properly when accept() returns due to non-blocking:
static ilu_Transport _tcp_AcceptClient (ilu_Mooring self)
{
  ...
  if ((ns = accept(self->mo_fd, (struct sockaddr *) &sin, &addrlen)) < 0)
    {
      if (errno == EWOULDBLOCK)
        fprintf(stderr, "tcp: accept(%d) would block!\n", self->mo_fd);
      else
        perror ("_tcp_AcceptClient:  accept");
    }
  else ...
}
Again, this should work for SunOS 4.1, Solaris 2, and Linux; for other systems, you may need to compare against another errno (EAGAIN would be a good guess --- EAGAIN should work for Solaris 2 and Linux, but not SunOS 4.1). Actually, the fprintf only helps you detect that this situation has arisen. Once that's no longer a mystery, you needn't bother printing the message.

Failure to close a broken connection

If an outgoing TCP connection is broken (e.g, because the server exited), calls on transport_flush_output will henceforth return ilu_Errors. But of the calls on transport_flush_output in sunrpc.c, only one even checks for errors. And that one doesn't close the connection, so there will be many more failing calls in the future. (Yes, at least some of the callers of _sunrpc_SendPacket are kernel interface procedures that don't close the connection either.)

What this means is that after a connectivity break between client and server, the client may henceforth get errors --- even after connectivity is restored.

The fix for this one is not small. Below are both a complete workaround and a partial fix; the workaround should work regardless of how much you fix the problem.

To work around this bug, do the following. On the client, react to the first call failure by banking the surrogate server and dissociating all its objects (in C, e.g., this can be done by a call on ILU_C_DestroyObjectAndServer, if you're using only one object from that server), and then re-importing the desired objects when you want them. The importation and/or subsequent uses should succeed or fail depending on whether connectivity is now available.

To partially fix the problem, add the following declaration into $ILUSRC/runtime/kernel/iluntrnl.h:

/*L1.sup < cmu; L2 >= {conn's callmu, iomu}*/
void _ilu_CloseLostConnection(ilu_Connection conn);
Between _ilu_ClearConnectionFromServer and _ilu_NDataPresent would be a plausible place. Add the definition to connect.c:
/*L1.sup < cmu; L2 >= {conn's callmu, iomu}*/
void _ilu_CloseLostConnection(ilu_Connection conn)
{
  ilu_Server      s = conn->co_server;
  DEBUG(CONNECTION_DEBUG,
	(stderr,  "Closing lost connection %p\n", conn));
  _ilu_AcquireMutex(ilu_cmu);
  _ilu_AcquireMutex(server_lock(s));
  _ilu_CloseIoingConnection(conn, FALSE);
  _ilu_ReleaseMutex(server_lock(s));
  _ilu_ReleaseMutex(ilu_cmu);
  return;
}
between _ilu_CloseConnection and ilu_CloseConnection. Add a call on the new procedure, from a new "if" statement in ilu_FinishRequest in call.c:
ilu_boolean ilu_FinishRequest (ilu_Call call)
{
  if (call_connection(call) == NIL) {
      _ilu_CommunicationsError (call, errno, CONNECTION_ERROR);
      return FALSE;
    }
  else {
      ilu_boolean ans = protocol_finish_request(call_proto(call), call);
      if (   (!call_transport(call)->tr_class->tc_timesout)
          || method_asynchronous(call_method(call))	/* ACK! */
         )
        protocol_drop_request(call_proto(call), call);
      if (!ans)
        _ilu_CloseLostConnection(call_connection(call));
      return (ans);
    }
}
A complete fix would add such calls in many more places.

Double free of WriteError-suffering buffer

When _sunrpc_SendPacket handles a WriteError from transport_flush_output, it frees the buffer, even though _tcp_WriteBuffer has also left that pointer in the TCPParms (so it will later be used in tcp.c). Note that iluntrnl.h doesn't say anything about ownership of the buffer, and the definition of WriteError (in transprt.h) is explicitly confused.

This can lead to memory smashes, and thus arbitrary misbehavior.

To fix, in procedure _sunrpc_SendPacket in ${ILUSRC}/runtime/kernel/sunrpc.c, replace the line

	ilu_free(ev->buffer);	/* pretty useless by now */
with
#if 0
	ilu_free(ev->buffer);	/* pretty useless by now */
/* ... but not owned by this code! */
#endif
And if your installation includes courier, do the analogous fix to _courier_SendPacket in courier.c.

Imprecise internal consistency check in object.c:ilu_SetLSO

This bug can cause unreal internal consistency check violations, on clients of COLLECTIBLE objects. To fix, replace the couplet
  err = IUpdate(obj, t);
  ILU_MUST_BE_SUCCESS(err);
in procedure ilu_SetLSO in ${ILUSRC}/runtime/kernel/object.c with
  err = IUpdate(obj, t);
  ILU_ERR_SWITCH (err) {
    ILU_SUCCESS_CASE
      {}
    ILU_ERR_CASE(GcRegFailed, e)
      _ilu_Assert(lso == NIL, "Couldn't register GC interest in collectible instance (in ilu_SetLSO)");
      ilu_FreeError(err);
  } ILU_ERR_ENDSWITCH;

Header file organization bug renders MOP unusable

iluxport.h declares ilu_RegisterProtocol and ilu_RegisterTransport. ilu_RegisterTransport takes a transport class instantiator, which creates a transport class. A transport class includes methods that raise exceptions declared in transprt.h, which is private to the kernel --- it doesn't go into the top-level include/ directory that apps "-I".

Language-Specific Runtime Bugs

Code cloning bug in iluServer.cc

At file level in ${ILUSRC}/runtime/c++/iluServer.cc, replace
static ilu_MainLoop kml = { CallRun, CallExit, CallRegisterInput, CallUnregisterInput, CallRegisterInput, CallUnregisterInput, CallCreateAlarm, CallSetAlarm, CallUnsetAlarm };
with
static ilu_MainLoop kml = { CallRun, CallExit, CallRegisterInput, CallUnregisterInput, CallRegisterOutput, CallUnregisterOutput, CallCreateAlarm, CallSetAlarm, CallUnsetAlarm };

strdup/free problem in iluObject::ILUEnsureKernelObject

Steve Freeman re-reports:
Subject: old C++ runtime bug still there...
Message-ID: "<199509131850.UAA04246@les-rouies.grenoble.rxrc.xerox.com>"
From: Steve.Freeman@grenoble.rxrc.xerox:com:Xerox
Date: Wed, 13 Sep 1995 11:50:55 PDT

This one turned up a while ago, and I've bumped into it again now
we've been using ILU some more. I'm going to fix our copy to duplicate
the id twice at line (3).

steve


------- start of forwarded message (RFC 934 encapsulation) -------
Message-Id: <9409161252.AA04014@grenoble.rxrc.xerox.com>
From: freeman@meije (Steve Freeman)
Subject: why we need garbage collection...
Date: Fri, 16 Sep 1994 14:52:46 --100


In the c++ runtime there are two instance handle fields: one in
the C++ object and one in the ILU object. These are set up by the
following code:

  ilu_KernelObject iluObject::ILUEnsureKernelObject()
  {
    if (this->ILURPCObject == NULL) {
      /* Should be a true object. */
      static int idcounter = 0;
      char * id;

      this->ILURPCServer = this->ILUGetServer()->KernelServer();
      if (this->ILUInstanceClassRecord->cl_singleton)
(1)      id = "0";
      else if ((id = this->ILUGetInstanceHandle()) != NULL)
(2)     id = _ilu_Strdup(id);
      else {
  	char idbuf[10];

	sprintf(idbuf, "%u", ++idcounter);
(3)	this->ILUInstanceHandle = id = _ilu_Strdup(idbuf);
      }

  [etc...]

In case (1), the instance handle "id" is constant so it's generated on
the fly. In case (2), the instance handle is _copied_ from an existing
C++ one. In case (3), the instance handle fields for both objects point
to the same storage. When destroying the object, the instance handles for
both the C++ and ILU objects are freed, which is obviously a bug in case
(3). Generally, this is not a problem, because you can get away with 
freeing space more than once and in the original, single-threaded, C++
runtime, this storage is not reused until we return from both frees.
In my new, improved, multi-threaded C++ runtime, however, the storage can
very occasionally be allocated to something else between the two frees,
with obvious (well, not really) results.

This stuff is just so much _fun_...

steve

------- end -------

C++ runtime inconsistent with kernel wrt thread ilu_MainLoop

Witness the following dialog:
Subject: Re: Unregistering Sources in runtime/kernel/tcp.c
In-Reply-To: "<95Sep7.105337pdt."17062(2)"@alpha.xerox.com>"
Message-ID: "<199509071843.UAA00575@galibier.grenoble.rxrc.xerox.com>"
To: Mike Spreitzer:PARC
Cc: Steve.Freeman@grenoble.rxrc.xerox
Reply-To: freeman@xerox:fr
From: Steve.Freeman@grenoble.rxrc.xerox:com:Xerox
Received: from meije.grenoble.rxrc.xerox.com ([13.202.220.10]) by alpha.xerox.com with SMTP id <19070(10)>; Thu, 7 Sep 1995 11:42:54 PDT
Received: from galibier.grenoble.rxrc.xerox.com (galibier [13.202.220.35]) by meije.grenoble.rxrc.xerox.com (8.6.10/8.6.9) with ESMTP id UAA06231; Thu, 7 Sep 1995 20:43:12 +0200
Original-From: Steve Freeman 
Received: (freeman@localhost) by galibier.grenoble.rxrc.xerox.com (8.6.12/8.6.9) id UAA00575; Thu, 7 Sep 1995 20:43:11 +0200
Date: Thu, 7 Sep 1995 11:43:11 PDT
References: "<199509070956.LAA06712@goelon.grenoble.rxrc.xerox.com>", "<95Sep7.105337pdt."17062(2)"@alpha.xerox.com>"

Mike Spreitzer writes:
 > Actually, look at the code in frame 4.  You'll see that it expected you to pass
 > NULL function pointers, instead of procedures that crash.

Ah but! look at the code in frame 3 (CallUnregisterInput, in
iluServer.cc). The C++ runtime defines mainLoop as an abstract class
which should be made concrete and then registered. The runtime then
registers its own private mainLoop functions that pass the calls
through to the relevant methods of this object.

For now, I'm just returning TRUE, but maybe I should just drop the C++
main loop and use the C one?  It feels like the C++ version of
mainLoop should either be annotated or removed.

 > We don't need documentation --- we distribute source code!  ;-)
Which is always an education to read...

steve
Date: Thu, 07 Sep 95 13:30:13 PDT
From: Mike Spreitzer:PARC:Xerox
Subject: Re: Unregistering Sources in runtime/kernel/tcp.c

Oh damn.  Yes, it looks like the C++ runtime is inconsistent with what the kernel expects.  Sorry 'bout that.

You could register a C++ mainloop with ml_register_X procs that crash, ml_unregister_X procs that just return TRUE.  Or you could register a C mainloop.

Stub Generator (and Generated Stub) Bugs

Wrong line numbers in parser error messages

A bug in the ISL parser lexer code prevented line numbers from incrementing when an open-paren char '(' is followed immediately by a newline, as in a possible style of method definition:
     ASYNCHRONOUS deliverData(
       IN context: ServerContextID,
       IN messageID: MessageID,
       IN data: OctetSeq),
The following patch to ILUSRC/stubbers/parser/iluparse.c.dist fixes the problem:
*** 1.1	1995/10/18 02:04:58
--- iluparse.c.dist	1995/10/18 02:05:39
***************
*** 4186,4191 ****
--- 4186,4193 ----
    while (c == '(')
      {
        c = GetChar(file);
+       if (c == NEWLINE)
+ 	CurrentParse->line += 1;
        if (c == '*')
  	{
  	  c = EatComment (file);

Missing name conversion in c/cheaders.c:generateUnionTypeDiscriminator

This bug prevents a hyphenated name from being converted to using underscores, when the name appears in the #defintion of a tag value used in a union. In procedure generateUnionTypeDiscriminator in ${ILUSRC}/stubbers/c/cheaders.c, replace
  fprintf (s->context->file, "#define %s__%s ", c_type_name (s->context->class), type_name (a->type));
with
  fprintf (s->context->file, "#define %s__%s ", c_type_name (s->context->class), c_string (type_name (a->type)));

Bug handling OUT string arguments in C

James L Fulton reports:
Subject: Output CString arguments and C clients
Message-ID: "<199509291636.QAA17155@qvarsx.er.usgs.GOV>"
From: jfulton@usgs:gov:Xerox
Date: Fri, 29 Sep 1995 09:41:45 PDT

I'm having trouble calling functions that use output ilu.CString
arguments from C. I believe that this is due to a bug in the C code
generated.

Take the trivial interface, spam.isl:

  INTERFACE spam;
  
  TYPE Factory = OBJECT
    DOCUMENTATION "spam spam spam"
    METHODS
  
       f(	OUT i : INTEGER,
	  OUT m : ilu.CString,
	  OUT j : INTEGER
	  ) "get spammed"
  
    END;
  
I have no trouble getting this to work with a Python server and
client, however, when I write a C client:

  #include 
  #include 
  
  static spam_Factory ilu_factory=0;
  
  static int
  initFactory()
  {
    if(! ilu_factory)
      {
	char sbh[128];
	char *server="nwiqqvarsa.er.usgs.gov";
	char *protocol="844852514";
	int port=5000;
  
	spam__Initialize( );
  
	sprintf(sbh,
		"theFactory@spam.%s"
		"@sunrpc_2_0x31000400_%s"
		"|tcp_130.11.50.6_%d", /* I'm not done here */
		server,protocol,port);
	
	ilu_factory=spam_Factory__CreateFromSBH(sbh,NULL);
	
	if (ilu_factory == NULL)
	  {
	    fprintf (stderr, "Couldn't find Factory object on server, %s.\n",
		     server);
	    return 0;
	  }
      }
    return 1;
  }
  
  main()
  {
    char *d="client";
    ILU_C_ENVIRONMENT env;
    ilu_integer i= -1,j= -1;
  
    if(! initFactory())
      {
	printf("could not get factory\n");
	return;
      }
  
    spam_Factory_f(ilu_factory, &env, &i, &d, &j);
  
    if (! ILU_C_SUCCESSFUL(&env))
      {
	printf("call failed\n");
	return;
      }
  
    printf("%d %d\n",i,j);
    if(d) printf("%s\n",d);
    else  printf("No data\n");
  }
  
The value of the string argument is unchanged. I looked at the code in
spam-surrogate.c that recieves the output arguments, which had:

      {
        ilu_cardinal _len;
        m = ILU_NIL;

        ilu_InputString(_call, (ilu_CString *) &m, &_len, 0, ilu_FALSE);
      }

Now, m is already a ilu_CString *, so I see no reason for the "&".
...

Jim

Memory leak on inout strings in C++?

Phil Miller reports:
Subject: memory leak on inout strings?
Message-ID: "<9506221924.AA08832@cen.com>"
From: pm@fox.cen:com:Xerox
Date: Thu, 22 Jun 1995 12:24:34 PDT

Looking at the generated C++ code (ILU version 1.8), I see that
for a string declared inout, the previous value of the string is
not freed before the proxy method gets the returned value via
ilu::InputString.   Thus, to do things correctly, the client must:

	ilu_T_CString s = strdup ("input string");
	ilu_T_CString save_s = s;	// save for future destruction
	obj->aMethod (&s);		// pass inout argument
	free (save_s);			// clean up previous value of s

I think this problem is (a) a memory leak for which there
may be no fix, and/or (b) a topic worthy of some documentation.

Regards -- Phil Miller

Feuerman's C++ stub problem

We haven't gotten to this one yet. Ken Feuerman reported
Subject: C++-Stubber Bug
Message-ID: Originator: "Ken Feuerman:PARC:Xerox", UniqueString: "28-Jul-95 8:24:15"
From: Ken Feuerman:PARC:Xerox
Date: Fri, 28 Jul 1995 08:24:19 PDT

Given the following .ISL file:

INTERFACE testbug BRAND "v2.0" IMPORTS ilu END;
TYPE Interval = ARRAY of 2 CARDINAL;
TYPE IntervalSeq = SEQUENCE of Interval;
TYPE Intervals = OPTIONAL IntervalSeq;

the resulting C++ code generated in the client stubs won't compile.  There seem
to be a couple of type declaration "typos", and a problem with assignment into
an array value.


--Ken.
and
Subject: Runtime Bug in C++ Stub
Message-ID: Originator: "Ken Feuerman:PARC:Xerox", UniqueString: "3-Aug-95 10:28:39"
From: Ken Feuerman:PARC:Xerox
Date: Thu, 3 Aug 1995 10:28:46 PDT

There's a runtime bug in the C++ stub generated when declaring an OPTIONAL
SEQUENCE type.  Given the following ISL:

------------------------------------
INTERFACE testbug BRAND "v2.0" IMPORTS ilu END;
TYPE Interval = RECORD
   startPos : CARDINAL,
   endPos : CARDINAL
END;
TYPE IntervalSeq = SEQUENCE of Interval;
TYPE Intervals = OPTIONAL IntervalSeq;
-------------------------------------

An excerpt of the client-common stub reads as follows:

-------------------------------------
void testbug_G::Free_Intervals (testbug_T_Intervals _val)
{
   testbug_G::Free_IntervalSeq (_val);
}
void testbug_G::Free_IntervalSeq (testbug_T_IntervalSeq _val)
{
   register testbug_T_Interval *data = _val->Array();
   free((char *) data);
}
---------------------------------------

Any variable foo of type Intervals could be NULL, since it's OPTIONAL.  But
if/when
testbug_G::Free_Intervals(foo) is called, there's a de-reference of NULL in
testbug_G::Free_IntervalSeq().

--Ken.

Array as return value in C++

Mitch Garnaat sent the following bug report (edited for brevity and HTML):
Subject: array as return value in C++
Message-ID: "<9505092021.AA01675@cacao.wrc.xerox.com>"
To: ilu-bugs:PARC
Date: Tue, 9 May 1995 13:21:53 PDT

I have the following interface:

INTERFACE foo;

TYPE R3 = ARRAY OF 3 REAL;

TYPE bar = OBJECT
  METHODS
    init (),
    run () : R3
  END;

The code produced by the C++ stubber contains a syntax error in the
handling of the return value of method "run".  The code is below.  I have
marked the part of the generated code which the compiler complains
about with lines starting with "*********".

I am running on SunOS4.1.3 using the sunpro-2.0 compilers.  Let me know
if you need any more info.

Thanks,

---------------------------------------------------------------
Mitch Garnaat		Wilson Center for Research & Technology
garnaat@wrc.xerox.com		  	      Xerox Corporation
(716)422-1521	      		   800 Phillips Road MS 128/28E
(716)265-7133 (fax)			      Webster, NY 14580


/* This file was automatically generated with ILU (version 1.8) tools
 * at Tue May  9 15:09:06 1995 by `garnaat'
 * running "/local/packages/ilu/bin/c++-stubber" of Tue May  9 14:07:47 1995
 * on "/local/garnaat/ilu/foo.isl" of Mon May  8 23:39:59 1995,
 * and "/local/packages/ilu/interfaces/ilu.isl" of Tue May  9 14:07:45 1995.
 *
 * ILU is Copyright 1991-1995 Xerox Corporation, All Rights Reserved.
 * ILU information:  ftp://ftp.parc.xerox.com/pub/ilu/ilu.html.
 */

#include 
#include 

extern "C" {
#include 
};
...
foo_T_R3 * foo_T_bar::run (fooStatus *_status)
{
	foo_T_R3 * _retvalue;
	ilu_Call _call;
	ilu_Cardinal _sizeOfDiscriminator = 0;
	ilu_ProtocolException _perror;
	ilu_Cardinal _scode;
	if ((_call = ilu_BeginCall (this->ILUGetKernelServer())) == NULL)
	{
		_status->returnCode = ilu::ProtocolError;
		_status->values.anyvalue = (ilu_Cardinal) ilu_ProtocolException_LostConnection;
	return ((foo_T_R3 *) 0);
	};
	_sizeOfDiscriminator = ilu::SizeOfObjectID(_call, this->ILUGetRPCObject(), ilu_TRUE, NULL);
	ilu::BeginRequest (_call, foo_T_bar::ILUClassRecord, MethodRecord_foo_T_bar_run, (0+_sizeOfDiscriminator));
	ilu::OutputObjectID (_call, this->ILUGetRPCObject(), ilu_TRUE, NULL);
	ilu::FinishRequest (_call);

	if ((_perror = ilu::WaitForReply (_call, &_scode)) == ilu_ProtocolException_Success)
	{
		if (_scode == 0)
		{
			_status->returnCode = NULL;
********* error on the following line
********* compiler output is:
"foo.cc", line 213: error: bad assignment type: foo_T_R3* = ilu_Real*
			_retvalue = (ilu_Real *) foo_G::Input_R3 (_call, NULL);
*********
		};
		/* no exceptions to catch */
	}
	else
	{
		_status->returnCode = ilu::ProtocolError;
		_status->values.anyvalue = (ilu_Cardinal) _perror;
	};
	ilu::FinishCall (_call);
	return(_retvalue);
}

...

Type problem with conditional expressions in C++

The C++ stubber emits code that uses a pattern developed for C but that's not quite correct for C++. Here's an example:
ilu::OutputOpaque(_call, ((_retvalue == NULL) ? NULL : *_retvalue), 8)
where
typedef unsigned char ilu_Byte;
...
typedef ilu_Byte Test1_T_A0[8];
...
Test1_T_A0 * _retvalue;
and the second argument to "ilu::OutputOpaque" is declared to be an "unsigned char *". The problem is the type of the second actual argument in the given code fragment. g++ on Linux has been observed to decide that the type of the actual argument is "void *", which cannot be assigned to an "unsigned char *". Note that "NULL" is #defined by system header files, usually to "0" or "((void*)0)". A more clearly unobjectionable pattern would be to use an explicit cast on the null pointer in the conditional expression:
ilu::OutputOpaque(_call, ((_retvalue == NULL) ? (ilu_Byte*)0 : *_retvalue), 8)

Last updated by $Author: spreitze $ at $Date: 1996/06/25 15:38:45 $.