FFI: Detect type punning through unions.

This commit is contained in:
Mike Pall 2012-08-27 20:52:15 +02:00
parent 76b18b2b46
commit c7826af5a0
2 changed files with 29 additions and 19 deletions

View File

@ -192,8 +192,8 @@ a <tt>typedef</tt>, except re-declarations will be ignored):
</ul> </ul>
<p> <p>
You're encouraged to use these types in preference to the You're encouraged to use these types in preference to
compiler-specific extensions or the target-dependent standard types. compiler-specific extensions or target-dependent standard types.
E.g. <tt>char</tt> differs in signedness and <tt>long</tt> differs in E.g. <tt>char</tt> differs in signedness and <tt>long</tt> differs in
size, depending on the target architecture and platform ABI. size, depending on the target architecture and platform ABI.
</p> </p>
@ -660,12 +660,18 @@ initialization. The JIT compiler benefits from this fact when applying
certain optimizations. certain optimizations.
</p> </p>
<p> <p>
As a consequence of this, the <em>elements</em> of complex numbers and As a consequence, the <em>elements</em> of complex numbers and
vectors are immutable. But the elements of an aggregate holding these vectors are immutable. But the elements of an aggregate holding these
types <em>may</em> be modified of course. I.e. you cannot assign to types <em>may</em> be modified of course. I.e. you cannot assign to
<tt>foo.c.im</tt>, but you can assign a (newly created) complex number <tt>foo.c.im</tt>, but you can assign a (newly created) complex number
to <tt>foo.c</tt>. to <tt>foo.c</tt>.
</p> </p>
<p>
The JIT compiler implements strict aliasing rules: accesses to different
types do <b>not</b> alias, except for differences in signedness (this
applies even to <tt>char</tt> pointers, unlike C99). Type punning
through unions is explicitly detected and allowed.
</p>
<h3 id="cdata_call">Calling a cdata object</h3> <h3 id="cdata_call">Calling a cdata object</h3>
<ul> <ul>

View File

@ -601,17 +601,8 @@ static AliasRet aa_xref(jit_State *J, IRIns *refa, IRIns *xa, IRIns *xb)
ptrdiff_t ofsa = 0, ofsb = 0; ptrdiff_t ofsa = 0, ofsb = 0;
IRIns *refb = IR(xb->op1); IRIns *refb = IR(xb->op1);
IRIns *basea = refa, *baseb = refb; IRIns *basea = refa, *baseb = refb;
/* This implements (very) strict aliasing rules. if (refa == refb && irt_sametype(xa->t, xb->t))
** Different types do NOT alias, except for differences in signedness. return ALIAS_MUST; /* Shortcut for same refs with identical type. */
** NYI: this also prevents type punning through unions.
*/
if (irt_sametype(xa->t, xb->t)) {
if (refa == refb)
return ALIAS_MUST; /* Shortcut for same refs with identical type. */
} else if (!(irt_typerange(xa->t, IRT_I8, IRT_U64) &&
((xa->t.irt - IRT_I8) ^ (xb->t.irt - IRT_I8)) == 1)) {
return ALIAS_NO;
}
/* Offset-based disambiguation. */ /* Offset-based disambiguation. */
if (refa->o == IR_ADD && irref_isk(refa->op2)) { if (refa->o == IR_ADD && irref_isk(refa->op2)) {
IRIns *irk = IR(refa->op2); IRIns *irk = IR(refa->op2);
@ -629,12 +620,25 @@ static AliasRet aa_xref(jit_State *J, IRIns *refa, IRIns *xa, IRIns *xb)
if (refa == baseb && ofsb != 0) if (refa == baseb && ofsb != 0)
return ALIAS_NO; /* base vs. base+-ofs. */ return ALIAS_NO; /* base vs. base+-ofs. */
} }
/* This implements (very) strict aliasing rules.
** Different types do NOT alias, except for differences in signedness.
** Type punning through unions is allowed (but forces a reload).
*/
if (basea == baseb) { if (basea == baseb) {
/* This assumes strictly-typed, non-overlapping accesses. */ ptrdiff_t sza = irt_size(xa->t), szb = irt_size(xb->t);
if (ofsa != ofsb) if (ofsa == ofsb) {
return ALIAS_NO; /* base+-o1 vs. base+-o2 and o1 != o2. */ if (sza == szb && irt_isfp(xa->t) == irt_isfp(xb->t))
return ALIAS_MUST; /* Unsigned vs. signed access to the same address. */ return ALIAS_MUST; /* Same-sized, same-kind. May need to convert. */
} else if (ofsa + sza <= ofsb || ofsb + szb <= ofsa) {
return ALIAS_NO; /* Non-overlapping base+-o1 vs. base+-o2. */
}
/* NYI: extract, extend or reinterpret bits (int <-> fp). */
return ALIAS_MAY; /* Overlapping or type punning: force reload. */
} }
if (!irt_sametype(xa->t, xb->t) &&
!(irt_typerange(xa->t, IRT_I8, IRT_U64) &&
((xa->t.irt - IRT_I8) ^ (xb->t.irt - IRT_I8)) == 1))
return ALIAS_NO;
/* NYI: structural disambiguation. */ /* NYI: structural disambiguation. */
return aa_cnew(J, basea, baseb); /* Try to disambiguate allocations. */ return aa_cnew(J, basea, baseb); /* Try to disambiguate allocations. */
} }
@ -730,7 +734,7 @@ retry:
if (st == IRT_I8 || st == IRT_I16) { /* Trunc + sign-extend. */ if (st == IRT_I8 || st == IRT_I16) { /* Trunc + sign-extend. */
st |= IRCONV_SEXT; st |= IRCONV_SEXT;
} else if (st == IRT_U8 || st == IRT_U16) { /* Trunc + zero-extend. */ } else if (st == IRT_U8 || st == IRT_U16) { /* Trunc + zero-extend. */
} else if (st == IRT_INT && !irt_isint(IR(store->op2)->t)) { } else if (st == IRT_INT) {
st = irt_type(IR(store->op2)->t); /* Needs dummy CONV.int.*. */ st = irt_type(IR(store->op2)->t); /* Needs dummy CONV.int.*. */
} else { /* I64/U64 are boxed, U32 is hidden behind a CONV.num.u32. */ } else { /* I64/U64 are boxed, U32 is hidden behind a CONV.num.u32. */
goto store_fwd; goto store_fwd;