Version 1.2 of ai05s/ai05-0157-1.txt
!standard 13.11.2(3) 09-06-02 AI05-0157-1/00
!class binding interpretation 09-06-02
!status work item 09-06-02
!status received 09-02-15
!priority Low
!difficulty Medium
!qualifier Omission
!subject Unchecked_Deallocation should be illegal for zero-sized pools
!summary
** TBD **
!question
RM-4.8(5.3/2) says:
5.3/2 {AI95-00366-01} An allocator shall not be of an access type for which
the Storage_Size has been specified by a static expression with value zero or
is defined by the language to be zero.
But there is not a similar rule for Unchecked_Deallocation. That means that
Unchecked_Deallocation can be instantiated for such types, and every call
to such an Unchecked_Deallocation is guaranteed to be erroneous.
Should such instances be illegal?
!recommendation
(See Summary.)
!wording
** TBD **
!discussion
We seem to have a number of choices here:
(1) Make the instance of Unchecked_Deallocation illegal. But this is
weird, because this is a legality check unrelated to the (normal) generic
contract. It would be a magic extra check.
(2) Raise Program_Error if such a generic instance is detected. This
is less weird, but it turns what otherwise would be a legality rule into
a runtime check. If it is a runtime check on cases that aren't currently
detected by the legality rule, it could have a negative impact on generics
that instantiate but do not call (in some cases) Unchecked_Deallocation.
(Imagine a generic that determines whether or not to call Free based on
an additional generic parameter; it would always have to instantiate it.)
(3) Raise Program_Error on the call of such a generic instance.
(4) Leave calling the instantiation erroneous, but add a permission for
an implementation to reject any program that it can detect would have
erroneous execution. (One wonders if a similar permission should be
allowed for Bounded Errors.) OTOH, this too could cause trouble for
any code conditionally compiled. Probably it would be better to follow
the rule in 1.1.5(6) (which suggests a warning when the compiler can
detect errors).
--!corrigendum 13.1(23)
!ACATS Test
!appendix
From: Bob Duff
Date: Sunday, February 15, 2009 11:17 AM
RM-4.8(5.3/2) says:
5.3/2 {AI95-00366-01} An allocator shall not be of an access type for which
the Storage_Size has been specified by a static expression with value zero or
is defined by the language to be zero.
But I can't find a similar rule for Unchecked_Deallocation. Seems like a hole,
to me. Unchecked_Deallocation should be illegal for such types, for the same
reasons as 4.8(5.3/2). Otherwise, every call to such an Unchecked_Deallocation
is guaranteed to be erroneous.
It's a nasty sort of erroneousness, because it will work fine on some
implementations.
****************************************************************
From: Robert Dewar
Date: Sunday, February 15, 2009 11:24 AM
Not likely, trying to allocate statically allocated stuff will most likely NOT
work and blow up! I agree this is an obvious hole. Bob, you should file this as
a bug if GNAT does not detect this case, and flag it as illegal.
****************************************************************
From: Bob Duff
Date: Sunday, February 15, 2009 12:22 PM
Sure, but the usual case is to allocate something with "new", then convert it to
another access type. If you then call U_D using the second access type, and
that has Storage_Size 0, GNAT will just deallocate the object. It won't blow up.
OK, just to be sure, I wrote this:
with Ada.Text_IO; use Ada.Text_IO;
with Unchecked_Deallocation;
procedure Main is
type A is access all String;
for A'Storage_Size use 0;
procedure Free is new Unchecked_Deallocation (String, A);
type Allocation_Type is access all String;
X : Allocation_Type := new String'("Hello, world.");
Y : A := A (X);
begin
Free (Y);
if Y = null then
Put_Line ("It's null.");
else
Put_Line ("It's not null.");
end if;
end Main;
It prints "It's null.". (A more realistic example would have various class-wide
types.)
The compiler warns, though: deallocation from empty storage pool.
So that's not so horrible.
>... I agree this is an obvious hole.
> Bob, you should file this as a bug if GNAT does not detect this case,
>and flag it as illegal.
Well, the current language doesn't make it illegal (except perhaps via "Robert's
Rule Of Absurdity") and we do give a warning...
****************************************************************
From: Tucker Taft
Date: Sunday, February 15, 2009 11:38 AM
I don't quite see how you can make it illegal (Unchecked_Deallocation is a
generic, after all), but you could define it to raise Program_Error (or perhaps
to do nothing?).
****************************************************************
From: Robert Dewar
Date: Sunday, February 15, 2009 11:42 AM
The instantiation should be illegal!
****************************************************************
From: Tucker Taft
Date: Sunday, February 15, 2009 12:03 PM
That could be a bit of a pain to implement for some. Generics can be renamed,
etc. At least in our implementation, there is nothing very special about
Unchecked_Deallocation until it is called, at which point we start treating it
specially.
****************************************************************
From: Robert Dewar
Date: Sunday, February 15, 2009 12:16 PM
How about then the following
a) a clear statement that instantiating UC or calling UC for such a type is
erroneous.
b) impl permission to make either the instantiation or the call illegal.
Actually it would make some sense to have impl permission that allows the
compiler to treat ANY recognized erroneous construct as illegal!
****************************************************************
From: Tucker Taft
Date: Sunday, February 15, 2009 12:51 PM
My only concern about this approach is one could imagine a generic that has a
formal access type and declares some kind of "Free" operation implemented using
Unchecked_Deallocation. The generic can reasonably be instantiated with an
access type with storage size zero, so long as the Free operation is never
called.
> Actually it would make some sense to have impl permission that allows
> the compiler to treat ANY recognized erroneous construct as illegal!
This would seem a natural extension of RM 1.1.5(6).
****************************************************************
From: Robert Dewar
Date: Sunday, February 15, 2009 1:07 PM
> My only concern about this approach is one could imagine a generic
> that has a formal access type and declares some kind of "Free"
> operation implemented using Unchecked_Deallocation. The generic can
> reasonably be instantiated with an access type with storage size zero,
> so long as the Free operation is never called.
That's a good argument, so it should be the Free operation that is always
erroneous, and impl permission to consider the call to Free to be illegal ...
****************************************************************
From: Bob Duff
Date: Sunday, February 15, 2009 12:12 PM
> I don't quite see how you can make it illegal (Unchecked_Deallocation
> is a generic, after all), but you could define it to raise
> Program_Error (or perhaps to do nothing?).
Not sure what you mean -- I'm proposing to make it illegal by adding a Legality
Rule:
For an instantiation of Unchecked_Deallocation, the generic actual
parameter for the Name generic formal parameter shall not have a
Storage_Size that has been specified by a static expression with value
zero, nor defined by the language to be zero.
Or:
An access type for which the Storage_Size has been specified by a static
expression with value zero or is defined by the language to be zero shall
not be passed to the Name parameter in an instantiation of
Unchecked_Deallocation.
Plus an AARM note: Including a renaming of Unchecked_Deallocation.
****************************************************************
From: Bob Duff
Date: Sunday, February 15, 2009 2:10 PM
> >> That could be a bit of a pain to implement for some.
> >> Generics can be renamed, etc. At least in our implementation,
> >> there is nothing very special about Unchecked_Deallocation until it
> >> is called, at which point we start treating it specially.
I have trouble believing this could be hard to implement in any compiler.
This is from the man who invented coextensions. ;-)
Seriously, during semantic analysis of an instantiation, you look in your symbol
table, and see if what you've got is called "unchecked_deallocation", and if its
parent is a root library unit called "ada". Yes, you have to follow renamings
-- big deal.
It's a special-case kludge. But it's not hard.
> > How about then the following
> >
> > a) a clear statement that instantiating UC or calling UC for such a
> > type is erroneous.
> >
> > b) impl permission to make either the instantiation or the call
> > illegal.
This is getting too complicated for my taste.
I'd rather leave the language alone.
We already have a warning, which is good enough in practise.
> My only concern about this approach is one could imagine a generic
> that has a formal access type and declares some kind of "Free"
> operation implemented using Unchecked_Deallocation. The generic can
> reasonably be instantiated with an access type with storage size zero,
> so long as the Free operation is never called.
The rule about "new" does not apply to such a generic formal type (I presume,
since otherwise it would be a contract model violation), and my proposed
legality rule should not apply to such a generic formal type. It only applies
if the Storage_Size is visibly and statically 0. So I think this is a red
herring.
****************************************************************
From: Randy Brukardt
Date: Tuesday, February 17, 2009 12:53 AM
> Seriously, during semantic analysis of an instantiation, you look in
> your symbol table, and see if what you've got is called
> "unchecked_deallocation", and if its parent is a root library unit
> called "ada". Yes, you have to follow renamings
> -- big deal.
>
> It's a special-case kludge. But it's not hard.
We've been *very* adverse to adding special-case kludges to generic
instantiations. Indeed, I proposed one to support the factory generic
(Generic_Dispatching_Constructor), and we decided instead to add the entire
mechanism to the language outright (abstract formal subprograms) -- which surely
was a lot more work.
I don't much care either way, BTW.
****************************************************************
From: Robert Dewar
Date: Tuesday, February 17, 2009 11:55 AM
> We've been *very* adverse to adding special-case kludges to generic
> instantiations.
I really think that Unchecked_Deallocation and Unchecked_Conversion are special
cases, they are really fundamental primitives in the language, which just happen
to be spelled as generics, but I don't see that we should let this aversion
cripple the definition in any way. In particular the rules for erroneousness are
already special.
****************************************************************
Questions? Ask the ACAA Technical Agent