Skip to content

Commit 95c26f5

Browse files
authored
lang: Fix Rust ICE when using declare_program! with unsafe zero copy accounts (solana-foundation#4131)
1 parent aaa6bdb commit 95c26f5

File tree

4 files changed

+111
-1
lines changed

4 files changed

+111
-1
lines changed

lang/attribute/program/src/declare_program/common.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,13 @@ pub fn convert_idl_type_def_to_ts(
146146
.flatten()
147147
.unwrap_or_default();
148148

149+
// `ser_attr` must be expanded first, as it may produce `repr(packed)`
150+
// This affects builtin derives so must be visible to them
151+
// https://github.com/solana-foundation/anchor/issues/4072
149152
quote! {
153+
#ser_attr
150154
#debug_attr
151155
#default_attr
152-
#ser_attr
153156
#clone_attr
154157
#copy_attr
155158
}

tests/declare-program/idls/external.json

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,25 @@
113113
"accounts": [],
114114
"args": []
115115
},
116+
{
117+
"name": "test_compilation_packed_account",
118+
"discriminator": [
119+
56,
120+
168,
121+
153,
122+
46,
123+
46,
124+
240,
125+
131,
126+
158
127+
],
128+
"accounts": [
129+
{
130+
"name": "packed_account"
131+
}
132+
],
133+
"args": []
134+
},
116135
{
117136
"name": "test_compilation_return_type",
118137
"discriminator": [
@@ -370,6 +389,19 @@
370389
50,
371390
42
372391
]
392+
},
393+
{
394+
"name": "PackedAccount",
395+
"discriminator": [
396+
87,
397+
129,
398+
238,
399+
130,
400+
11,
401+
67,
402+
95,
403+
44
404+
]
373405
}
374406
],
375407
"events": [
@@ -421,6 +453,37 @@
421453
}
422454
]
423455
}
456+
},
457+
{
458+
"name": "PackedAccount",
459+
"serialization": "bytemuckunsafe",
460+
"repr": {
461+
"kind": "rust",
462+
"packed": true
463+
},
464+
"type": {
465+
"kind": "struct",
466+
"fields": [
467+
{
468+
"name": "a",
469+
"type": {
470+
"array": [
471+
"u8",
472+
8
473+
]
474+
}
475+
},
476+
{
477+
"name": "b",
478+
"type": {
479+
"array": [
480+
"u16",
481+
8
482+
]
483+
}
484+
}
485+
]
486+
}
424487
}
425488
],
426489
"constants": [

tests/declare-program/programs/declare-program/tests/parsers.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,30 @@ pub fn test_account_parser() {
1616
// Correct discriminator and valid data
1717
match Account::parse(&[DISC, &[1, 0, 0, 0]].concat()) {
1818
Ok(Account::MyAccount(my_account)) => assert_eq!(my_account.field, 1),
19+
Ok(_) => panic!("Expected MyAccount account variant"),
20+
Err(e) => panic!("Expected Ok result, got error: {:?}", e),
21+
}
22+
23+
// Unsafe zero-copy account
24+
let packed_account = external::accounts::PackedAccount {
25+
a: [1; 8],
26+
b: [2; 8],
27+
};
28+
const PACKED_DISC: &[u8] = external::accounts::PackedAccount::DISCRIMINATOR;
29+
match Account::parse(
30+
&[
31+
PACKED_DISC,
32+
anchor_lang::__private::bytemuck::bytes_of(&packed_account),
33+
]
34+
.concat(),
35+
) {
36+
Ok(Account::PackedAccount(packed_account)) => {
37+
let a = packed_account.a;
38+
let b = packed_account.b;
39+
assert_eq!(a, [1; 8]);
40+
assert_eq!(b, [2; 8]);
41+
}
42+
Ok(_) => panic!("Expected PackedAccount account variant"),
1943
Err(e) => panic!("Expected Ok result, got error: {:?}", e),
2044
}
2145
}

tests/declare-program/programs/external/src/lib.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@ pub mod external {
107107
Ok(())
108108
}
109109

110+
// Compilation test for unsafe zero-copy accounts generated via `declare_program!`
111+
pub fn test_compilation_packed_account(
112+
_ctx: Context<TestCompilationPackedAccount>,
113+
) -> Result<()> {
114+
Ok(())
115+
}
116+
110117
// Compilation test for an instruction with no accounts
111118
pub fn test_compilation_no_accounts(_ctx: Context<TestCompilationNoAccounts>) -> Result<()> {
112119
Ok(())
@@ -132,6 +139,11 @@ pub struct TestCompilation<'info> {
132139
pub signer: Signer<'info>,
133140
}
134141

142+
#[derive(Accounts)]
143+
pub struct TestCompilationPackedAccount<'info> {
144+
pub packed_account: AccountLoader<'info, PackedAccount>,
145+
}
146+
135147
#[derive(Accounts)]
136148
pub struct TestCompilationNoAccounts {}
137149

@@ -203,6 +215,14 @@ pub struct MyAccount {
203215
pub field: u32,
204216
}
205217

218+
// Regression test for `declare_program!` codegen on `#[account(zero_copy(unsafe))]`
219+
// https://github.com/solana-foundation/anchor/issues/4072
220+
#[account(zero_copy(unsafe))]
221+
pub struct PackedAccount {
222+
pub a: [u8; 8],
223+
pub b: [u16; 8],
224+
}
225+
206226
#[event]
207227
pub struct MyEvent {
208228
pub value: u32,

0 commit comments

Comments
 (0)