Skip to content

rust: alloc: implement try_format! macro #478

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

Open
wants to merge 4 commits into
base: rust
Choose a base branch
from

Conversation

jablonskim
Copy link

@jablonskim jablonskim commented Aug 3, 2021

Implement try_format! macro - an equivalent of format! that will never panic on memory allocation failure. It returns an error instead.

The try_format! macro uses a StringWriter helper internally that implements Write trait for a String in a way that never panics during memory allocation.

The usage of try_format! is demonstrated in the rust_minimal sample module.

Based on #476.

This commit adds the following methods to `String` structure:
  - `try_with_capacity`
  - `try_push_str`
  - `try_shrink_to_fit`
  - `try_push`
  - `try_into_boxed_str`

Those are panic-free equivalents of already existing methods.
They may be useful for `String` creation inside kernel code.

Signed-off-by: Mateusz Jabłoński <[email protected]>
/// ```
#[stable(feature = "kernel", since = "1.0.0")]
#[derive(Debug)]
pub struct StringWriter {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I do not like the name StringWriter. The information about the panic-free logic ant it's purpose is missing, but I had no better idea for the name to be descriptive but also short and clean. If you have any ideas for a better name, feel free to comment.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be pub.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have made it public because it seemed to me that it may be useful in some other places too. For example, one may use it like that:

let mut sw = StringWriter::try_with_capacity(0)?;
write!(&mut sw, "test {}\n", 1).unwrap();
write!(&mut sw, "test {}\n", 2).unwrap();
let s = sw.into_string()?;

What do you think?

The `StringWriter` type is a helper type, that implements `Write` trait
for a `String` type in a way that never panics during memory allocation.
Instead, if any memory allocation during all writing and formatting
operations executed on the `StringWriter` fail, it saves the error and
returns it as a result when the result of the writing and formatting
is requested.

Signed-off-by: Mateusz Jabłoński <[email protected]>
Implement `try_format!` macro - an equivalent of `format!` that will never
panic on memory allocation failure. It returns an error instead.

Signed-off-by: Mateusz Jabłoński <[email protected]>
ojeda pushed a commit that referenced this pull request Dec 20, 2021
Shuang reported that the following script:

 1) tc qdisc add dev ddd0 handle 10: parent 1: ets bands 8 strict 4 priomap 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7
 2) mausezahn ddd0  -A 10.10.10.1 -B 10.10.10.2 -c 0 -a own -b 00:c1:a0:c1:a0:00 -t udp &
 3) tc qdisc change dev ddd0 handle 10: ets bands 4 strict 2 quanta 2500 2500 priomap 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3

