Classes not referenced from code are removed during Lagoon image stripping. However where such an unreferenced class is actually referenced from a class variable in another non-stripped class the "unreferenced" class still exists in the deployed image as an unbound class.
This can cause issues where the image stripper is configured with "Remove redundant methods" (the default). Since the unbound class is no longer traceable from the system roots its methods are not included when assembling the set of sent messages. Thus methods referenced solely from such classes are stripped despite possibly being sent.
Example:
In the Database Connection package, subclasses of DBUnstructuredFieldBuffer are only referenced from DBColAttr class>>initialize. This reference is stripped along with other class initialization methods leaving the subclasses unreferenced from code and thus removed. However the subclasses are all referenced from the DBColAttr class variable BufferClasses. This reference means the subclasses are present and usable in a deployed image.
DBNumericFieldBuffer>>dbUnmarshal: is one of only two senders in a standard image of on:from:to: which is solely implemented by PositionableStream class. The other reference is from WriteStream class>>with:from:to which is unsent and so (correctly) stripped during deployment. However since DBNumericFieldBuffer is considered unreferenced and so partly removed as described above, its send of on:from:to: is not found. Consequently PositionableStream class>>on:from:to: is considered unsent and removed from the image. This subsequently causes an error when attempting to marshal decimals from the database.
To Reproduce:
-
Install the package Database Test App. This prompts for an ODBC DSN, creates a temporary table containing a DECIMAL column, and attempts to INSERT and SELECT from that table.
-
Deploy the application. The executable manifest should show that DBNumericFieldBuffer has been stripped but also exists as an unbound class:
<RemoveClass>DBNumericFieldBuffer</RemoveClass>
...
<Class name="DBNumericFieldBuffer" count="0" memoryUsage="0" unbound="true">
<Methods count="5">
<Method>dbConvert:for:</Method>
<Method>dbInterchangeType</Method>
<Method>dbMarshal:into:</Method>
<Method>dbUnmarshal:</Method>
<Method>initializeForColumn:</Method>
</Methods>
<ClassMethods count="2">
<Method>dbTransferOctetLengthForColumn:</Method>
<Method>valueClass</Method>
</ClassMethods>
</Class>
The manifest will also show that PositionableStream class>>on:from:to: has been removed:
<StripMethods reason="unsent">
...
<Method methodClass="PositionableStream class">on:from:to:</Method>
- Run the application, selecting a writeable database. The runtime error
ReadStream class does not understand #on:from:to: will be logged.
Possible fixes:
Such cases are probably rare enough to be handled ad hoc, for example by adding the associated class initialization methods to the must not strip category - doing this with DBColAttr class>>initialize allows the example app to be deployed and run successfully. An explicit warning of unbound classes following image deployment could help identify such cases.
Checking for references from class variables to otherwise-unreferenced classes (and thus preventing their removal) would resolve the issue more directly. However this suggests other types of references (global, class instance variable, pool dictionaries) should also be checked which may have an adverse effect on deployment performance.
Dolphin 7.2.2
Windows 11 on Mac Silicon under VMWare
Classes not referenced from code are removed during Lagoon image stripping. However where such an unreferenced class is actually referenced from a class variable in another non-stripped class the "unreferenced" class still exists in the deployed image as an unbound class.
This can cause issues where the image stripper is configured with "Remove redundant methods" (the default). Since the unbound class is no longer traceable from the system roots its methods are not included when assembling the set of sent messages. Thus methods referenced solely from such classes are stripped despite possibly being sent.
Example:
In the Database Connection package, subclasses of
DBUnstructuredFieldBufferare only referenced fromDBColAttr class>>initialize. This reference is stripped along with other class initialization methods leaving the subclasses unreferenced from code and thus removed. However the subclasses are all referenced from theDBColAttrclass variableBufferClasses. This reference means the subclasses are present and usable in a deployed image.DBNumericFieldBuffer>>dbUnmarshal:is one of only two senders in a standard image ofon:from:to:which is solely implemented byPositionableStream class. The other reference is fromWriteStream class>>with:from:towhich is unsent and so (correctly) stripped during deployment. However sinceDBNumericFieldBufferis considered unreferenced and so partly removed as described above, its send ofon:from:to:is not found. ConsequentlyPositionableStream class>>on:from:to:is considered unsent and removed from the image. This subsequently causes an error when attempting to marshal decimals from the database.To Reproduce:
Install the package Database Test App. This prompts for an ODBC DSN, creates a temporary table containing a DECIMAL column, and attempts to INSERT and SELECT from that table.
Deploy the application. The executable manifest should show that
DBNumericFieldBufferhas been stripped but also exists as an unbound class:The manifest will also show that
PositionableStream class>>on:from:to:has been removed:ReadStream class does not understand #on:from:to:will be logged.Possible fixes:
Such cases are probably rare enough to be handled ad hoc, for example by adding the associated class initialization methods to the
must not stripcategory - doing this withDBColAttr class>>initializeallows the example app to be deployed and run successfully. An explicit warning of unbound classes following image deployment could help identify such cases.Checking for references from class variables to otherwise-unreferenced classes (and thus preventing their removal) would resolve the issue more directly. However this suggests other types of references (global, class instance variable, pool dictionaries) should also be checked which may have an adverse effect on deployment performance.
Dolphin 7.2.2
Windows 11 on Mac Silicon under VMWare