Merge 455cdcb45f ("Merge tag 'rust-6.7' of https://github.com/Rust-for-Linux/linux") into android-mainline
Steps on the way to 6.7-rc1 Change-Id: Iac969751633fa04c87f55fd262227a24fe2be51f Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
@@ -31,7 +31,7 @@ you probably needn't concern yourself with pcmciautils.
|
||||
====================== =============== ========================================
|
||||
GNU C 5.1 gcc --version
|
||||
Clang/LLVM (optional) 11.0.0 clang --version
|
||||
Rust (optional) 1.71.1 rustc --version
|
||||
Rust (optional) 1.73.0 rustc --version
|
||||
bindgen (optional) 0.65.1 bindgen --version
|
||||
GNU make 3.82 make --version
|
||||
bash 4.2 bash --version
|
||||
|
||||
@@ -6,6 +6,25 @@ Rust
|
||||
Documentation related to Rust within the kernel. To start using Rust
|
||||
in the kernel, please read the quick-start.rst guide.
|
||||
|
||||
|
||||
The Rust experiment
|
||||
-------------------
|
||||
|
||||
The Rust support was merged in v6.1 into mainline in order to help in
|
||||
determining whether Rust as a language was suitable for the kernel, i.e. worth
|
||||
the tradeoffs.
|
||||
|
||||
Currently, the Rust support is primarily intended for kernel developers and
|
||||
maintainers interested in the Rust support, so that they can start working on
|
||||
abstractions and drivers, as well as helping the development of infrastructure
|
||||
and tools.
|
||||
|
||||
If you are an end user, please note that there are currently no in-tree
|
||||
drivers/modules suitable or intended for production use, and that the Rust
|
||||
support is still in development/experimental, especially for certain kernel
|
||||
configurations.
|
||||
|
||||
|
||||
.. only:: rustdoc and html
|
||||
|
||||
You can also browse `rustdoc documentation <rustdoc/kernel/index.html>`_.
|
||||
|
||||
+2
-1
@@ -18741,9 +18741,10 @@ R: Andreas Hindborg <a.hindborg@samsung.com>
|
||||
R: Alice Ryhl <aliceryhl@google.com>
|
||||
L: rust-for-linux@vger.kernel.org
|
||||
S: Supported
|
||||
W: https://github.com/Rust-for-Linux/linux
|
||||
W: https://rust-for-linux.com
|
||||
B: https://github.com/Rust-for-Linux/linux/issues
|
||||
C: zulip://rust-for-linux.zulipchat.com
|
||||
P: https://rust-for-linux.com/contributing
|
||||
T: git https://github.com/Rust-for-Linux/linux.git rust-next
|
||||
F: Documentation/rust/
|
||||
F: rust/
|
||||
|
||||
@@ -81,6 +81,7 @@ ifeq ($(CONFIG_X86_KERNEL_IBT),y)
|
||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104816
|
||||
#
|
||||
KBUILD_CFLAGS += $(call cc-option,-fcf-protection=branch -fno-jump-tables)
|
||||
KBUILD_RUSTFLAGS += -Zcf-protection=branch -Zno-jump-tables
|
||||
else
|
||||
KBUILD_CFLAGS += $(call cc-option,-fcf-protection=none)
|
||||
endif
|
||||
|
||||
+50
-9
@@ -219,6 +219,20 @@ static inline bool cap_ambient_invariant_ok(const struct cred *cred)
|
||||
cred->cap_inheritable));
|
||||
}
|
||||
|
||||
/**
|
||||
* get_new_cred_many - Get references on a new set of credentials
|
||||
* @cred: The new credentials to reference
|
||||
* @nr: Number of references to acquire
|
||||
*
|
||||
* Get references on the specified set of new credentials. The caller must
|
||||
* release all acquired references.
|
||||
*/
|
||||
static inline struct cred *get_new_cred_many(struct cred *cred, int nr)
|
||||
{
|
||||
atomic_add(nr, &cred->usage);
|
||||
return cred;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_new_cred - Get a reference on a new set of credentials
|
||||
* @cred: The new credentials to reference
|
||||
@@ -228,16 +242,16 @@ static inline bool cap_ambient_invariant_ok(const struct cred *cred)
|
||||
*/
|
||||
static inline struct cred *get_new_cred(struct cred *cred)
|
||||
{
|
||||
atomic_inc(&cred->usage);
|
||||
return cred;
|
||||
return get_new_cred_many(cred, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_cred - Get a reference on a set of credentials
|
||||
* get_cred_many - Get references on a set of credentials
|
||||
* @cred: The credentials to reference
|
||||
* @nr: Number of references to acquire
|
||||
*
|
||||
* Get a reference on the specified set of credentials. The caller must
|
||||
* release the reference. If %NULL is passed, it is returned with no action.
|
||||
* Get references on the specified set of credentials. The caller must release
|
||||
* all acquired reference. If %NULL is passed, it is returned with no action.
|
||||
*
|
||||
* This is used to deal with a committed set of credentials. Although the
|
||||
* pointer is const, this will temporarily discard the const and increment the
|
||||
@@ -245,14 +259,28 @@ static inline struct cred *get_new_cred(struct cred *cred)
|
||||
* accidental alteration of a set of credentials that should be considered
|
||||
* immutable.
|
||||
*/
|
||||
static inline const struct cred *get_cred(const struct cred *cred)
|
||||
static inline const struct cred *get_cred_many(const struct cred *cred, int nr)
|
||||
{
|
||||
struct cred *nonconst_cred = (struct cred *) cred;
|
||||
if (!cred)
|
||||
return cred;
|
||||
validate_creds(cred);
|
||||
nonconst_cred->non_rcu = 0;
|
||||
return get_new_cred(nonconst_cred);
|
||||
return get_new_cred_many(nonconst_cred, nr);
|
||||
}
|
||||
|
||||
/*
|
||||
* get_cred - Get a reference on a set of credentials
|
||||
* @cred: The credentials to reference
|
||||
*
|
||||
* Get a reference on the specified set of credentials. The caller must
|
||||
* release the reference. If %NULL is passed, it is returned with no action.
|
||||
*
|
||||
* This is used to deal with a committed set of credentials.
|
||||
*/
|
||||
static inline const struct cred *get_cred(const struct cred *cred)
|
||||
{
|
||||
return get_cred_many(cred, 1);
|
||||
}
|
||||
|
||||
static inline const struct cred *get_cred_rcu(const struct cred *cred)
|
||||
@@ -270,6 +298,7 @@ static inline const struct cred *get_cred_rcu(const struct cred *cred)
|
||||
/**
|
||||
* put_cred - Release a reference to a set of credentials
|
||||
* @cred: The credentials to release
|
||||
* @nr: Number of references to release
|
||||
*
|
||||
* Release a reference to a set of credentials, deleting them when the last ref
|
||||
* is released. If %NULL is passed, nothing is done.
|
||||
@@ -278,17 +307,29 @@ static inline const struct cred *get_cred_rcu(const struct cred *cred)
|
||||
* on task_struct are attached by const pointers to prevent accidental
|
||||
* alteration of otherwise immutable credential sets.
|
||||
*/
|
||||
static inline void put_cred(const struct cred *_cred)
|
||||
static inline void put_cred_many(const struct cred *_cred, int nr)
|
||||
{
|
||||
struct cred *cred = (struct cred *) _cred;
|
||||
|
||||
if (cred) {
|
||||
validate_creds(cred);
|
||||
if (atomic_dec_and_test(&(cred)->usage))
|
||||
if (atomic_sub_and_test(nr, &cred->usage))
|
||||
__put_cred(cred);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* put_cred - Release a reference to a set of credentials
|
||||
* @cred: The credentials to release
|
||||
*
|
||||
* Release a reference to a set of credentials, deleting them when the last ref
|
||||
* is released. If %NULL is passed, nothing is done.
|
||||
*/
|
||||
static inline void put_cred(const struct cred *cred)
|
||||
{
|
||||
put_cred_many(cred, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* current_cred - Access the current task's subjective credentials
|
||||
*
|
||||
|
||||
+1
-1
@@ -2478,7 +2478,7 @@ struct filename {
|
||||
};
|
||||
static_assert(offsetof(struct filename, iname) % sizeof(long) == 0);
|
||||
|
||||
static inline struct mnt_idmap *file_mnt_idmap(struct file *file)
|
||||
static inline struct mnt_idmap *file_mnt_idmap(const struct file *file)
|
||||
{
|
||||
return mnt_idmap(file->f_path.mnt);
|
||||
}
|
||||
|
||||
@@ -43,17 +43,17 @@ LSM_HOOK(int, 0, capset, struct cred *new, const struct cred *old,
|
||||
const kernel_cap_t *permitted)
|
||||
LSM_HOOK(int, 0, capable, const struct cred *cred, struct user_namespace *ns,
|
||||
int cap, unsigned int opts)
|
||||
LSM_HOOK(int, 0, quotactl, int cmds, int type, int id, struct super_block *sb)
|
||||
LSM_HOOK(int, 0, quotactl, int cmds, int type, int id, const struct super_block *sb)
|
||||
LSM_HOOK(int, 0, quota_on, struct dentry *dentry)
|
||||
LSM_HOOK(int, 0, syslog, int type)
|
||||
LSM_HOOK(int, 0, settime, const struct timespec64 *ts,
|
||||
const struct timezone *tz)
|
||||
LSM_HOOK(int, 0, vm_enough_memory, struct mm_struct *mm, long pages)
|
||||
LSM_HOOK(int, 0, bprm_creds_for_exec, struct linux_binprm *bprm)
|
||||
LSM_HOOK(int, 0, bprm_creds_from_file, struct linux_binprm *bprm, struct file *file)
|
||||
LSM_HOOK(int, 0, bprm_creds_from_file, struct linux_binprm *bprm, const struct file *file)
|
||||
LSM_HOOK(int, 0, bprm_check_security, struct linux_binprm *bprm)
|
||||
LSM_HOOK(void, LSM_RET_VOID, bprm_committing_creds, struct linux_binprm *bprm)
|
||||
LSM_HOOK(void, LSM_RET_VOID, bprm_committed_creds, struct linux_binprm *bprm)
|
||||
LSM_HOOK(void, LSM_RET_VOID, bprm_committing_creds, const struct linux_binprm *bprm)
|
||||
LSM_HOOK(void, LSM_RET_VOID, bprm_committed_creds, const struct linux_binprm *bprm)
|
||||
LSM_HOOK(int, 0, fs_context_submount, struct fs_context *fc, struct super_block *reference)
|
||||
LSM_HOOK(int, 0, fs_context_dup, struct fs_context *fc,
|
||||
struct fs_context *src_sc)
|
||||
@@ -66,7 +66,7 @@ LSM_HOOK(void, LSM_RET_VOID, sb_free_mnt_opts, void *mnt_opts)
|
||||
LSM_HOOK(int, 0, sb_eat_lsm_opts, char *orig, void **mnt_opts)
|
||||
LSM_HOOK(int, 0, sb_mnt_opts_compat, struct super_block *sb, void *mnt_opts)
|
||||
LSM_HOOK(int, 0, sb_remount, struct super_block *sb, void *mnt_opts)
|
||||
LSM_HOOK(int, 0, sb_kern_mount, struct super_block *sb)
|
||||
LSM_HOOK(int, 0, sb_kern_mount, const struct super_block *sb)
|
||||
LSM_HOOK(int, 0, sb_show_options, struct seq_file *m, struct super_block *sb)
|
||||
LSM_HOOK(int, 0, sb_statfs, struct dentry *dentry)
|
||||
LSM_HOOK(int, 0, sb_mount, const char *dev_name, const struct path *path,
|
||||
|
||||
+10
-10
@@ -151,7 +151,7 @@ extern int cap_capset(struct cred *new, const struct cred *old,
|
||||
const kernel_cap_t *effective,
|
||||
const kernel_cap_t *inheritable,
|
||||
const kernel_cap_t *permitted);
|
||||
extern int cap_bprm_creds_from_file(struct linux_binprm *bprm, struct file *file);
|
||||
extern int cap_bprm_creds_from_file(struct linux_binprm *bprm, const struct file *file);
|
||||
int cap_inode_setxattr(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags);
|
||||
int cap_inode_removexattr(struct mnt_idmap *idmap,
|
||||
@@ -284,16 +284,16 @@ int security_capable(const struct cred *cred,
|
||||
struct user_namespace *ns,
|
||||
int cap,
|
||||
unsigned int opts);
|
||||
int security_quotactl(int cmds, int type, int id, struct super_block *sb);
|
||||
int security_quotactl(int cmds, int type, int id, const struct super_block *sb);
|
||||
int security_quota_on(struct dentry *dentry);
|
||||
int security_syslog(int type);
|
||||
int security_settime64(const struct timespec64 *ts, const struct timezone *tz);
|
||||
int security_vm_enough_memory_mm(struct mm_struct *mm, long pages);
|
||||
int security_bprm_creds_for_exec(struct linux_binprm *bprm);
|
||||
int security_bprm_creds_from_file(struct linux_binprm *bprm, struct file *file);
|
||||
int security_bprm_creds_from_file(struct linux_binprm *bprm, const struct file *file);
|
||||
int security_bprm_check(struct linux_binprm *bprm);
|
||||
void security_bprm_committing_creds(struct linux_binprm *bprm);
|
||||
void security_bprm_committed_creds(struct linux_binprm *bprm);
|
||||
void security_bprm_committing_creds(const struct linux_binprm *bprm);
|
||||
void security_bprm_committed_creds(const struct linux_binprm *bprm);
|
||||
int security_fs_context_submount(struct fs_context *fc, struct super_block *reference);
|
||||
int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc);
|
||||
int security_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param);
|
||||
@@ -304,7 +304,7 @@ void security_free_mnt_opts(void **mnt_opts);
|
||||
int security_sb_eat_lsm_opts(char *options, void **mnt_opts);
|
||||
int security_sb_mnt_opts_compat(struct super_block *sb, void *mnt_opts);
|
||||
int security_sb_remount(struct super_block *sb, void *mnt_opts);
|
||||
int security_sb_kern_mount(struct super_block *sb);
|
||||
int security_sb_kern_mount(const struct super_block *sb);
|
||||
int security_sb_show_options(struct seq_file *m, struct super_block *sb);
|
||||
int security_sb_statfs(struct dentry *dentry);
|
||||
int security_sb_mount(const char *dev_name, const struct path *path,
|
||||
@@ -581,7 +581,7 @@ static inline int security_capable(const struct cred *cred,
|
||||
}
|
||||
|
||||
static inline int security_quotactl(int cmds, int type, int id,
|
||||
struct super_block *sb)
|
||||
const struct super_block *sb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -613,7 +613,7 @@ static inline int security_bprm_creds_for_exec(struct linux_binprm *bprm)
|
||||
}
|
||||
|
||||
static inline int security_bprm_creds_from_file(struct linux_binprm *bprm,
|
||||
struct file *file)
|
||||
const struct file *file)
|
||||
{
|
||||
return cap_bprm_creds_from_file(bprm, file);
|
||||
}
|
||||
@@ -623,11 +623,11 @@ static inline int security_bprm_check(struct linux_binprm *bprm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void security_bprm_committing_creds(struct linux_binprm *bprm)
|
||||
static inline void security_bprm_committing_creds(const struct linux_binprm *bprm)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void security_bprm_committed_creds(struct linux_binprm *bprm)
|
||||
static inline void security_bprm_committed_creds(const struct linux_binprm *bprm)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ struct audit_chunk {
|
||||
struct list_head list;
|
||||
struct audit_tree *owner;
|
||||
unsigned index; /* index; upper bit indicates 'will prune' */
|
||||
} owners[];
|
||||
} owners[] __counted_by(count);
|
||||
};
|
||||
|
||||
struct audit_tree_mark {
|
||||
|
||||
@@ -527,11 +527,18 @@ int audit_exe_compare(struct task_struct *tsk, struct audit_fsnotify_mark *mark)
|
||||
unsigned long ino;
|
||||
dev_t dev;
|
||||
|
||||
exe_file = get_task_exe_file(tsk);
|
||||
/* only do exe filtering if we are recording @current events/records */
|
||||
if (tsk != current)
|
||||
return 0;
|
||||
|
||||
if (WARN_ON_ONCE(!current->mm))
|
||||
return 0;
|
||||
exe_file = get_mm_exe_file(current->mm);
|
||||
if (!exe_file)
|
||||
return 0;
|
||||
ino = file_inode(exe_file)->i_ino;
|
||||
dev = file_inode(exe_file)->i_sb->s_dev;
|
||||
fput(exe_file);
|
||||
|
||||
return audit_mark_compare(mark, ino, dev);
|
||||
}
|
||||
|
||||
+15
-11
@@ -162,23 +162,29 @@ EXPORT_SYMBOL(__put_cred);
|
||||
*/
|
||||
void exit_creds(struct task_struct *tsk)
|
||||
{
|
||||
struct cred *cred;
|
||||
struct cred *real_cred, *cred;
|
||||
|
||||
kdebug("exit_creds(%u,%p,%p,{%d,%d})", tsk->pid, tsk->real_cred, tsk->cred,
|
||||
atomic_read(&tsk->cred->usage),
|
||||
read_cred_subscribers(tsk->cred));
|
||||
|
||||
cred = (struct cred *) tsk->real_cred;
|
||||
real_cred = (struct cred *) tsk->real_cred;
|
||||
tsk->real_cred = NULL;
|
||||
validate_creds(cred);
|
||||
alter_cred_subscribers(cred, -1);
|
||||
put_cred(cred);
|
||||
|
||||
cred = (struct cred *) tsk->cred;
|
||||
tsk->cred = NULL;
|
||||
|
||||
validate_creds(cred);
|
||||
alter_cred_subscribers(cred, -1);
|
||||
put_cred(cred);
|
||||
if (real_cred == cred) {
|
||||
alter_cred_subscribers(cred, -2);
|
||||
put_cred_many(cred, 2);
|
||||
} else {
|
||||
validate_creds(real_cred);
|
||||
alter_cred_subscribers(real_cred, -1);
|
||||
put_cred(real_cred);
|
||||
alter_cred_subscribers(cred, -1);
|
||||
put_cred(cred);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KEYS_REQUEST_CACHE
|
||||
key_put(tsk->cached_requested_key);
|
||||
@@ -355,8 +361,7 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
|
||||
#endif
|
||||
clone_flags & CLONE_THREAD
|
||||
) {
|
||||
p->real_cred = get_cred(p->cred);
|
||||
get_cred(p->cred);
|
||||
p->real_cred = get_cred_many(p->cred, 2);
|
||||
alter_cred_subscribers(p->cred, 2);
|
||||
kdebug("share_creds(%p{%d,%d})",
|
||||
p->cred, atomic_read(&p->cred->usage),
|
||||
@@ -520,8 +525,7 @@ int commit_creds(struct cred *new)
|
||||
proc_id_connector(task, PROC_EVENT_GID);
|
||||
|
||||
/* release the old obj and subj refs both */
|
||||
put_cred(old);
|
||||
put_cred(old);
|
||||
put_cred_many(old, 2);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(commit_creds);
|
||||
|
||||
+3
-5
@@ -336,13 +336,13 @@ quiet_cmd_bindgen = BINDGEN $@
|
||||
$(bindgen_target_cflags) $(bindgen_target_extra)
|
||||
|
||||
$(obj)/bindings/bindings_generated.rs: private bindgen_target_flags = \
|
||||
$(shell grep -v '^#\|^$$' $(srctree)/$(src)/bindgen_parameters)
|
||||
$(shell grep -Ev '^#|^$$' $(srctree)/$(src)/bindgen_parameters)
|
||||
$(obj)/bindings/bindings_generated.rs: $(src)/bindings/bindings_helper.h \
|
||||
$(src)/bindgen_parameters FORCE
|
||||
$(call if_changed_dep,bindgen)
|
||||
|
||||
$(obj)/uapi/uapi_generated.rs: private bindgen_target_flags = \
|
||||
$(shell grep -v '^#\|^$$' $(srctree)/$(src)/bindgen_parameters)
|
||||
$(shell grep -Ev '^#|^$$' $(srctree)/$(src)/bindgen_parameters)
|
||||
$(obj)/uapi/uapi_generated.rs: $(src)/uapi/uapi_helper.h \
|
||||
$(src)/bindgen_parameters FORCE
|
||||
$(call if_changed_dep,bindgen)
|
||||
@@ -364,9 +364,7 @@ $(obj)/bindings/bindings_helpers_generated.rs: $(src)/helpers.c FORCE
|
||||
quiet_cmd_exports = EXPORTS $@
|
||||
cmd_exports = \
|
||||
$(NM) -p --defined-only $< \
|
||||
| grep -E ' (T|R|D) ' | cut -d ' ' -f 3 \
|
||||
| xargs -Isymbol \
|
||||
echo 'EXPORT_SYMBOL_RUST_GPL(symbol);' > $@
|
||||
| awk '/ (T|R|D) / {printf "EXPORT_SYMBOL_RUST_GPL(%s);\n",$$3}' > $@
|
||||
|
||||
$(obj)/exports_core_generated.h: $(obj)/core.o FORCE
|
||||
$(call if_changed,exports)
|
||||
|
||||
@@ -6,9 +6,7 @@
|
||||
|
||||
#[cfg(not(test))]
|
||||
use core::intrinsics;
|
||||
use core::intrinsics::{min_align_of_val, size_of_val};
|
||||
|
||||
use core::ptr::Unique;
|
||||
#[cfg(not(test))]
|
||||
use core::ptr::{self, NonNull};
|
||||
|
||||
@@ -40,7 +38,6 @@ extern "Rust" {
|
||||
#[rustc_nounwind]
|
||||
fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
|
||||
|
||||
#[cfg(not(bootstrap))]
|
||||
static __rust_no_alloc_shim_is_unstable: u8;
|
||||
}
|
||||
|
||||
@@ -98,7 +95,6 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 {
|
||||
unsafe {
|
||||
// Make sure we don't accidentally allow omitting the allocator shim in
|
||||
// stable code until it is actually stabilized.
|
||||
#[cfg(not(bootstrap))]
|
||||
core::ptr::read_volatile(&__rust_no_alloc_shim_is_unstable);
|
||||
|
||||
__rust_alloc(layout.size(), layout.align())
|
||||
@@ -339,22 +335,6 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(not(test), lang = "box_free")]
|
||||
#[inline]
|
||||
// This signature has to be the same as `Box`, otherwise an ICE will happen.
|
||||
// When an additional parameter to `Box` is added (like `A: Allocator`), this has to be added here as
|
||||
// well.
|
||||
// For example if `Box` is changed to `struct Box<T: ?Sized, A: Allocator>(Unique<T>, A)`,
|
||||
// this function has to be changed to `fn box_free<T: ?Sized, A: Allocator>(Unique<T>, A)` as well.
|
||||
pub(crate) unsafe fn box_free<T: ?Sized, A: Allocator>(ptr: Unique<T>, alloc: A) {
|
||||
unsafe {
|
||||
let size = size_of_val(ptr.as_ref());
|
||||
let align = min_align_of_val(ptr.as_ref());
|
||||
let layout = Layout::from_size_align_unchecked(size, align);
|
||||
alloc.deallocate(From::from(ptr.cast()), layout)
|
||||
}
|
||||
}
|
||||
|
||||
// # Allocation error handler
|
||||
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
@@ -414,7 +394,6 @@ pub mod __alloc_error_handler {
|
||||
static __rust_alloc_error_handler_should_panic: u8;
|
||||
}
|
||||
|
||||
#[allow(unused_unsafe)]
|
||||
if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
|
||||
panic!("memory allocation of {size} bytes failed")
|
||||
} else {
|
||||
|
||||
+39
-17
@@ -159,12 +159,12 @@ use core::hash::{Hash, Hasher};
|
||||
use core::iter::FusedIterator;
|
||||
use core::marker::Tuple;
|
||||
use core::marker::Unsize;
|
||||
use core::mem;
|
||||
use core::mem::{self, SizedTypeProperties};
|
||||
use core::ops::{
|
||||
CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Generator, GeneratorState, Receiver,
|
||||
};
|
||||
use core::pin::Pin;
|
||||
use core::ptr::{self, Unique};
|
||||
use core::ptr::{self, NonNull, Unique};
|
||||
use core::task::{Context, Poll};
|
||||
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
@@ -483,8 +483,12 @@ impl<T, A: Allocator> Box<T, A> {
|
||||
where
|
||||
A: Allocator,
|
||||
{
|
||||
let layout = Layout::new::<mem::MaybeUninit<T>>();
|
||||
let ptr = alloc.allocate(layout)?.cast();
|
||||
let ptr = if T::IS_ZST {
|
||||
NonNull::dangling()
|
||||
} else {
|
||||
let layout = Layout::new::<mem::MaybeUninit<T>>();
|
||||
alloc.allocate(layout)?.cast()
|
||||
};
|
||||
unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) }
|
||||
}
|
||||
|
||||
@@ -553,8 +557,12 @@ impl<T, A: Allocator> Box<T, A> {
|
||||
where
|
||||
A: Allocator,
|
||||
{
|
||||
let layout = Layout::new::<mem::MaybeUninit<T>>();
|
||||
let ptr = alloc.allocate_zeroed(layout)?.cast();
|
||||
let ptr = if T::IS_ZST {
|
||||
NonNull::dangling()
|
||||
} else {
|
||||
let layout = Layout::new::<mem::MaybeUninit<T>>();
|
||||
alloc.allocate_zeroed(layout)?.cast()
|
||||
};
|
||||
unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) }
|
||||
}
|
||||
|
||||
@@ -679,14 +687,16 @@ impl<T> Box<[T]> {
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[inline]
|
||||
pub fn try_new_uninit_slice(len: usize) -> Result<Box<[mem::MaybeUninit<T>]>, AllocError> {
|
||||
unsafe {
|
||||
let ptr = if T::IS_ZST || len == 0 {
|
||||
NonNull::dangling()
|
||||
} else {
|
||||
let layout = match Layout::array::<mem::MaybeUninit<T>>(len) {
|
||||
Ok(l) => l,
|
||||
Err(_) => return Err(AllocError),
|
||||
};
|
||||
let ptr = Global.allocate(layout)?;
|
||||
Ok(RawVec::from_raw_parts_in(ptr.as_mut_ptr() as *mut _, len, Global).into_box(len))
|
||||
}
|
||||
Global.allocate(layout)?.cast()
|
||||
};
|
||||
unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, Global).into_box(len)) }
|
||||
}
|
||||
|
||||
/// Constructs a new boxed slice with uninitialized contents, with the memory
|
||||
@@ -711,14 +721,16 @@ impl<T> Box<[T]> {
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[inline]
|
||||
pub fn try_new_zeroed_slice(len: usize) -> Result<Box<[mem::MaybeUninit<T>]>, AllocError> {
|
||||
unsafe {
|
||||
let ptr = if T::IS_ZST || len == 0 {
|
||||
NonNull::dangling()
|
||||
} else {
|
||||
let layout = match Layout::array::<mem::MaybeUninit<T>>(len) {
|
||||
Ok(l) => l,
|
||||
Err(_) => return Err(AllocError),
|
||||
};
|
||||
let ptr = Global.allocate_zeroed(layout)?;
|
||||
Ok(RawVec::from_raw_parts_in(ptr.as_mut_ptr() as *mut _, len, Global).into_box(len))
|
||||
}
|
||||
Global.allocate_zeroed(layout)?.cast()
|
||||
};
|
||||
unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, Global).into_box(len)) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1215,8 +1227,18 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box<T, A> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
// FIXME: Do nothing, drop is currently performed by compiler.
|
||||
// the T in the Box is dropped by the compiler before the destructor is run
|
||||
|
||||
let ptr = self.0;
|
||||
|
||||
unsafe {
|
||||
let layout = Layout::for_value_raw(ptr.as_ptr());
|
||||
if layout.size() != 0 {
|
||||
self.1.deallocate(From::from(ptr.cast()), layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2165,7 +2187,7 @@ impl dyn Error + Send {
|
||||
let err: Box<dyn Error> = self;
|
||||
<dyn Error>::downcast(err).map_err(|s| unsafe {
|
||||
// Reapply the `Send` marker.
|
||||
mem::transmute::<Box<dyn Error>, Box<dyn Error + Send>>(s)
|
||||
Box::from_raw(Box::into_raw(s) as *mut (dyn Error + Send))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -2179,7 +2201,7 @@ impl dyn Error + Send + Sync {
|
||||
let err: Box<dyn Error> = self;
|
||||
<dyn Error>::downcast(err).map_err(|s| unsafe {
|
||||
// Reapply the `Send + Sync` marker.
|
||||
mem::transmute::<Box<dyn Error>, Box<dyn Error + Send + Sync>>(s)
|
||||
Box::from_raw(Box::into_raw(s) as *mut (dyn Error + Send + Sync))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+7
-6
@@ -58,6 +58,11 @@
|
||||
//! [`Rc`]: rc
|
||||
//! [`RefCell`]: core::cell
|
||||
|
||||
// To run alloc tests without x.py without ending up with two copies of alloc, Miri needs to be
|
||||
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
|
||||
// rustc itself never sets the feature, so this line has no effect there.
|
||||
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
|
||||
//
|
||||
#![allow(unused_attributes)]
|
||||
#![stable(feature = "alloc", since = "1.36.0")]
|
||||
#![doc(
|
||||
@@ -77,11 +82,6 @@
|
||||
))]
|
||||
#![no_std]
|
||||
#![needs_allocator]
|
||||
// To run alloc tests without x.py without ending up with two copies of alloc, Miri needs to be
|
||||
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
|
||||
// rustc itself never sets the feature, so this line has no affect there.
|
||||
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
|
||||
//
|
||||
// Lints:
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
#![deny(fuzzy_provenance_casts)]
|
||||
@@ -90,6 +90,8 @@
|
||||
#![warn(missing_docs)]
|
||||
#![allow(explicit_outlives_requirements)]
|
||||
#![warn(multiple_supertrait_upcastable)]
|
||||
#![cfg_attr(not(bootstrap), allow(internal_features))]
|
||||
#![cfg_attr(not(bootstrap), allow(rustdoc::redundant_explicit_links))]
|
||||
//
|
||||
// Library features:
|
||||
// tidy-alphabetical-start
|
||||
@@ -139,7 +141,6 @@
|
||||
#![feature(maybe_uninit_uninit_array_transpose)]
|
||||
#![feature(pattern)]
|
||||
#![feature(pointer_byte_offsets)]
|
||||
#![feature(provide_any)]
|
||||
#![feature(ptr_internals)]
|
||||
#![feature(ptr_metadata)]
|
||||
#![feature(ptr_sub_ptr)]
|
||||
|
||||
+20
-10
@@ -471,16 +471,26 @@ impl<T, A: Allocator> RawVec<T, A> {
|
||||
let (ptr, layout) = if let Some(mem) = self.current_memory() { mem } else { return Ok(()) };
|
||||
// See current_memory() why this assert is here
|
||||
let _: () = const { assert!(mem::size_of::<T>() % mem::align_of::<T>() == 0) };
|
||||
let ptr = unsafe {
|
||||
// `Layout::array` cannot overflow here because it would have
|
||||
// overflowed earlier when capacity was larger.
|
||||
let new_size = mem::size_of::<T>().unchecked_mul(cap);
|
||||
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
|
||||
self.alloc
|
||||
.shrink(ptr, layout, new_layout)
|
||||
.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?
|
||||
};
|
||||
self.set_ptr_and_cap(ptr, cap);
|
||||
|
||||
// If shrinking to 0, deallocate the buffer. We don't reach this point
|
||||
// for the T::IS_ZST case since current_memory() will have returned
|
||||
// None.
|
||||
if cap == 0 {
|
||||
unsafe { self.alloc.deallocate(ptr, layout) };
|
||||
self.ptr = Unique::dangling();
|
||||
self.cap = 0;
|
||||
} else {
|
||||
let ptr = unsafe {
|
||||
// `Layout::array` cannot overflow here because it would have
|
||||
// overflowed earlier when capacity was larger.
|
||||
let new_size = mem::size_of::<T>().unchecked_mul(cap);
|
||||
let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
|
||||
self.alloc
|
||||
.shrink(ptr, layout, new_layout)
|
||||
.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?
|
||||
};
|
||||
self.set_ptr_and_cap(ptr, cap);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,199 +0,0 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
use crate::alloc::{Allocator, Global};
|
||||
use core::mem::{ManuallyDrop, SizedTypeProperties};
|
||||
use core::ptr;
|
||||
use core::slice;
|
||||
|
||||
use super::Vec;
|
||||
|
||||
/// An iterator which uses a closure to determine if an element should be removed.
|
||||
///
|
||||
/// This struct is created by [`Vec::drain_filter`].
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(drain_filter)]
|
||||
///
|
||||
/// let mut v = vec![0, 1, 2];
|
||||
/// let iter: std::vec::DrainFilter<'_, _, _> = v.drain_filter(|x| *x % 2 == 0);
|
||||
/// ```
|
||||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
||||
#[derive(Debug)]
|
||||
pub struct DrainFilter<
|
||||
'a,
|
||||
T,
|
||||
F,
|
||||
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
|
||||
> where
|
||||
F: FnMut(&mut T) -> bool,
|
||||
{
|
||||
pub(super) vec: &'a mut Vec<T, A>,
|
||||
/// The index of the item that will be inspected by the next call to `next`.
|
||||
pub(super) idx: usize,
|
||||
/// The number of items that have been drained (removed) thus far.
|
||||
pub(super) del: usize,
|
||||
/// The original length of `vec` prior to draining.
|
||||
pub(super) old_len: usize,
|
||||
/// The filter test predicate.
|
||||
pub(super) pred: F,
|
||||
/// A flag that indicates a panic has occurred in the filter test predicate.
|
||||
/// This is used as a hint in the drop implementation to prevent consumption
|
||||
/// of the remainder of the `DrainFilter`. Any unprocessed items will be
|
||||
/// backshifted in the `vec`, but no further items will be dropped or
|
||||
/// tested by the filter predicate.
|
||||
pub(super) panic_flag: bool,
|
||||
}
|
||||
|
||||
impl<T, F, A: Allocator> DrainFilter<'_, T, F, A>
|
||||
where
|
||||
F: FnMut(&mut T) -> bool,
|
||||
{
|
||||
/// Returns a reference to the underlying allocator.
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[inline]
|
||||
pub fn allocator(&self) -> &A {
|
||||
self.vec.allocator()
|
||||
}
|
||||
|
||||
/// Keep unyielded elements in the source `Vec`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(drain_filter)]
|
||||
/// #![feature(drain_keep_rest)]
|
||||
///
|
||||
/// let mut vec = vec!['a', 'b', 'c'];
|
||||
/// let mut drain = vec.drain_filter(|_| true);
|
||||
///
|
||||
/// assert_eq!(drain.next().unwrap(), 'a');
|
||||
///
|
||||
/// // This call keeps 'b' and 'c' in the vec.
|
||||
/// drain.keep_rest();
|
||||
///
|
||||
/// // If we wouldn't call `keep_rest()`,
|
||||
/// // `vec` would be empty.
|
||||
/// assert_eq!(vec, ['b', 'c']);
|
||||
/// ```
|
||||
#[unstable(feature = "drain_keep_rest", issue = "101122")]
|
||||
pub fn keep_rest(self) {
|
||||
// At this moment layout looks like this:
|
||||
//
|
||||
// _____________________/-- old_len
|
||||
// / \
|
||||
// [kept] [yielded] [tail]
|
||||
// \_______/ ^-- idx
|
||||
// \-- del
|
||||
//
|
||||
// Normally `Drop` impl would drop [tail] (via .for_each(drop), ie still calling `pred`)
|
||||
//
|
||||
// 1. Move [tail] after [kept]
|
||||
// 2. Update length of the original vec to `old_len - del`
|
||||
// a. In case of ZST, this is the only thing we want to do
|
||||
// 3. Do *not* drop self, as everything is put in a consistent state already, there is nothing to do
|
||||
let mut this = ManuallyDrop::new(self);
|
||||
|
||||
unsafe {
|
||||
// ZSTs have no identity, so we don't need to move them around.
|
||||
if !T::IS_ZST && this.idx < this.old_len && this.del > 0 {
|
||||
let ptr = this.vec.as_mut_ptr();
|
||||
let src = ptr.add(this.idx);
|
||||
let dst = src.sub(this.del);
|
||||
let tail_len = this.old_len - this.idx;
|
||||
src.copy_to(dst, tail_len);
|
||||
}
|
||||
|
||||
let new_len = this.old_len - this.del;
|
||||
this.vec.set_len(new_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
||||
impl<T, F, A: Allocator> Iterator for DrainFilter<'_, T, F, A>
|
||||
where
|
||||
F: FnMut(&mut T) -> bool,
|
||||
{
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<T> {
|
||||
unsafe {
|
||||
while self.idx < self.old_len {
|
||||
let i = self.idx;
|
||||
let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
|
||||
self.panic_flag = true;
|
||||
let drained = (self.pred)(&mut v[i]);
|
||||
self.panic_flag = false;
|
||||
// Update the index *after* the predicate is called. If the index
|
||||
// is updated prior and the predicate panics, the element at this
|
||||
// index would be leaked.
|
||||
self.idx += 1;
|
||||
if drained {
|
||||
self.del += 1;
|
||||
return Some(ptr::read(&v[i]));
|
||||
} else if self.del > 0 {
|
||||
let del = self.del;
|
||||
let src: *const T = &v[i];
|
||||
let dst: *mut T = &mut v[i - del];
|
||||
ptr::copy_nonoverlapping(src, dst, 1);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(0, Some(self.old_len - self.idx))
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
||||
impl<T, F, A: Allocator> Drop for DrainFilter<'_, T, F, A>
|
||||
where
|
||||
F: FnMut(&mut T) -> bool,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
struct BackshiftOnDrop<'a, 'b, T, F, A: Allocator>
|
||||
where
|
||||
F: FnMut(&mut T) -> bool,
|
||||
{
|
||||
drain: &'b mut DrainFilter<'a, T, F, A>,
|
||||
}
|
||||
|
||||
impl<'a, 'b, T, F, A: Allocator> Drop for BackshiftOnDrop<'a, 'b, T, F, A>
|
||||
where
|
||||
F: FnMut(&mut T) -> bool,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if self.drain.idx < self.drain.old_len && self.drain.del > 0 {
|
||||
// This is a pretty messed up state, and there isn't really an
|
||||
// obviously right thing to do. We don't want to keep trying
|
||||
// to execute `pred`, so we just backshift all the unprocessed
|
||||
// elements and tell the vec that they still exist. The backshift
|
||||
// is required to prevent a double-drop of the last successfully
|
||||
// drained item prior to a panic in the predicate.
|
||||
let ptr = self.drain.vec.as_mut_ptr();
|
||||
let src = ptr.add(self.drain.idx);
|
||||
let dst = src.sub(self.drain.del);
|
||||
let tail_len = self.drain.old_len - self.drain.idx;
|
||||
src.copy_to(dst, tail_len);
|
||||
}
|
||||
self.drain.vec.set_len(self.drain.old_len - self.drain.del);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let backshift = BackshiftOnDrop { drain: self };
|
||||
|
||||
// Attempt to consume any remaining elements if the filter predicate
|
||||
// has not yet panicked. We'll backshift any remaining elements
|
||||
// whether we've already panicked or if the consumption here panics.
|
||||
if !backshift.drain.panic_flag {
|
||||
backshift.drain.for_each(drop);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
|
||||
use crate::alloc::{Allocator, Global};
|
||||
use core::ptr;
|
||||
use core::slice;
|
||||
|
||||
use super::Vec;
|
||||
|
||||
/// An iterator which uses a closure to determine if an element should be removed.
|
||||
///
|
||||
/// This struct is created by [`Vec::extract_if`].
|
||||
/// See its documentation for more.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(extract_if)]
|
||||
///
|
||||
/// let mut v = vec![0, 1, 2];
|
||||
/// let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(|x| *x % 2 == 0);
|
||||
/// ```
|
||||
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
||||
#[derive(Debug)]
|
||||
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||
pub struct ExtractIf<
|
||||
'a,
|
||||
T,
|
||||
F,
|
||||
#[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
|
||||
> where
|
||||
F: FnMut(&mut T) -> bool,
|
||||
{
|
||||
pub(super) vec: &'a mut Vec<T, A>,
|
||||
/// The index of the item that will be inspected by the next call to `next`.
|
||||
pub(super) idx: usize,
|
||||
/// The number of items that have been drained (removed) thus far.
|
||||
pub(super) del: usize,
|
||||
/// The original length of `vec` prior to draining.
|
||||
pub(super) old_len: usize,
|
||||
/// The filter test predicate.
|
||||
pub(super) pred: F,
|
||||
}
|
||||
|
||||
impl<T, F, A: Allocator> ExtractIf<'_, T, F, A>
|
||||
where
|
||||
F: FnMut(&mut T) -> bool,
|
||||
{
|
||||
/// Returns a reference to the underlying allocator.
|
||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||
#[inline]
|
||||
pub fn allocator(&self) -> &A {
|
||||
self.vec.allocator()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
||||
impl<T, F, A: Allocator> Iterator for ExtractIf<'_, T, F, A>
|
||||
where
|
||||
F: FnMut(&mut T) -> bool,
|
||||
{
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<T> {
|
||||
unsafe {
|
||||
while self.idx < self.old_len {
|
||||
let i = self.idx;
|
||||
let v = slice::from_raw_parts_mut(self.vec.as_mut_ptr(), self.old_len);
|
||||
let drained = (self.pred)(&mut v[i]);
|
||||
// Update the index *after* the predicate is called. If the index
|
||||
// is updated prior and the predicate panics, the element at this
|
||||
// index would be leaked.
|
||||
self.idx += 1;
|
||||
if drained {
|
||||
self.del += 1;
|
||||
return Some(ptr::read(&v[i]));
|
||||
} else if self.del > 0 {
|
||||
let del = self.del;
|
||||
let src: *const T = &v[i];
|
||||
let dst: *mut T = &mut v[i - del];
|
||||
ptr::copy_nonoverlapping(src, dst, 1);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(0, Some(self.old_len - self.idx))
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
||||
impl<T, F, A: Allocator> Drop for ExtractIf<'_, T, F, A>
|
||||
where
|
||||
F: FnMut(&mut T) -> bool,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if self.idx < self.old_len && self.del > 0 {
|
||||
// This is a pretty messed up state, and there isn't really an
|
||||
// obviously right thing to do. We don't want to keep trying
|
||||
// to execute `pred`, so we just backshift all the unprocessed
|
||||
// elements and tell the vec that they still exist. The backshift
|
||||
// is required to prevent a double-drop of the last successfully
|
||||
// drained item prior to a panic in the predicate.
|
||||
let ptr = self.vec.as_mut_ptr();
|
||||
let src = ptr.add(self.idx);
|
||||
let dst = src.sub(self.del);
|
||||
let tail_len = self.old_len - self.idx;
|
||||
src.copy_to(dst, tail_len);
|
||||
}
|
||||
self.vec.set_len(self.old_len - self.del);
|
||||
}
|
||||
}
|
||||
}
|
||||
+53
-57
@@ -74,10 +74,10 @@ use crate::boxed::Box;
|
||||
use crate::collections::{TryReserveError, TryReserveErrorKind};
|
||||
use crate::raw_vec::RawVec;
|
||||
|
||||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
||||
pub use self::drain_filter::DrainFilter;
|
||||
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
||||
pub use self::extract_if::ExtractIf;
|
||||
|
||||
mod drain_filter;
|
||||
mod extract_if;
|
||||
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
#[stable(feature = "vec_splice", since = "1.21.0")]
|
||||
@@ -216,7 +216,7 @@ mod spec_extend;
|
||||
///
|
||||
/// # Indexing
|
||||
///
|
||||
/// The `Vec` type allows to access values by index, because it implements the
|
||||
/// The `Vec` type allows access to values by index, because it implements the
|
||||
/// [`Index`] trait. An example will be more explicit:
|
||||
///
|
||||
/// ```
|
||||
@@ -618,22 +618,20 @@ impl<T> Vec<T> {
|
||||
/// Using memory that was allocated elsewhere:
|
||||
///
|
||||
/// ```rust
|
||||
/// #![feature(allocator_api)]
|
||||
///
|
||||
/// use std::alloc::{AllocError, Allocator, Global, Layout};
|
||||
/// use std::alloc::{alloc, Layout};
|
||||
///
|
||||
/// fn main() {
|
||||
/// let layout = Layout::array::<u32>(16).expect("overflow cannot happen");
|
||||
///
|
||||
/// let vec = unsafe {
|
||||
/// let mem = match Global.allocate(layout) {
|
||||
/// Ok(mem) => mem.cast::<u32>().as_ptr(),
|
||||
/// Err(AllocError) => return,
|
||||
/// };
|
||||
/// let mem = alloc(layout).cast::<u32>();
|
||||
/// if mem.is_null() {
|
||||
/// return;
|
||||
/// }
|
||||
///
|
||||
/// mem.write(1_000_000);
|
||||
///
|
||||
/// Vec::from_raw_parts_in(mem, 1, 16, Global)
|
||||
/// Vec::from_raw_parts(mem, 1, 16)
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(vec, &[1_000_000]);
|
||||
@@ -876,19 +874,22 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||
/// Using memory that was allocated elsewhere:
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::alloc::{alloc, Layout};
|
||||
/// #![feature(allocator_api)]
|
||||
///
|
||||
/// use std::alloc::{AllocError, Allocator, Global, Layout};
|
||||
///
|
||||
/// fn main() {
|
||||
/// let layout = Layout::array::<u32>(16).expect("overflow cannot happen");
|
||||
///
|
||||
/// let vec = unsafe {
|
||||
/// let mem = alloc(layout).cast::<u32>();
|
||||
/// if mem.is_null() {
|
||||
/// return;
|
||||
/// }
|
||||
/// let mem = match Global.allocate(layout) {
|
||||
/// Ok(mem) => mem.cast::<u32>().as_ptr(),
|
||||
/// Err(AllocError) => return,
|
||||
/// };
|
||||
///
|
||||
/// mem.write(1_000_000);
|
||||
///
|
||||
/// Vec::from_raw_parts(mem, 1, 16)
|
||||
/// Vec::from_raw_parts_in(mem, 1, 16, Global)
|
||||
/// };
|
||||
///
|
||||
/// assert_eq!(vec, &[1_000_000]);
|
||||
@@ -2507,7 +2508,7 @@ impl<T: Clone, A: Allocator> Vec<T, A> {
|
||||
let len = self.len();
|
||||
|
||||
if new_len > len {
|
||||
self.extend_with(new_len - len, ExtendElement(value))
|
||||
self.extend_with(new_len - len, value)
|
||||
} else {
|
||||
self.truncate(new_len);
|
||||
}
|
||||
@@ -2545,7 +2546,7 @@ impl<T: Clone, A: Allocator> Vec<T, A> {
|
||||
let len = self.len();
|
||||
|
||||
if new_len > len {
|
||||
self.try_extend_with(new_len - len, ExtendElement(value))
|
||||
self.try_extend_with(new_len - len, value)
|
||||
} else {
|
||||
self.truncate(new_len);
|
||||
Ok(())
|
||||
@@ -2684,26 +2685,10 @@ impl<T, A: Allocator, const N: usize> Vec<[T; N], A> {
|
||||
}
|
||||
}
|
||||
|
||||
// This code generalizes `extend_with_{element,default}`.
|
||||
trait ExtendWith<T> {
|
||||
fn next(&mut self) -> T;
|
||||
fn last(self) -> T;
|
||||
}
|
||||
|
||||
struct ExtendElement<T>(T);
|
||||
impl<T: Clone> ExtendWith<T> for ExtendElement<T> {
|
||||
fn next(&mut self) -> T {
|
||||
self.0.clone()
|
||||
}
|
||||
fn last(self) -> T {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, A: Allocator> Vec<T, A> {
|
||||
impl<T: Clone, A: Allocator> Vec<T, A> {
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
/// Extend the vector by `n` values, using the given generator.
|
||||
fn extend_with<E: ExtendWith<T>>(&mut self, n: usize, mut value: E) {
|
||||
/// Extend the vector by `n` clones of value.
|
||||
fn extend_with(&mut self, n: usize, value: T) {
|
||||
self.reserve(n);
|
||||
|
||||
unsafe {
|
||||
@@ -2715,15 +2700,15 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||
|
||||
// Write all elements except the last one
|
||||
for _ in 1..n {
|
||||
ptr::write(ptr, value.next());
|
||||
ptr::write(ptr, value.clone());
|
||||
ptr = ptr.add(1);
|
||||
// Increment the length in every step in case next() panics
|
||||
// Increment the length in every step in case clone() panics
|
||||
local_len.increment_len(1);
|
||||
}
|
||||
|
||||
if n > 0 {
|
||||
// We can write the last element directly without cloning needlessly
|
||||
ptr::write(ptr, value.last());
|
||||
ptr::write(ptr, value);
|
||||
local_len.increment_len(1);
|
||||
}
|
||||
|
||||
@@ -2731,8 +2716,8 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to extend the vector by `n` values, using the given generator.
|
||||
fn try_extend_with<E: ExtendWith<T>>(&mut self, n: usize, mut value: E) -> Result<(), TryReserveError> {
|
||||
/// Try to extend the vector by `n` clones of value.
|
||||
fn try_extend_with(&mut self, n: usize, value: T) -> Result<(), TryReserveError> {
|
||||
self.try_reserve(n)?;
|
||||
|
||||
unsafe {
|
||||
@@ -2744,15 +2729,15 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||
|
||||
// Write all elements except the last one
|
||||
for _ in 1..n {
|
||||
ptr::write(ptr, value.next());
|
||||
ptr::write(ptr, value.clone());
|
||||
ptr = ptr.add(1);
|
||||
// Increment the length in every step in case next() panics
|
||||
// Increment the length in every step in case clone() panics
|
||||
local_len.increment_len(1);
|
||||
}
|
||||
|
||||
if n > 0 {
|
||||
// We can write the last element directly without cloning needlessly
|
||||
ptr::write(ptr, value.last());
|
||||
ptr::write(ptr, value);
|
||||
local_len.increment_len(1);
|
||||
}
|
||||
|
||||
@@ -3210,6 +3195,12 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||
/// If the closure returns false, the element will remain in the vector and will not be yielded
|
||||
/// by the iterator.
|
||||
///
|
||||
/// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating
|
||||
/// or the iteration short-circuits, then the remaining elements will be retained.
|
||||
/// Use [`retain`] with a negated predicate if you do not need the returned iterator.
|
||||
///
|
||||
/// [`retain`]: Vec::retain
|
||||
///
|
||||
/// Using this method is equivalent to the following code:
|
||||
///
|
||||
/// ```
|
||||
@@ -3228,10 +3219,10 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||
/// # assert_eq!(vec, vec![1, 4, 5]);
|
||||
/// ```
|
||||
///
|
||||
/// But `drain_filter` is easier to use. `drain_filter` is also more efficient,
|
||||
/// But `extract_if` is easier to use. `extract_if` is also more efficient,
|
||||
/// because it can backshift the elements of the array in bulk.
|
||||
///
|
||||
/// Note that `drain_filter` also lets you mutate every element in the filter closure,
|
||||
/// Note that `extract_if` also lets you mutate every element in the filter closure,
|
||||
/// regardless of whether you choose to keep or remove it.
|
||||
///
|
||||
/// # Examples
|
||||
@@ -3239,17 +3230,17 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||
/// Splitting an array into evens and odds, reusing the original allocation:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(drain_filter)]
|
||||
/// #![feature(extract_if)]
|
||||
/// let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15];
|
||||
///
|
||||
/// let evens = numbers.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
|
||||
/// let evens = numbers.extract_if(|x| *x % 2 == 0).collect::<Vec<_>>();
|
||||
/// let odds = numbers;
|
||||
///
|
||||
/// assert_eq!(evens, vec![2, 4, 6, 8, 14]);
|
||||
/// assert_eq!(odds, vec![1, 3, 5, 9, 11, 13, 15]);
|
||||
/// ```
|
||||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
||||
pub fn drain_filter<F>(&mut self, filter: F) -> DrainFilter<'_, T, F, A>
|
||||
#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")]
|
||||
pub fn extract_if<F>(&mut self, filter: F) -> ExtractIf<'_, T, F, A>
|
||||
where
|
||||
F: FnMut(&mut T) -> bool,
|
||||
{
|
||||
@@ -3260,7 +3251,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||
self.set_len(0);
|
||||
}
|
||||
|
||||
DrainFilter { vec: self, idx: 0, del: 0, old_len, pred: filter, panic_flag: false }
|
||||
ExtractIf { vec: self, idx: 0, del: 0, old_len, pred: filter }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3272,7 +3263,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
||||
/// [`copy_from_slice`]: slice::copy_from_slice
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
#[stable(feature = "extend_ref", since = "1.2.0")]
|
||||
impl<'a, T: Copy + 'a, A: Allocator + 'a> Extend<&'a T> for Vec<T, A> {
|
||||
impl<'a, T: Copy + 'a, A: Allocator> Extend<&'a T> for Vec<T, A> {
|
||||
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
|
||||
self.spec_extend(iter.into_iter())
|
||||
}
|
||||
@@ -3290,9 +3281,14 @@ impl<'a, T: Copy + 'a, A: Allocator + 'a> Extend<&'a T> for Vec<T, A> {
|
||||
|
||||
/// Implements comparison of vectors, [lexicographically](Ord#lexicographical-comparison).
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: PartialOrd, A: Allocator> PartialOrd for Vec<T, A> {
|
||||
impl<T, A1, A2> PartialOrd<Vec<T, A2>> for Vec<T, A1>
|
||||
where
|
||||
T: PartialOrd,
|
||||
A1: Allocator,
|
||||
A2: Allocator,
|
||||
{
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
fn partial_cmp(&self, other: &Vec<T, A2>) -> Option<Ordering> {
|
||||
PartialOrd::partial_cmp(&**self, &**other)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ impl<T, A: Allocator> TrySpecExtend<T, IntoIter<T>> for Vec<T, A> {
|
||||
}
|
||||
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
impl<'a, T: 'a, I, A: Allocator + 'a> SpecExtend<&'a T, I> for Vec<T, A>
|
||||
impl<'a, T: 'a, I, A: Allocator> SpecExtend<&'a T, I> for Vec<T, A>
|
||||
where
|
||||
I: Iterator<Item = &'a T>,
|
||||
T: Clone,
|
||||
@@ -87,7 +87,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a, I, A: Allocator + 'a> TrySpecExtend<&'a T, I> for Vec<T, A>
|
||||
impl<'a, T: 'a, I, A: Allocator> TrySpecExtend<&'a T, I> for Vec<T, A>
|
||||
where
|
||||
I: Iterator<Item = &'a T>,
|
||||
T: Clone,
|
||||
@@ -98,7 +98,7 @@ where
|
||||
}
|
||||
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
impl<'a, T: 'a, A: Allocator + 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T, A>
|
||||
impl<'a, T: 'a, A: Allocator> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T, A>
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
@@ -108,7 +108,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a, A: Allocator + 'a> TrySpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T, A>
|
||||
impl<'a, T: 'a, A: Allocator> TrySpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T, A>
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
//! [`compiler_builtins`]: https://github.com/rust-lang/compiler-builtins
|
||||
//! [`compiler-rt`]: https://compiler-rt.llvm.org/
|
||||
|
||||
#![allow(internal_features)]
|
||||
#![feature(compiler_builtins)]
|
||||
#![compiler_builtins]
|
||||
#![no_builtins]
|
||||
|
||||
+10
-10
@@ -35,7 +35,7 @@
|
||||
//! that you need to write `<-` instead of `:` for fields that you want to initialize in-place.
|
||||
//!
|
||||
//! ```rust
|
||||
//! # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)]
|
||||
//! # #![allow(clippy::disallowed_names)]
|
||||
//! use kernel::{prelude::*, sync::Mutex, new_mutex};
|
||||
//! # use core::pin::Pin;
|
||||
//! #[pin_data]
|
||||
@@ -55,7 +55,7 @@
|
||||
//! (or just the stack) to actually initialize a `Foo`:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)]
|
||||
//! # #![allow(clippy::disallowed_names)]
|
||||
//! # use kernel::{prelude::*, sync::Mutex, new_mutex};
|
||||
//! # use core::pin::Pin;
|
||||
//! # #[pin_data]
|
||||
@@ -86,7 +86,7 @@
|
||||
//! To declare an init macro/function you just return an [`impl PinInit<T, E>`]:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)]
|
||||
//! # #![allow(clippy::disallowed_names)]
|
||||
//! # use kernel::{sync::Mutex, prelude::*, new_mutex, init::PinInit, try_pin_init};
|
||||
//! #[pin_data]
|
||||
//! struct DriverData {
|
||||
@@ -236,7 +236,7 @@ pub mod macros;
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)]
|
||||
/// # #![allow(clippy::disallowed_names)]
|
||||
/// # use kernel::{init, macros::pin_data, pin_init, stack_pin_init, init::*, sync::Mutex, new_mutex};
|
||||
/// # use core::pin::Pin;
|
||||
/// #[pin_data]
|
||||
@@ -288,7 +288,7 @@ macro_rules! stack_pin_init {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)]
|
||||
/// # #![allow(clippy::disallowed_names)]
|
||||
/// # use kernel::{init, pin_init, stack_try_pin_init, init::*, sync::Mutex, new_mutex};
|
||||
/// # use macros::pin_data;
|
||||
/// # use core::{alloc::AllocError, pin::Pin};
|
||||
@@ -314,7 +314,7 @@ macro_rules! stack_pin_init {
|
||||
/// ```
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)]
|
||||
/// # #![allow(clippy::disallowed_names)]
|
||||
/// # use kernel::{init, pin_init, stack_try_pin_init, init::*, sync::Mutex, new_mutex};
|
||||
/// # use macros::pin_data;
|
||||
/// # use core::{alloc::AllocError, pin::Pin};
|
||||
@@ -366,7 +366,7 @@ macro_rules! stack_try_pin_init {
|
||||
/// The syntax is almost identical to that of a normal `struct` initializer:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)]
|
||||
/// # #![allow(clippy::disallowed_names)]
|
||||
/// # use kernel::{init, pin_init, macros::pin_data, init::*};
|
||||
/// # use core::pin::Pin;
|
||||
/// #[pin_data]
|
||||
@@ -411,7 +411,7 @@ macro_rules! stack_try_pin_init {
|
||||
/// To create an initializer function, simply declare it like this:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)]
|
||||
/// # #![allow(clippy::disallowed_names)]
|
||||
/// # use kernel::{init, pin_init, prelude::*, init::*};
|
||||
/// # use core::pin::Pin;
|
||||
/// # #[pin_data]
|
||||
@@ -438,7 +438,7 @@ macro_rules! stack_try_pin_init {
|
||||
/// Users of `Foo` can now create it like this:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)]
|
||||
/// # #![allow(clippy::disallowed_names)]
|
||||
/// # use kernel::{init, pin_init, macros::pin_data, init::*};
|
||||
/// # use core::pin::Pin;
|
||||
/// # #[pin_data]
|
||||
@@ -466,7 +466,7 @@ macro_rules! stack_try_pin_init {
|
||||
/// They can also easily embed it into their own `struct`s:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)]
|
||||
/// # #![allow(clippy::disallowed_names)]
|
||||
/// # use kernel::{init, pin_init, macros::pin_data, init::*};
|
||||
/// # use core::pin::Pin;
|
||||
/// # #[pin_data]
|
||||
|
||||
@@ -399,6 +399,7 @@ macro_rules! pr_debug (
|
||||
/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
|
||||
/// `alloc::format!` for information about the formatting syntax.
|
||||
///
|
||||
/// [`pr_info!`]: crate::pr_info!
|
||||
/// [`pr_cont`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_cont
|
||||
/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
|
||||
///
|
||||
|
||||
@@ -302,7 +302,7 @@ impl<T: ?Sized> Drop for Arc<T> {
|
||||
// The count reached zero, we must free the memory.
|
||||
//
|
||||
// SAFETY: The pointer was initialised from the result of `Box::leak`.
|
||||
unsafe { Box::from_raw(self.ptr.as_ptr()) };
|
||||
unsafe { drop(Box::from_raw(self.ptr.as_ptr())) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +91,6 @@ unsafe impl Sync for CondVar {}
|
||||
|
||||
impl CondVar {
|
||||
/// Constructs a new condvar initialiser.
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> {
|
||||
pin_init!(Self {
|
||||
_pin: PhantomPinned,
|
||||
|
||||
@@ -99,7 +99,6 @@ unsafe impl<T: ?Sized + Send, B: Backend> Sync for Lock<T, B> {}
|
||||
|
||||
impl<T, B: Backend> Lock<T, B> {
|
||||
/// Constructs a new lock initialiser.
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
pub fn new(t: T, name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> {
|
||||
pin_init!(Self {
|
||||
data: UnsafeCell::new(t),
|
||||
|
||||
+1
-1
@@ -82,7 +82,7 @@ impl Task {
|
||||
/// Returns a task reference for the currently executing task/thread.
|
||||
///
|
||||
/// The recommended way to get the current task/thread is to use the
|
||||
/// [`current`](crate::current) macro because it is safe.
|
||||
/// [`current`] macro because it is safe.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
|
||||
@@ -31,7 +31,7 @@ llvm)
|
||||
fi
|
||||
;;
|
||||
rustc)
|
||||
echo 1.71.1
|
||||
echo 1.73.0
|
||||
;;
|
||||
bindgen)
|
||||
echo 0.65.1
|
||||
|
||||
@@ -734,7 +734,7 @@ fail:
|
||||
* apparmor_bprm_committing_creds - do task cleanup on committing new creds
|
||||
* @bprm: binprm for the exec (NOT NULL)
|
||||
*/
|
||||
static void apparmor_bprm_committing_creds(struct linux_binprm *bprm)
|
||||
static void apparmor_bprm_committing_creds(const struct linux_binprm *bprm)
|
||||
{
|
||||
struct aa_label *label = aa_current_raw_label();
|
||||
struct aa_label *new_label = cred_label(bprm->cred);
|
||||
@@ -756,7 +756,7 @@ static void apparmor_bprm_committing_creds(struct linux_binprm *bprm)
|
||||
* apparmor_bprm_committed_creds() - do cleanup after new creds committed
|
||||
* @bprm: binprm for the exec (NOT NULL)
|
||||
*/
|
||||
static void apparmor_bprm_committed_creds(struct linux_binprm *bprm)
|
||||
static void apparmor_bprm_committed_creds(const struct linux_binprm *bprm)
|
||||
{
|
||||
/* clear out temporary/transitional state from the context */
|
||||
aa_clear_task_ctx_trans(task_ctx(current));
|
||||
|
||||
@@ -720,7 +720,7 @@ int get_vfs_caps_from_disk(struct mnt_idmap *idmap,
|
||||
* its xattrs and, if present, apply them to the proposed credentials being
|
||||
* constructed by execve().
|
||||
*/
|
||||
static int get_file_caps(struct linux_binprm *bprm, struct file *file,
|
||||
static int get_file_caps(struct linux_binprm *bprm, const struct file *file,
|
||||
bool *effective, bool *has_fcap)
|
||||
{
|
||||
int rc = 0;
|
||||
@@ -882,7 +882,7 @@ static inline bool nonroot_raised_pE(struct cred *new, const struct cred *old,
|
||||
*
|
||||
* Return: 0 if successful, -ve on error.
|
||||
*/
|
||||
int cap_bprm_creds_from_file(struct linux_binprm *bprm, struct file *file)
|
||||
int cap_bprm_creds_from_file(struct linux_binprm *bprm, const struct file *file)
|
||||
{
|
||||
/* Process setpcap binaries and capabilities for uid 0 */
|
||||
const struct cred *old = current_cred();
|
||||
|
||||
+6
-6
@@ -957,7 +957,7 @@ int security_capable(const struct cred *cred,
|
||||
*
|
||||
* Return: Returns 0 if permission is granted.
|
||||
*/
|
||||
int security_quotactl(int cmds, int type, int id, struct super_block *sb)
|
||||
int security_quotactl(int cmds, int type, int id, const struct super_block *sb)
|
||||
{
|
||||
return call_int_hook(quotactl, 0, cmds, type, id, sb);
|
||||
}
|
||||
@@ -1079,7 +1079,7 @@ int security_bprm_creds_for_exec(struct linux_binprm *bprm)
|
||||
*
|
||||
* Return: Returns 0 if the hook is successful and permission is granted.
|
||||
*/
|
||||
int security_bprm_creds_from_file(struct linux_binprm *bprm, struct file *file)
|
||||
int security_bprm_creds_from_file(struct linux_binprm *bprm, const struct file *file)
|
||||
{
|
||||
return call_int_hook(bprm_creds_from_file, 0, bprm, file);
|
||||
}
|
||||
@@ -1118,7 +1118,7 @@ int security_bprm_check(struct linux_binprm *bprm)
|
||||
* open file descriptors to which access will no longer be granted when the
|
||||
* attributes are changed. This is called immediately before commit_creds().
|
||||
*/
|
||||
void security_bprm_committing_creds(struct linux_binprm *bprm)
|
||||
void security_bprm_committing_creds(const struct linux_binprm *bprm)
|
||||
{
|
||||
call_void_hook(bprm_committing_creds, bprm);
|
||||
}
|
||||
@@ -1134,7 +1134,7 @@ void security_bprm_committing_creds(struct linux_binprm *bprm)
|
||||
* process such as clearing out non-inheritable signal state. This is called
|
||||
* immediately after commit_creds().
|
||||
*/
|
||||
void security_bprm_committed_creds(struct linux_binprm *bprm)
|
||||
void security_bprm_committed_creds(const struct linux_binprm *bprm)
|
||||
{
|
||||
call_void_hook(bprm_committed_creds, bprm);
|
||||
}
|
||||
@@ -1319,7 +1319,7 @@ EXPORT_SYMBOL(security_sb_remount);
|
||||
*
|
||||
* Return: Returns 0 if permission is granted.
|
||||
*/
|
||||
int security_sb_kern_mount(struct super_block *sb)
|
||||
int security_sb_kern_mount(const struct super_block *sb)
|
||||
{
|
||||
return call_int_hook(sb_kern_mount, 0, sb);
|
||||
}
|
||||
@@ -3957,7 +3957,7 @@ void security_inode_invalidate_secctx(struct inode *inode)
|
||||
EXPORT_SYMBOL(security_inode_invalidate_secctx);
|
||||
|
||||
/**
|
||||
* security_inode_notifysecctx() - Nofify the LSM of an inode's security label
|
||||
* security_inode_notifysecctx() - Notify the LSM of an inode's security label
|
||||
* @inode: inode
|
||||
* @ctx: secctx
|
||||
* @ctxlen: length of secctx
|
||||
|
||||
@@ -77,3 +77,13 @@ config SECURITY_SELINUX_DEBUG
|
||||
This enables debugging code designed to help SELinux kernel
|
||||
developers, unless you know what this does in the kernel code you
|
||||
should leave this disabled.
|
||||
|
||||
To fine control the messages to be printed enable
|
||||
CONFIG_DYNAMIC_DEBUG and see
|
||||
Documentation/admin-guide/dynamic-debug-howto.rst for additional
|
||||
information.
|
||||
|
||||
Example usage:
|
||||
|
||||
echo -n 'file "security/selinux/*" +p' > \
|
||||
/proc/dynamic_debug/control
|
||||
|
||||
@@ -12,6 +12,8 @@ obj-$(CONFIG_SECURITY_SELINUX) := selinux.o
|
||||
|
||||
ccflags-y := -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
|
||||
|
||||
ccflags-$(CONFIG_SECURITY_SELINUX_DEBUG) += -DDEBUG
|
||||
|
||||
selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \
|
||||
netnode.o netport.o status.o \
|
||||
ss/ebitmap.o ss/hashtab.o ss/symtab.o ss/sidtab.o ss/avtab.o \
|
||||
|
||||
@@ -1937,7 +1937,7 @@ static inline int may_rename(struct inode *old_dir,
|
||||
|
||||
/* Check whether a task can perform a filesystem operation. */
|
||||
static int superblock_has_perm(const struct cred *cred,
|
||||
struct super_block *sb,
|
||||
const struct super_block *sb,
|
||||
u32 perms,
|
||||
struct common_audit_data *ad)
|
||||
{
|
||||
@@ -2139,7 +2139,7 @@ static int selinux_capable(const struct cred *cred, struct user_namespace *ns,
|
||||
return cred_has_capability(cred, cap, opts, ns == &init_user_ns);
|
||||
}
|
||||
|
||||
static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
|
||||
static int selinux_quotactl(int cmds, int type, int id, const struct super_block *sb)
|
||||
{
|
||||
const struct cred *cred = current_cred();
|
||||
int rc = 0;
|
||||
@@ -2455,7 +2455,7 @@ static inline void flush_unauthorized_files(const struct cred *cred,
|
||||
/*
|
||||
* Prepare a process for imminent new credential changes due to exec
|
||||
*/
|
||||
static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
|
||||
static void selinux_bprm_committing_creds(const struct linux_binprm *bprm)
|
||||
{
|
||||
struct task_security_struct *new_tsec;
|
||||
struct rlimit *rlim, *initrlim;
|
||||
@@ -2501,7 +2501,7 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
|
||||
* Clean up the process immediately after the installation of new credentials
|
||||
* due to exec
|
||||
*/
|
||||
static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
|
||||
static void selinux_bprm_committed_creds(const struct linux_binprm *bprm)
|
||||
{
|
||||
const struct task_security_struct *tsec = selinux_cred(current_cred());
|
||||
u32 osid, sid;
|
||||
@@ -2721,7 +2721,7 @@ out_bad_option:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int selinux_sb_kern_mount(struct super_block *sb)
|
||||
static int selinux_sb_kern_mount(const struct super_block *sb)
|
||||
{
|
||||
const struct cred *cred = current_cred();
|
||||
struct common_audit_data ad;
|
||||
|
||||
+11
-26
@@ -17,6 +17,7 @@
|
||||
* Tuned number of hash slots for avtab to reduce memory usage
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/errno.h>
|
||||
@@ -66,8 +67,7 @@ static inline u32 avtab_hash(const struct avtab_key *keyp, u32 mask)
|
||||
}
|
||||
|
||||
static struct avtab_node*
|
||||
avtab_insert_node(struct avtab *h, u32 hvalue,
|
||||
struct avtab_node *prev,
|
||||
avtab_insert_node(struct avtab *h, struct avtab_node **dst,
|
||||
const struct avtab_key *key, const struct avtab_datum *datum)
|
||||
{
|
||||
struct avtab_node *newnode;
|
||||
@@ -89,15 +89,8 @@ avtab_insert_node(struct avtab *h, u32 hvalue,
|
||||
newnode->datum.u.data = datum->u.data;
|
||||
}
|
||||
|
||||
if (prev) {
|
||||
newnode->next = prev->next;
|
||||
prev->next = newnode;
|
||||
} else {
|
||||
struct avtab_node **n = &h->htable[hvalue];
|
||||
|
||||
newnode->next = *n;
|
||||
*n = newnode;
|
||||
}
|
||||
newnode->next = *dst;
|
||||
*dst = newnode;
|
||||
|
||||
h->nel++;
|
||||
return newnode;
|
||||
@@ -137,7 +130,8 @@ static int avtab_insert(struct avtab *h, const struct avtab_key *key,
|
||||
break;
|
||||
}
|
||||
|
||||
newnode = avtab_insert_node(h, hvalue, prev, key, datum);
|
||||
newnode = avtab_insert_node(h, prev ? &prev->next : &h->htable[hvalue],
|
||||
key, datum);
|
||||
if (!newnode)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -177,7 +171,8 @@ struct avtab_node *avtab_insert_nonunique(struct avtab *h,
|
||||
key->target_class < cur->key.target_class)
|
||||
break;
|
||||
}
|
||||
return avtab_insert_node(h, hvalue, prev, key, datum);
|
||||
return avtab_insert_node(h, prev ? &prev->next : &h->htable[hvalue],
|
||||
key, datum);
|
||||
}
|
||||
|
||||
/* This search function returns a node pointer, and can be used in
|
||||
@@ -298,13 +293,7 @@ int avtab_alloc(struct avtab *h, u32 nrules)
|
||||
u32 nslot = 0;
|
||||
|
||||
if (nrules != 0) {
|
||||
u32 shift = 1;
|
||||
u32 work = nrules >> 3;
|
||||
while (work) {
|
||||
work >>= 1;
|
||||
shift++;
|
||||
}
|
||||
nslot = 1 << shift;
|
||||
nslot = nrules > 3 ? rounddown_pow_of_two(nrules / 2) : 2;
|
||||
if (nslot > MAX_AVTAB_HASH_BUCKETS)
|
||||
nslot = MAX_AVTAB_HASH_BUCKETS;
|
||||
|
||||
@@ -349,7 +338,7 @@ void avtab_hash_eval(struct avtab *h, const char *tag)
|
||||
}
|
||||
|
||||
pr_debug("SELinux: %s: %d entries and %d/%d buckets used, "
|
||||
"longest chain length %d sum of chain length^2 %llu\n",
|
||||
"longest chain length %d, sum of chain length^2 %llu\n",
|
||||
tag, h->nel, slots_used, h->nslot, max_chain_len,
|
||||
chain2_len_sum);
|
||||
}
|
||||
@@ -477,11 +466,7 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
set = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(spec_order); i++) {
|
||||
if (key.specified & spec_order[i])
|
||||
set++;
|
||||
}
|
||||
set = hweight16(key.specified & (AVTAB_XPERMS | AVTAB_TYPE | AVTAB_AV));
|
||||
if (!set || set > 1) {
|
||||
pr_err("SELinux: avtab: more than one specifier\n");
|
||||
return -EINVAL;
|
||||
|
||||
@@ -107,10 +107,12 @@ int hashtab_map(struct hashtab *h,
|
||||
void hashtab_stat(struct hashtab *h, struct hashtab_info *info)
|
||||
{
|
||||
u32 i, chain_len, slots_used, max_chain_len;
|
||||
u64 chain2_len_sum;
|
||||
struct hashtab_node *cur;
|
||||
|
||||
slots_used = 0;
|
||||
max_chain_len = 0;
|
||||
chain2_len_sum = 0;
|
||||
for (i = 0; i < h->size; i++) {
|
||||
cur = h->htable[i];
|
||||
if (cur) {
|
||||
@@ -123,11 +125,14 @@ void hashtab_stat(struct hashtab *h, struct hashtab_info *info)
|
||||
|
||||
if (chain_len > max_chain_len)
|
||||
max_chain_len = chain_len;
|
||||
|
||||
chain2_len_sum += (u64)chain_len * chain_len;
|
||||
}
|
||||
}
|
||||
|
||||
info->slots_used = slots_used;
|
||||
info->max_chain_len = max_chain_len;
|
||||
info->chain2_len_sum = chain2_len_sum;
|
||||
}
|
||||
#endif /* CONFIG_SECURITY_SELINUX_DEBUG */
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ struct hashtab {
|
||||
struct hashtab_info {
|
||||
u32 slots_used;
|
||||
u32 max_chain_len;
|
||||
u64 chain2_len_sum;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -491,7 +491,7 @@ static u32 role_trans_hash(const void *k)
|
||||
{
|
||||
const struct role_trans_key *key = k;
|
||||
|
||||
return key->role + (key->type << 3) + (key->tclass << 5);
|
||||
return jhash_3words(key->role, key->type, (u32)key->tclass << 16 | key->tclass, 0);
|
||||
}
|
||||
|
||||
static int role_trans_cmp(const void *k1, const void *k2)
|
||||
@@ -684,9 +684,9 @@ static void hash_eval(struct hashtab *h, const char *hash_name)
|
||||
struct hashtab_info info;
|
||||
|
||||
hashtab_stat(h, &info);
|
||||
pr_debug("SELinux: %s: %d entries and %d/%d buckets used, longest chain length %d\n",
|
||||
pr_debug("SELinux: %s: %d entries and %d/%d buckets used, longest chain length %d, sum of chain length^2 %llu\n",
|
||||
hash_name, h->nel, info.slots_used, h->size,
|
||||
info.max_chain_len);
|
||||
info.max_chain_len, info.chain2_len_sum);
|
||||
}
|
||||
|
||||
static void symtab_hash_eval(struct symtab *s)
|
||||
|
||||
@@ -25,7 +25,7 @@ struct sidtab_str_cache {
|
||||
struct list_head lru_member;
|
||||
struct sidtab_entry *parent;
|
||||
u32 len;
|
||||
char str[];
|
||||
char str[] __counted_by(len);
|
||||
};
|
||||
|
||||
#define index_to_sid(index) ((index) + SECINITSID_NUM + 1)
|
||||
|
||||
@@ -52,7 +52,7 @@ static int tomoyo_cred_prepare(struct cred *new, const struct cred *old,
|
||||
*
|
||||
* @bprm: Pointer to "struct linux_binprm".
|
||||
*/
|
||||
static void tomoyo_bprm_committed_creds(struct linux_binprm *bprm)
|
||||
static void tomoyo_bprm_committed_creds(const struct linux_binprm *bprm)
|
||||
{
|
||||
/* Clear old_domain_info saved by execve() request. */
|
||||
struct tomoyo_task *s = tomoyo_task(current);
|
||||
|
||||
Reference in New Issue
Block a user