[fpc-devel] Const optimization is a serious bug
Chad Berchek
ad100 at vobarian.com
Mon Jul 11 02:45:36 CEST 2011
Sorry for the additional post; I should have added this to my preceding
message.
I just want to clarify: I am trying to be very careful to distinguish
between implementation and semantics.
If my understanding is correct, AnsiString implementation is always
pass-by-reference.
The problem is the programmer should be forced to stick to certain
semantics, not a certain implementation. With const AnsiString, the
implementation is consistently pass-by-ref, but the semantics can change
as described in my previous message, depending on the instance's
refcount when the procedure is invoked and what you may do with it while
the procedure is running.
It has correctly been pointed out that you therefore can't make an
assumption about what exactly a const AnsiString parameter will do; you
just have to be prepared in either case, and if it turns out to be by
reference, don't modify the instance via another reference.
I simply propose constref (existing) and constval (hyptothetical) for
those who come across situations where more precise programming would be
desired.
--- Implementation ---
I had a few ideas about implementation of constval, as I described it,
for AnsiString. (Or, alternatively, a way to change the behavior of
const, though this is no longer what I advocate.) These are all
speculative. These are some ideas, basically, not assertions. Also my
knowledge of how FPC works is limited as I've said before.
1. It seems that if a string is a (non-const) local variable it should
be safe. I base this on the following reasoning:
a) In order to trigger the undesired behavior, you have to get an
instance with a refcount of 1 which actually has more than one reference
to it. The only way to do this is to pass a reference to an instance
with a refcount of 1 to a function accepting a const AnsiString
parameter. (Aside: The critical value is 1 because that determines
whether copy-on-write happens and whether it gets freed the next time
the refcount is decremented.)
b) Furthermore, you must be able to access the non-const reference at a
higher scope (object, class, or global).
c) To do this, you could either have a higher-scope variable which you
assign to a local variable, or vice versa.
d) If you do either of these, the refcount becomes 2 and the problem
cannot occur.
e) The problem cannot be triggered passing a local variable.
2. Implementing 1 would require that the reference count update can be
applied or not applied to a specific function depending how it's called.
This could be done in two ways I'm thinking of:
a) Move the responsibility for updating the refcount to the caller.
There are pros and cons to this idea. It could result in slightly larger
code (because the refcount update and try-finally are in more places).
However I think it could also speed things up *even more than the
current implementation* because the refcount updates for several
non-const strings could be combined into a single try-finally in the
caller, rather than having one in each function.
b) Another possibility is to have two entry points to the function. The
update of the refcount and try-finally would remain in the function, not
the caller. However the caller could enter the function at either of two
entry points. One would do the refcount update and set up the
try-finally, whereas the other would skip to the code after that. I
don't know if this is even possible. It seemed like something that might
be doable with some tweaking when I was looking at the assembly code.
More information about the fpc-devel
mailing list