crashes systematically when line 2) is commented:

 list_del corruption, ffff8e028404bd30->next is LIST_POISON1 (dead000000000100)
 ------------[ cut here ]------------
 kernel BUG at lib/list_debug.c:47!
 invalid opcode: 0000 [#1] PREEMPT SMP NOPTI
 CPU: 0 PID: 954 Comm: tc Not tainted 5.16.0-rc4+ #478
 Hardware name: Red Hat KVM, BIOS 1.11.1-4.module+el8.1.0+4066+0f1aadab 04/01/2014
 RIP: 0010:__list_del_entry_valid.cold.1+0x12/0x47
 Code: fe ff 0f 0b 48 89 c1 4c 89 c6 48 c7 c7 08 42 1b 87 e8 1d c5 fe ff 0f 0b 48 89 fe 48 89 c2 48 c7 c7 98 42 1b 87 e8 09 c5 fe ff <0f> 0b 48 c7 c7 48 43 1b 87 e8 fb c4 fe ff 0f 0b 48 89 f2 48 89 fe
 RSP: 0018:ffffae46807a3888 EFLAGS: 00010246
 RAX: 000000000000004e RBX: 0000000000000007 RCX: 0000000000000202
 RDX: 0000000000000000 RSI: ffffffff871ac536 RDI: 00000000ffffffff
 RBP: ffffae46807a3a10 R08: 0000000000000000 R09: c0000000ffff7fff
 R10: 0000000000000001 R11: ffffae46807a36a8 R12: ffff8e028404b800
 R13: ffff8e028404bd30 R14: dead000000000100 R15: ffff8e02fafa2400
 FS:  00007efdc92e4480(0000) GS:ffff8e02fb600000(0000) knlGS:0000000000000000
 CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
 CR2: 0000000000682f48 CR3: 00000001058be000 CR4: 0000000000350ef0
 Call Trace:
  <TASK>
  ets_qdisc_change+0x58b/0xa70 [sch_ets]
  tc_modify_qdisc+0x323/0x880
  rtnetlink_rcv_msg+0x169/0x4a0
  netlink_rcv_skb+0x50/0x100
  netlink_unicast+0x1a5/0x280
  netlink_sendmsg+0x257/0x4d0
  sock_sendmsg+0x5b/0x60
  ____sys_sendmsg+0x1f2/0x260
  ___sys_sendmsg+0x7c/0xc0
  __sys_sendmsg+0x57/0xa0
  do_syscall_64+0x3a/0x80
  entry_SYSCALL_64_after_hwframe+0x44/0xae
 RIP: 0033:0x7efdc8031338
 Code: 89 02 48 c7 c0 ff ff ff ff eb b5 0f 1f 80 00 00 00 00 f3 0f 1e fa 48 8d 05 25 43 2c 00 8b 00 85 c0 75 17 b8 2e 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 58 c3 0f 1f 80 00 00 00 00 41 54 41 89 d4 55
 RSP: 002b:00007ffdf1ce9828 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
 RAX: ffffffffffffffda RBX: 0000000061b37a97 RCX: 00007efdc8031338
 RDX: 0000000000000000 RSI: 00007ffdf1ce9890 RDI: 0000000000000003
 RBP: 0000000000000000 R08: 0000000000000001 R09: 000000000078a940
 R10: 000000000000000c R11: 0000000000000246 R12: 0000000000000001
 R13: 0000000000688880 R14: 0000000000000000 R15: 0000000000000000
  </TASK>
 Modules linked in: sch_ets sch_tbf dummy rfkill iTCO_wdt iTCO_vendor_support intel_rapl_msr intel_rapl_common joydev pcspkr i2c_i801 virtio_balloon i2c_smbus lpc_ich ip_tables xfs libcrc32c crct10dif_pclmul crc32_pclmul crc32c_intel serio_raw ghash_clmulni_intel ahci libahci libata virtio_blk virtio_console virtio_net net_failover failover sunrpc dm_mirror dm_region_hash dm_log dm_mod [last unloaded: sch_ets]
 ---[ end trace f35878d1912655c2 ]---
 RIP: 0010:__list_del_entry_valid.cold.1+0x12/0x47
 Code: fe ff 0f 0b 48 89 c1 4c 89 c6 48 c7 c7 08 42 1b 87 e8 1d c5 fe ff 0f 0b 48 89 fe 48 89 c2 48 c7 c7 98 42 1b 87 e8 09 c5 fe ff <0f> 0b 48 c7 c7 48 43 1b 87 e8 fb c4 fe ff 0f 0b 48 89 f2 48 89 fe
 RSP: 0018:ffffae46807a3888 EFLAGS: 00010246
 RAX: 000000000000004e RBX: 0000000000000007 RCX: 0000000000000202
 RDX: 0000000000000000 RSI: ffffffff871ac536 RDI: 00000000ffffffff
 RBP: ffffae46807a3a10 R08: 0000000000000000 R09: c0000000ffff7fff
 R10: 0000000000000001 R11: ffffae46807a36a8 R12: ffff8e028404b800
 R13: ffff8e028404bd30 R14: dead000000000100 R15: ffff8e02fafa2400
 FS:  00007efdc92e4480(0000) GS:ffff8e02fb600000(0000) knlGS:0000000000000000
 CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
 CR2: 0000000000682f48 CR3: 00000001058be000 CR4: 0000000000350ef0
 Kernel panic - not syncing: Fatal exception in interrupt
 Kernel Offset: 0x4e00000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)
 ---[ end Kernel panic - not syncing: Fatal exception in interrupt ]---

we can remove 'q->classes[i].alist' only if DRR class 'i' was part of the
active list. In the ETS scheduler DRR classes belong to that list only if
the queue length is greater than zero: we need to test for non-zero value
of 'q->classes[i].qdisc->q.qlen' before removing from the list, similarly
to what has been done elsewhere in the ETS code.

Fixes: de6d259 ("net/sched: sch_ets: don't peek at classes beyond 'nbands'")
Reported-by: Shuang Li <[email protected]>
Signed-off-by: Davide Caratti <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants