C11 alinea contra clang -Wcast-align

 C Programming >> Programación C >  >> Tags >> Clang
C11 alinea contra clang -Wcast-align


Así que tengo el siguiente código C11 minimizado que define una estructura que contiene un uint16_t (lo que significa que la estructura debe estar alineada a 2 bytes) y quiero convertir un búfer de caracteres en un puntero a esa estructura.


Con todas las advertencias, clang se quejó con razón de que no se cumplen los requisitos de alineación de la estructura. Así que agregué un C11 alignas especificador al búfer para asegurarse de que el búfer esté lo suficientemente alineado, pero eso no se detuvo.


Mi pregunta es:¿estoy haciendo algo mal con alignas? ? ¿O es solo que el diagnóstico -Wcast-align solo analiza el tipo de argumentos y no también la alineación especificada manualmente? (Me doy cuenta de que puedo lanzar a void* para silenciar el diagnóstico, pero dado que se supone que este fragmento de código es portátil, no quiero eludir el diagnóstico a menos que esté seguro de que es un falso positivo).


#include <stdint.h>
#include <stdalign.h>
struct foo {
uint16_t field1;
};
int main(void) {
alignas(struct foo) char buffer[122] = {0};
struct foo *foo = (struct foo*)buffer;
return foo->field1;
}

Opciones del compilador y mensaje de error:


$ clang -ggdb -O3 foo.c -Weverything -Werror -Wno-c++98-compat -Wno-c11-extensions
foo.c:11:23: error: cast from 'char *' to 'struct foo *' increases required alignment from 1 to 2 [-Werror,-Wcast-align]
struct foo *foo = (struct foo*)buffer;
^~~~~~~~~~~~~~~~~~~~~~~~~

Versión del compilador:


$ clang -v
clang version 3.5.1 (tags/RELEASE_351/final)
Target: x86_64-pc-linux-gnu
Thread model: posix
Selected GCC installation: /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.4

Actualización:
No hay ninguna advertencia cuando muevo el búfer y su alineación en una estructura. Interpreto esto como una pista de que clang solo mira los tipos de esta advertencia.


#include <stdint.h>
#include <stdalign.h>
struct foo {
uint16_t field1;
};
struct bar {
alignas(struct foo) char buffer[122];
};
int main(void) {
struct bar bar = {{0}};
struct foo *foo = (struct foo*)&bar;
return foo->field1;
}

Respuestas:


De la fuente clang, en SemaChecking.cpp:~7862, parece que solo están mirando tipos como los que mencionas:


  CharUnits SrcAlign = Context.getTypeAlignInChars(SrcPointee);
if (SrcAlign >= DestAlign) return;
// else warn...

Me parece que clang se está preparando para un lanzamiento de estilo c que a su vez verificará la alineación del lanzamiento.


void CastOperation::CheckCStyleCast()
-> Kind = CastKind Sema::PrepareScalarCast(...);
-> if (Kind == CK_BitCast)
checkCastAlign();
void checkCastAlign() {
Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange);
}

Aquí está el método con un poco más de contexto:


/// CheckCastAlign - Implements -Wcast-align, which warns when a
/// pointer cast increases the alignment requirements.
void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) {
// This is actually a lot of work to potentially be doing on every
// cast; don't do it if we're ignoring -Wcast_align (as is the default).
if (getDiagnostics().isIgnored(diag::warn_cast_align, TRange.getBegin()))
return;
// Ignore dependent types.
if (T->isDependentType() || Op->getType()->isDependentType())
return;
// Require that the destination be a pointer type.
const PointerType *DestPtr = T->getAs<PointerType>();
if (!DestPtr) return;
// If the destination has alignment 1, we're done.
QualType DestPointee = DestPtr->getPointeeType();
if (DestPointee->isIncompleteType()) return;
CharUnits DestAlign = Context.getTypeAlignInChars(DestPointee);
if (DestAlign.isOne()) return;
// Require that the source be a pointer type.
const PointerType *SrcPtr = Op->getType()->getAs<PointerType>();
if (!SrcPtr) return;
QualType SrcPointee = SrcPtr->getPointeeType();
// Whitelist casts from cv void*. We already implicitly
// whitelisted casts to cv void*, since they have alignment 1.
// Also whitelist casts involving incomplete types, which implicitly
// includes 'void'.
if (SrcPointee->isIncompleteType()) return;
CharUnits SrcAlign = Context.getTypeAlignInChars(SrcPointee);
if (SrcAlign >= DestAlign) return;
Diag(TRange.getBegin(), diag::warn_cast_align)
<< Op->getType() << T
<< static_cast<unsigned>(SrcAlign.getQuantity())
<< static_cast<unsigned>(DestAlign.getQuantity())
<< TRange << Op->getSourceRange();
}
static const Type* getElementType(const Expr *BaseExpr) {
const Type* EltType = BaseExpr->getType().getTypePtr();
if (EltType->isAnyPointerType())
return EltType->getPointeeType().getTypePtr();
else if (EltType->isArrayType())
return EltType->getBaseElementTypeUnsafe();
return EltType;
}