Clarify interaction of shared with effective type for accesses
Issue #110
new
Originally reported on Google Code with ID 110
In the process of researching some related issues, I discovered a small but significant
"hole" in UPC's current type system. In a nutshell:
shared int x;
int main() {
if (MYTHREAD == 0) {
int *p = (int *)&x;
*p = *p + 1; // permitted?
}
return 0;
}
I suspect everyone agrees this should be permitted, and I believe that all current
implementations consider this fully correct and permissible.
The problem is that by a careful reading of C99 6.5, these accesses are prohibited:
6.5-6
The effective type of an object for an access to its stored value is the declared
type of the
object, if any
=> This implies the "effective" type of x is (shared int)
6.5-7
An object shall have its stored value accessed only by an lvalue expression that
has one of
the following types:
..
- a type compatible with the effective type of the object,
- a qualified version of a type compatible with the effective type of the object,
=> This access falls under the first case, which requires the type of *p to be compatible
with the "effective" type of x which is (shared int).
But the type of *p is (int).
6.2.7
Two types have compatible type if their types are the same. Additional rules for
determining whether two types are compatible are described in 6.7.2 for type specifiers,
in 6.7.3 for type qualifiers, and in 6.7.5 for declarators.46
6.7.3-9
For two qualified types to be compatible, both shall have the identically qualified
version
of a compatible type; the order of type qualifiers within a list of specifiers or
qualifiers
does not affect the specified type.
=> This implies that (shared int) and (int) are not compatible types.
This problem has existed since the inception of UPC. It basically arises because we
define shared as a type qualifier for syntactic convenience, whereas semantically it's
really more of a storage-class specifier. Because shared is defined as a qualifier,
it inherits the C99 details of how qualifiers affect type compatibility, and the resulting
impact on access restrictions. In the case of the C99 qualifiers (const, restrict,
volatile), these restrictions "make sense" and prohibit illegal accesses that attempt
to bypass qualifiers. But in the case of "shared", the resulting restriction is "too
strong" and prohibits accesses that we wish to permit.
The same issue also affects code like the following:
shared [10] int A[10*THREADS];
shared [] int *q = (shared [] int *)&(A[0]);
*q = *q + 1;
The effective type of A[0] here is (shared [10] int), and the type of the lvalue *q
is (shared [] int).
However by UPC 6.5.1.1-13: The block size is a part of the type compatibility
So the access is also prohibited by C99 6.5-7.
In general, the shared qualifier still needs to be a part of type compatibility (especially
as related to compatibility of pointers). However I believe we need to clarify how
shared interacts with the access restriction in 6.5-7.
Initial proposal:
---------------------------------------
Add a new paragraph to UPC 6.5.1.1 Semantics:
The {\it effective type} of a shared object is the type as determined
by [ISO/IEC00 Sec. 6.5], with the shared qualifier removed.
\footnote{For example, in this declaration:
shared [10] int A[10*THREADS];
The effective type of the object A[0] is "int".
This implies the following lvalue expressions are all permitted for accessing
the object:
int x1 = A[0];
int x2 = *(int *)&(A[0]); // valid only for MYTHREAD==0
int x3 = *(shared [] int *)&(A[0]);
}
---------------------------------------
This fixes the problem by removing the shared qualifier from the effective type of
a shared object being accessed. Consequently, C99 6.5-7 will allow access via an lvalue
expression that either lacks a shared qualifier, or has a shared qualifier with any
blocksize.
I don't know whether this belongs in 1.3 or a later revision, but either way I believe
it should have NO impact on existing implementations or applications. We're just clarifying
the spec details to reflect the implicit understanding that I believe we've had all
along.
Reported by danbonachea
on 2013-03-15 12:51:09
Comments (6)
-
Account Deleted -
Account Deleted Below is an actual Latex diff proposal. This version also clarifies that the top-level shared qualifier is the one removed when computing the effective type. Specifically, for a "tricky" object like: shared int * shared p; the effective type of p is (shared int *). --- upc-language.tex (revision 204) +++ upc-language.tex (working copy) @@ -559,6 +568,21 @@ \np For purposes of assignment compatibility, generic pointers-to-shared behave as if they always have a compatible block size. + +\np \xadded[id=DB]{110}{ + The {\it effective type} of a shared object + is the type as determined by [ISO/IEC00 Sec. 6.5], + with the top-level (rightmost) shared qualifier removed.% + \truefootnote{For example, in the file-scope declaration {\tt shared [10] int A[10*THREADS];} + the effective type of the object {\tt A[0]} is {\tt int}. + This implies the following lvalue expressions are all permitted for accessing the object: + \begin{quote} + {\tt int x1 = A[0];}\\ + {\tt int x2 = *(int *)\&(A[0]); // valid only for MYTHREAD==0}\\ + {\tt int x3 = *(shared [] int *)\&(A[0]); } + \end{quote} + } + } \np If the layout qualifier is of the form `{\bf [ * ]}', the shared object is distributed as if it had a block size of
Reported by
danbonachea
on 2013-03-15 17:45:31 -
Account Deleted > Given that the issue clarifications noted in this issue "should have NO impact on existing > implementations or applications" (as Dan states), I recommend that this issue be deferred to Spec. > version 1.4. There are already several other clarifications to the definition and use of > layout qualifiers that have been deferred to 1.4 for example. It's worth noting that while it has "no impact" on existing applications, most non-trivial applications are nonetheless very heavily reliant upon the implicit understanding of the core concept being clarified here. This is in contrast to issues like issue 69 which are merely a corner case of the type system where we can get away with saying "just don't do that" because the ambiguity is easily avoided in user code. One can make a convincing case that without this clarification, most real UPC applications are relying upon undefined behavior.
Reported by
danbonachea
on 2013-03-15 17:49:38 - Labels added: Priority-Critical - Labels removed: Priority-High -
Account Deleted In the 3/15/13 telecon, we decided that we should try to resolve this issue in spec 1.3. Official change proposal mailed 3/15/13: Proposed Change: ------------------------- --- upc-language.tex (revision 204) +++ upc-language.tex (working copy) @@ -559,6 +568,22 @@ \np For purposes of assignment compatibility, generic pointers-to-shared behave as if they always have a compatible block size. + +\np \xadded[id=DB]{110}{ + The {\it effective type} of a shared object + is the type as determined by [ISO/IEC00 Sec. 6.5], + with the top-level (rightmost) shared qualifier removed.% + \truefootnote{For example, in the file-scope declaration {\tt shared [10] int A[10*THREADS];} + the effective type of the object {\tt A[0]} is {\tt int}. + This implies the following lvalue expressions are all permitted for accessing the object: + % DOB: would like to use verbatim environment here, but Latex does not allow it in a footnote + \begin{quote} + {\tt int x1 = A[0];}\\ + {\tt int x2 = *(int *)\&(A[0]); // valid only for MYTHREAD==0}\\ + {\tt int x3 = *(shared [] int *)\&(A[0]); } + \end{quote} + } + } \np If the layout qualifier is of the form `{\bf [ * ]}', the shared object is distributed as if it had a block size of
Reported by
danbonachea
on 2013-03-16 01:31:49 - Status changed:PendingApproval
-
Account Deleted Committed as SVN r212
Reported by
danbonachea
on 2013-04-30 18:34:45 - Status changed:Fixed
-
Account Deleted Ratified in the 5/22 telecon.
Reported by
danbonachea
on 2013-08-03 03:55:37 - Status changed:Ratified
- Log in to comment
Reported by
gary.funck
on 2013-03-15 15:47:55