Tcl Source Code

View Ticket
Login
Ticket UUID: 3030870
Title: make itcl 3.x built with pre-8.6 work in 8.6
Type: Bug Version: obsolete: 8.5.8
Submitter: nijtmans Created on: 2010-07-17 07:30:46
Subsystem: None Assigned To: hobbs
Priority: 5 Medium Severity:
Status: Closed Last Modified: 2010-07-25 17:27:20
Resolution: Fixed Closed By: nijtmans
    Closed on: 2010-07-25 10:27:20
Description:
Of course, this could be fixed the same way as [incr Tcl Bug #1725219]
 <https://sourceforge.net/tracker/index.php?func=detail&aid=1725219&group_id=13244&atid=313244>

But, much easier and much less hacky is to just
add dummy unused fields to the
Tcl_CallFrame and CallFrame structures.

Here is the patch, for Tcl 8.5 and 8.4.

For Tcl 8.6 nothing changes. But when
compiling Itcl 3.x, just some extra unused
stack space is reserved, so whenever the
same Itcl built is run under Tcl 8.6 this
space can be used at will.
User Comments: nijtmans added on 2010-07-25 17:27:20:

allow_comments - 1

Fixed in 8.5, 8.4 and 8.3 branch.

If soneone asks: 8.3???? does someone still use that?
Answer: Itcl 3.4b1 still works fine with Tcl 8.3. So at least
I had to verify that this patch works there too. No-one
is planning to release a new Tcl 8.3 version, it's officially
dead, but if someone (like me) wants to revive it
in his own environment, the 8.3 branch still exists
and works.

nijtmans added on 2010-07-20 14:37:24:
Final suggestion: The only reason I added dummy fields to CallFrame in tclInt.h, was
that tclBasic.c demands it. However, this bug shows that in fact Tcl_CallFrame
cannot be smaller than CallFrame, so that's the requirement that should
be checked in tclBasic. Here is the patch.

This allows me to revert my changes to tclInt.h, so the Tcl binary produced is
exactly as before. The only intention of this patch is to tell extenions:
"please allocate a little bit more for your Tcl_CallFrame, because future
Tcl versions might need it".

I'll revert my changes to tclInt.h, and apply the patch to tclBasic.c this
weekend. Jeff, Don, is that safe enough?

nijtmans added on 2010-07-20 14:32:27:

File Added - 380572: tclBasic.c.diff

nijtmans added on 2010-07-19 19:04:46:
>Tcl never allocates a (Tcl_)?CallFrame

I should have added there: 
   "on the stack"
Tcl allocates CallFrames in two places
(tclBasic.c:610 and tclNamesp.c:413),
that would be the only places in the
binaries that are affected by this patch.

But even in those 2 places, Tcl only
allocates those in order to use the
Tcl_(Push|Pop)CallFrame API the
same way as extensions do. So,
still, all arguments hold.

nijtmans added on 2010-07-19 13:29:12:
>I'm sorry to say that, but this is simply not true. Itcl
>compiled against 8.5.9 just runs fine when running
>in 8.5.x (x<9). 
Let me add why, and I'l rest my case.
Tcl never allocates a (Tcl_)?CallFrame, it's the
extension that is supposed to do that. This means
that this patch does not even change a single
byte inside Tcl binaries at all! Tcl binaries with
or without this patch are binary equal, so
sure they are compatible.

The ONLY effect this patch has, is that
Itcl allocates a little more space for the
Tcl_CallFrame that is given to Tcl. The
change to tclInt.h was not even
necessary, although sure it will raise
questions when Tcl_CallFrame and
CallFrame are not equal in size any more.

I rest my case.

nijtmans added on 2010-07-19 04:36:54:
> This means that binaries built using the 8.5.9 tcl.h
> header file will allocate larger Tcl_CallFrame structs.
> This means those binaries will not function when [load]ed
> or otherwise matched up at runtime with a Tcl library
> from release 8.5.x where x < 9.

I'm sorry to say that, but this is simply not true. Itcl
compiled against 8.5.9 just runs fine when running
in 8.5.x (x<9). 

> if Itcl
> hasn't bothered to stay compatible with Tcl 8.5 -- now
> several years old -- that's a problem for Itcl to solve.
That's exactly what [incr Tcl Bug #1725219] is about,
which was handled by jeff, so I would like to hear
his view before going on.

dgp added on 2010-07-19 00:37:51:
In addition, it's of quite questionable value to add aids
to assist the migration of Itcl 3.* from Tcl 8.5 to Tcl 8.6
since Tcl 8.6 is going to come with Itcl 4.

dgp added on 2010-07-19 00:31:53:
On a less technical, more political note, if Itcl
hasn't bothered to stay compatible with Tcl 8.5 -- now
several years old -- that's a problem for Itcl to solve.
Not something for Tcl to twist itself into accomodating.

We spent too many years with crazy Aunt Millie in
init.tcl from pursuing this reasoning in the past.
Enough.  If Itcl is broken, then fix it, or discard it.

dgp added on 2010-07-19 00:29:31:
Your commit to core-8-5-branch adds a field "dummy13"
to the end of the public definition of the Tcl_CallFrame
struct.

This means that binaries built using the 8.5.9 tcl.h
header file will allocate larger Tcl_CallFrame structs.
This means those binaries will not function when [load]ed
or otherwise matched up at runtime with a Tcl library
from release 8.5.x where x < 9.

This kind of incompatibility is one we have customarily
reserved for new minor releases, not patchlevels.  At
a minimum, reacting to such a policy change means
that extensions have to rethink their Tcl_InitStubs()
and [package require Tcl] habits so that they begin
checking for compatible Tcl libraries all the way to
the patchlevel detail.

Maybe a case could be made that that's a desirable
way to go, but it should be something proposed and
consideredand discussed, with some feedback from some actual
extension authors, not something just dropped in
over the weekend.

I say revert.

nijtmans added on 2010-07-18 12:42:53:
See the following comment in tcl.h:
==========================================================================
A call frame is initialized and pushed using Tcl_PushCallFrame and popped
using Tcl_PopCallFrame. Storage for a Tcl_CallFrame must be provided by the
Tcl_PushCallFrame caller, and callers typically allocate them on the C call
stack for efficiency. For this reason, Tcl_CallFrame is defined as a
structure and not as an opaque token. However, most Tcl_CallFrame fields
are hidden since applications should not access them directly; others are
declared as "dummyX".
==========================================================================

Example extension code:

 Tcl_CallFrame frame;
 int somevar;

 Tcl_PushCallFrame(interp, &frame, ....);
 ....
 Tcl_PopCallFrame(interp);

The functions Tcl_PushCallFrame and Tcl_PopCallFrame are functions
that look like public, but in fact they are in the private stub
table. The Tcl_CallFrame structure looks like a public structure,
but in fact is was never documented. As far as I know, the only
extension using it is Itcl. So, is it really public?....

Just because Tcl 8.5 added two fields to the Tcl_CallFrame structure
this caused [incr Tcl Bug #1725219]. Tcl 8.6 did it again with one
additional field. So, yes, you are right that "Adjusting the size
of any public structure is a recipe for problems". That's exactly
what caused [incr Tcl Bug #1725219]. The problem is caused by
overwriting variables that come immediately afther the Tcl_CallFrame
structure on the stack, that that's exactly what this patch is
not doing.

So, what happens if the above example code is compiled against
Tcl 8.4.19? The "frame" variable is allocated on the stack, and
is used to hold the old callframe between the Tcl_PushCallFrame
and Tcl_PopCallFrame calls. Now we are running it in Tcl 8.5 or
Tcl 8.6. The Tcl_CallFrame structure got some extra
fields, so the result is that the "frame" variable is not
big enough any more to hold the information stored by Tcl.
The effect will be that the "somevar" variable is overwritten.

So, now we run it in Tcl 8.4.20 (with this patch). Yes, the
Tcl_CallFrame got some extra fields. But Tcl never reads or
writes those dummy fields, so the "somevar" variable will
never be overwritten.

Now what happens if we compile the above sample code using
Tcl 8.4.20 (with this patch). The effect is that the "frame"
variable gets some extra space, and the the "somevar" variable
is moved farther away on the stack. When running it on
Tcl 8.4.19, this extra space is not used. But when running
it on Tcl 8.5 or Tcl 8.6, this space will be used by the
Tcl_PushCallFrame function! But this patch prevents that
the "somevar" is overwritten, so the bug is solved.

nijtmans added on 2010-07-18 06:00:28:
This is fully compatible, because the added fields are unused! The only effect is that in newly compiled code, a little more space is allocated than necessary. But this space is necessary when running under Tcl 8.6. It's exactly the same as (but better than)  the hack used in Itcl 3.4, only it can be used by all extensions using (Tcl_)?CallFrame.

Please provide an example where this causes a problem, before suggesting that I broke any compatibility. There isn't!

hobbs added on 2010-07-18 04:21:21:

allow_comments - 0

This seems like a misguided patch.  Adjusting the size of any public structure is a recipe for problems.  If this has been used in existing code, you may well have just broken compatibility for 8.4 and 8.5.  This doesn't seem like a safe enough approach.

nijtmans added on 2010-07-17 14:44:57:

allow_comments - 1

fixed in Tcl 8.5 and 8.4 branch

nijtmans added on 2010-07-17 14:36:07:

File Added - 380337: 3030870.patch

Attachments: