Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
ec487bf3
R
Rust
项目概览
int
/
Rust
大约 1 年 前同步成功
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
Rust
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
ec487bf3
编写于
3月 13, 2021
作者:
B
bors
浏览文件
操作
浏览文件
下载
差异文件
Auto merge of #82760 - WaffleLapkin:unleak_extend_from_within, r=kennytm
Fix leak in Vec::extend_from_within Fixes #82533
上级
f42888c1
1f031d95
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
70 addition
and
15 deletion
+70
-15
library/alloc/src/vec/mod.rs
library/alloc/src/vec/mod.rs
+28
-15
library/alloc/tests/vec.rs
library/alloc/tests/vec.rs
+42
-0
未找到文件。
library/alloc/src/vec/mod.rs
浏览文件 @
ec487bf3
...
...
@@ -1942,6 +1942,18 @@ pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] {
#[unstable(feature
=
"vec_split_at_spare"
,
issue
=
"81944"
)]
#[inline]
pub
fn
split_at_spare_mut
(
&
mut
self
)
->
(
&
mut
[
T
],
&
mut
[
MaybeUninit
<
T
>
])
{
// SAFETY:
// - len is ignored and so never changed
let
(
init
,
spare
,
_
)
=
unsafe
{
self
.split_at_spare_mut_with_len
()
};
(
init
,
spare
)
}
/// Safety: changing returned .2 (&mut usize) is considered the same as calling `.set_len(_)`.
///
/// This method is used to have unique access to all vec parts at once in `extend_from_within`.
unsafe
fn
split_at_spare_mut_with_len
(
&
mut
self
,
)
->
(
&
mut
[
T
],
&
mut
[
MaybeUninit
<
T
>
],
&
mut
usize
)
{
let
Range
{
start
:
ptr
,
end
:
spare_ptr
}
=
self
.as_mut_ptr_range
();
let
spare_ptr
=
spare_ptr
.cast
::
<
MaybeUninit
<
T
>>
();
let
spare_len
=
self
.buf
.capacity
()
-
self
.len
;
...
...
@@ -1953,7 +1965,7 @@ pub fn split_at_spare_mut(&mut self) -> (&mut [T], &mut [MaybeUninit<T>]) {
let
initialized
=
slice
::
from_raw_parts_mut
(
ptr
,
self
.len
);
let
spare
=
slice
::
from_raw_parts_mut
(
spare_ptr
,
spare_len
);
(
initialized
,
spare
)
(
initialized
,
spare
,
&
mut
self
.len
)
}
}
}
...
...
@@ -2165,22 +2177,23 @@ trait ExtendFromWithinSpec {
impl
<
T
:
Clone
,
A
:
Allocator
>
ExtendFromWithinSpec
for
Vec
<
T
,
A
>
{
default
unsafe
fn
spec_extend_from_within
(
&
mut
self
,
src
:
Range
<
usize
>
)
{
let
initialized
=
{
let
(
this
,
spare
)
=
self
.split_at_spare_mut
();
// SAFETY:
// - caller guaratees that src is a valid index
let
to_clone
=
unsafe
{
this
.get_unchecked
(
src
)
};
to_clone
.iter
()
.cloned
()
.zip
(
spare
.iter_mut
())
.map
(|(
e
,
s
)|
s
.write
(
e
))
.count
()
};
// SAFETY:
// - len is increased only after initializing elements
let
(
this
,
spare
,
len
)
=
unsafe
{
self
.split_at_spare_mut_with_len
()
};
// SAFETY:
// - elements were just initialized
unsafe
{
let
new_len
=
self
.len
()
+
initialized
;
self
.set_len
(
new_len
);
}
// - caller guaratees that src is a valid index
let
to_clone
=
unsafe
{
this
.get_unchecked
(
src
)
};
to_clone
.iter
()
.cloned
()
.zip
(
spare
.iter_mut
())
.map
(|(
src
,
dst
)|
dst
.write
(
src
))
// Note:
// - Element was just initialized with `MaybeUninit::write`, so it's ok to increace len
// - len is increased after each element to prevent leaks (see issue #82533)
.for_each
(|
_
|
*
len
+=
1
);
}
}
...
...
library/alloc/tests/vec.rs
浏览文件 @
ec487bf3
...
...
@@ -7,6 +7,7 @@
use
std
::
ops
::
Bound
::
*
;
use
std
::
panic
::{
catch_unwind
,
AssertUnwindSafe
};
use
std
::
rc
::
Rc
;
use
std
::
sync
::
atomic
::{
AtomicU32
,
Ordering
};
use
std
::
vec
::{
Drain
,
IntoIter
};
struct
DropCounter
<
'a
>
{
...
...
@@ -2100,3 +2101,44 @@ fn test_extend_from_within() {
assert_eq!
(
v
,
[
"a"
,
"b"
,
"c"
,
"b"
,
"c"
,
"a"
,
"b"
]);
}
// Regression test for issue #82533
#[test]
fn
test_extend_from_within_panicing_clone
()
{
struct
Panic
<
'dc
>
{
drop_count
:
&
'dc
AtomicU32
,
aaaaa
:
bool
,
}
impl
Clone
for
Panic
<
'_
>
{
fn
clone
(
&
self
)
->
Self
{
if
self
.aaaaa
{
panic!
(
"panic! at the clone"
);
}
Self
{
..*
self
}
}
}
impl
Drop
for
Panic
<
'_
>
{
fn
drop
(
&
mut
self
)
{
self
.drop_count
.fetch_add
(
1
,
Ordering
::
SeqCst
);
}
}
let
count
=
core
::
sync
::
atomic
::
AtomicU32
::
new
(
0
);
let
mut
vec
=
vec!
[
Panic
{
drop_count
:
&
count
,
aaaaa
:
false
},
Panic
{
drop_count
:
&
count
,
aaaaa
:
true
},
Panic
{
drop_count
:
&
count
,
aaaaa
:
false
},
];
// This should clone&append one Panic{..} at the end, and then panic while
// cloning second Panic{..}. This means that `Panic::drop` should be called
// 4 times (3 for items already in vector, 1 for just appended).
//
// Previously just appended item was leaked, making drop_count = 3, instead of 4.
std
::
panic
::
catch_unwind
(
move
||
vec
.extend_from_within
(
..
))
.unwrap_err
();
assert_eq!
(
count
.load
(
Ordering
::
SeqCst
),
4
);
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录