-
Notifications
You must be signed in to change notification settings - Fork 1.7k
[dart:ffi] Unnecessary constraints on packed nested structs #46644
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
/cc @dcharkes |
@timsneath, in this case it works because However, if typedef struct tagRECT
{
LONG left;
LONG top;
uint8_t right;
LONG bottom;
} RECT, *PRECT, NEAR *NPRECT, FAR *LPRECT; Then its layout would be different packed or non-packed. Code generated for The current analysis does not check whether any of the members would be unaligned if packing is enabled, so it is too conservative. I think we have multiple options here:
Illustration of C compiler when using pointers: https://godbolt.org/z/9vz9W8EEa uint32_t UseRect(RECT* rect){
// Loads from offset 12 for bottom: ldr r0, [r0, #12]
return rect->bottom;
}
Any preference for one of the options @mkustermann @cskau-g ? |
There's a few things here:
I suggest to implement option a) above - which should fix @timsneath 's issue without downsides. This seems to be a quite rare case, so we can leave it there for now (until we actually have user demand for nesting with floating point types). |
Changing all loads to unaligned loads to fit a single usecase is quite destructive (performance-wise). Outside of FP, LDRD/STRD on ARMv7 requires 4-byte alignment. Otherwise 64-bit load/stores would need two instructions. The way Rust handles this is by restricting the creation of references to unaligned fields. This allows code to still rely on alignment. In the above example, if you needed to pass a reference to the RECT to some other function for mutation, you'd have to copy it to stack first. https://rust.godbolt.org/z/1EGnK48hT |
I am trying to write a generator for I am not using Error:
C++ code: // in isteamnetworkingmessage.h
#pragma pack( push, 1 )
struct SteamNetworkingMessagesSessionFailed_t
{
SteamNetConnectionInfo_t m_info;
};
#pragma pack(pop)
// in steamnetworkingtypes.h
#pragma pack( push, 4 )
struct SteamNetConnectionInfo_t
{
SteamNetworkingIdentity m_identityRemote;
int64 m_nUserData;
HSteamListenSocket m_hListenSocket;
uint16 m__pad1;
SteamNetworkingPOPID m_idPOPRemote;
SteamNetworkingPOPID m_idPOPRelay;
ESteamNetworkingConnectionState m_eState;
int m_eEndReason;
char m_szEndDebug[ k_cchSteamNetworkingMaxConnectionCloseReason ];
char m_szConnectionDescription[ k_cchSteamNetworkingMaxConnectionDescription ];
int m_nFlags;
uint32 reserved[63];
};
#pragma pack(pop)
Generated dart code: @Packed(1)
class SteamNetworkingMessagesSessionFailed extends Struct {
external SteamNetConnectionInfo info;
}
@Packed(4)
class SteamNetConnectionInfo extends Struct {
external SteamNetworkingIdentity identityRemote;
@LongLong()
external int userData;
@UnsignedInt()
external HSteamListenSocket listenSocket;
external SteamNetworkingIpAddr addrRemote;
@UnsignedShort()
external int pad1;
@UnsignedInt()
external SteamNetworkingPOPId dPOPRemote;
@UnsignedInt()
external SteamNetworkingPOPId dPOPRelay;
@Int32()
external ESteamNetworkingConnectionState state;
@Int()
external int endReason;
external Pointer<Utf8> endDebug;
external Pointer<Utf8> connectionDescription;
@Int()
external int flags;
@Array<UnsignedInt>(63)
external Array<UnsignedInt> reserved;
} |
Yeah, this is the same issue, @aeb-dev. What I see in https://stackoverflow.com/a/49132034 is that Dart is stricter than compiler convention (packing instructions are not transitive, therefore Dart should not enforce transitiveness). Given that we now have two common examples of this (Steamworks and Windows), I'd like to advocate for a loosening of our approach. |
Fix underway: https://dart-review.googlesource.com/c/sdk/+/247382 Should we keep analyzer warnings/hints just in case people do it by accident? These warnings/hints can then be ignored with a class Foo extends Struct {
external Pointer<Uint8> notEmpty;
}
@Packed(1)
class Bar extends Struct {
external Pointer<Uint8> notEmpty;
// ignore: packed_nesting_non_packed
external Foo nestedNotPacked;
} In |
We could add an optional lint, but my understanding is that we try to avoid
likely false positive in the lints package recommended list.
…On Mon, Jun 6, 2022 at 12:32 PM Daco Harkes ***@***.***> wrote:
Fix underway: https://dart-review.googlesource.com/c/sdk/+/247382
Should we keep analyzer warnings/hints just in case people do it by
accident? These warnings/hints can then be ignored with a // ignore to
signal intent.
class Foo extends Struct {
external Pointer<Uint8> notEmpty;
}
@PACKED(1)class Bar extends Struct {
external Pointer<Uint8> notEmpty;
// ignore: packed_nesting_non_packed
external Foo nestedNotPacked;
}
In package:ffigen people could add // ignore_for_file:
packed_nesting_non_packed to the preamble if needed.
—
Reply to this email directly, view it on GitHub
<#46644 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AARWL66BN6HBAKHCFYU5T2DVNZG27ANCNFSM5AP42GKA>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
@mit-mit who do we cc on lint/hint/warning questions? |
Take the following example:
FFI complains with the error:
This is unnecessarily restrictive. The equivalent C code is fine, as best as I can infer (here's the original that I'm mapping):
and in a separate file without a
#pragma
directive:Any thoughts, @dcharkes? Marking
RECT
with@Packed(1)
is not an option, since this is being auto-generated from the original header file.The text was updated successfully, but these errors were encountered: