mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-11 13:36:13 +03:00
AK+Kernel: Add the FixedStringBuffer class and StdLib functions for it
This class encapsulates a fixed Array with compile-time size definition for storing ASCII characters. There are also new Kernel StdLib functions to copy user data into such objects so this class will be useful later on.
This commit is contained in:
parent
3b09560251
commit
0d30f558f4
Notes:
sideshowbarker
2024-07-17 09:49:33 +09:00
Author: https://github.com/supercomputer7 Commit: https://github.com/SerenityOS/serenity/commit/0d30f558f4 Pull-request: https://github.com/SerenityOS/serenity/pull/20037 Reviewed-by: https://github.com/ADKaster ✅ Reviewed-by: https://github.com/kleinesfilmroellchen ✅
97
AK/FixedStringBuffer.h
Normal file
97
AK/FixedStringBuffer.h
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2023, Liav A. <liavalb@hotmail.co.il>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Array.h>
|
||||||
|
#include <AK/StringView.h>
|
||||||
|
#include <AK/TypedTransfer.h>
|
||||||
|
#include <AK/Userspace.h>
|
||||||
|
|
||||||
|
#ifdef KERNEL
|
||||||
|
# include <Kernel/Arch/SafeMem.h>
|
||||||
|
# include <Kernel/Arch/SmapDisabler.h>
|
||||||
|
# include <Kernel/Memory/MemorySections.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace AK {
|
||||||
|
|
||||||
|
template<size_t Size>
|
||||||
|
class FixedStringBuffer {
|
||||||
|
public:
|
||||||
|
void store_characters(StringView characters)
|
||||||
|
{
|
||||||
|
// NOTE: Only store the characters up to the first null terminator
|
||||||
|
// because we don't care about any further characters.
|
||||||
|
// This matches some expected behavior in the Kernel code, because
|
||||||
|
// technically userspace programs could send a syscall argument with
|
||||||
|
// multiple null terminators - we only care about the *first* chunk up to
|
||||||
|
// the first null terminator, if present at all.
|
||||||
|
size_t stored_length = 0;
|
||||||
|
for (; stored_length < min(Size, characters.length()); stored_length++) {
|
||||||
|
if (characters[stored_length] == '\0')
|
||||||
|
break;
|
||||||
|
m_storage[stored_length] = characters[stored_length];
|
||||||
|
}
|
||||||
|
m_stored_length = stored_length;
|
||||||
|
// NOTE: Fill the rest of the array bytes with zeroes, just to be
|
||||||
|
// on the safe side.
|
||||||
|
// Technically, it means that a sent StringView could occupy the
|
||||||
|
// entire storage without any null terminators and that's OK as well.
|
||||||
|
for (size_t index = m_stored_length; index < Size; index++)
|
||||||
|
m_storage[index] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef KERNEL
|
||||||
|
ErrorOr<void> copy_characters_from_user(Userspace<char const*> user_str, size_t user_str_size)
|
||||||
|
{
|
||||||
|
if (user_str_size > Size)
|
||||||
|
return EFAULT;
|
||||||
|
bool is_user = Kernel::Memory::is_user_range(user_str.vaddr(), user_str_size);
|
||||||
|
if (!is_user)
|
||||||
|
return EFAULT;
|
||||||
|
Kernel::SmapDisabler disabler;
|
||||||
|
void* fault_at;
|
||||||
|
ssize_t length = Kernel::safe_strnlen(user_str.unsafe_userspace_ptr(), user_str_size, fault_at);
|
||||||
|
if (length < 0) {
|
||||||
|
dbgln("FixedStringBuffer::copy_characters_into_storage({:p}, {}) failed at {} (strnlen)", static_cast<void const*>(user_str.unsafe_userspace_ptr()), user_str_size, VirtualAddress { fault_at });
|
||||||
|
return EFAULT;
|
||||||
|
}
|
||||||
|
if (!Kernel::safe_memcpy(m_storage.data(), user_str.unsafe_userspace_ptr(), (size_t)length, fault_at)) {
|
||||||
|
dbgln("FixedStringBuffer::copy_characters_into_storage({:p}, {}) failed at {} (memcpy)", static_cast<void const*>(user_str.unsafe_userspace_ptr()), user_str_size, VirtualAddress { fault_at });
|
||||||
|
return EFAULT;
|
||||||
|
}
|
||||||
|
m_stored_length = (size_t)length;
|
||||||
|
for (size_t index = m_stored_length; index < Size; index++)
|
||||||
|
m_storage[index] = '\0';
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Span<u8> storage()
|
||||||
|
{
|
||||||
|
return m_storage.span();
|
||||||
|
}
|
||||||
|
StringView representable_view() const { return StringView(m_storage.data(), m_stored_length); }
|
||||||
|
|
||||||
|
size_t fixed_length() const { return Size; }
|
||||||
|
size_t stored_length() const { return m_stored_length; }
|
||||||
|
|
||||||
|
FixedStringBuffer()
|
||||||
|
{
|
||||||
|
m_storage.fill(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Array<u8, Size> m_storage;
|
||||||
|
size_t m_stored_length { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#if USING_AK_GLOBALLY
|
||||||
|
using AK::FixedStringBuffer;
|
||||||
|
#endif
|
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||||
|
* Copyright (c) 2023, Liav A. <liavalb@hotmail.co.il>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
@ -8,6 +9,7 @@
|
|||||||
|
|
||||||
#include <AK/Checked.h>
|
#include <AK/Checked.h>
|
||||||
#include <AK/Error.h>
|
#include <AK/Error.h>
|
||||||
|
#include <AK/FixedStringBuffer.h>
|
||||||
#include <AK/Forward.h>
|
#include <AK/Forward.h>
|
||||||
#include <AK/Time.h>
|
#include <AK/Time.h>
|
||||||
#include <AK/Userspace.h>
|
#include <AK/Userspace.h>
|
||||||
@ -16,6 +18,25 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
ErrorOr<NonnullOwnPtr<Kernel::KString>> try_copy_kstring_from_user(Userspace<char const*>, size_t);
|
ErrorOr<NonnullOwnPtr<Kernel::KString>> try_copy_kstring_from_user(Userspace<char const*>, size_t);
|
||||||
|
|
||||||
|
template<size_t Size>
|
||||||
|
ErrorOr<void> try_copy_string_from_user_into_fixed_string_buffer(Userspace<char const*> user_str, FixedStringBuffer<Size>& buffer, size_t user_str_size)
|
||||||
|
{
|
||||||
|
if (user_str_size > Size)
|
||||||
|
return E2BIG;
|
||||||
|
TRY(buffer.copy_characters_from_user(user_str, user_str_size));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t Size>
|
||||||
|
ErrorOr<void> try_copy_name_from_user_into_fixed_string_buffer(Userspace<char const*> user_str, FixedStringBuffer<Size>& buffer, size_t user_str_size)
|
||||||
|
{
|
||||||
|
if (user_str_size > Size)
|
||||||
|
return ENAMETOOLONG;
|
||||||
|
TRY(buffer.copy_characters_from_user(user_str, user_str_size));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
ErrorOr<Duration> copy_time_from_user(timespec const*);
|
ErrorOr<Duration> copy_time_from_user(timespec const*);
|
||||||
ErrorOr<Duration> copy_time_from_user(timeval const*);
|
ErrorOr<Duration> copy_time_from_user(timeval const*);
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
Loading…
Reference in New Issue
Block a user