Skip to content

Commit

Permalink
Port STACK_ALLOCATED to base/, with clang plugin checks
Browse files Browse the repository at this point in the history
Change-Id: Ibcae800f7757dae9063c39ad8f1cc4660e8ec80c

Bug: chromium:1423429
Change-Id: Ibcae800f7757dae9063c39ad8f1cc4660e8ec80c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4308073
Reviewed-by: danakj <danakj@chromium.org>
Reviewed-by: Hans Wennborg <hans@chromium.org>
Reviewed-by: Kentaro Hara <haraken@chromium.org>
Commit-Queue: Stefan Zager <szager@chromium.org>
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1116435}
  • Loading branch information
szager-chromium authored and Chromium LUCI CQ committed Mar 13, 2023
1 parent 97fb80d commit ce1b867
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 83 deletions.
1 change: 1 addition & 0 deletions base/BUILD.gn
Expand Up @@ -445,6 +445,7 @@ component("base") {
"memory/shared_memory_tracker.cc",
"memory/shared_memory_tracker.h",
"memory/singleton.h",
"memory/stack_allocated.h",
"memory/unsafe_shared_memory_pool.cc",
"memory/unsafe_shared_memory_pool.h",
"memory/unsafe_shared_memory_region.cc",
Expand Down
57 changes: 57 additions & 0 deletions base/memory/stack_allocated.h
@@ -0,0 +1,57 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_MEMORY_STACK_ALLOCATED_H_
#define BASE_MEMORY_STACK_ALLOCATED_H_

#if defined(__clang__)
#define STACK_ALLOCATED_IGNORE(reason) \
__attribute__((annotate("stack_allocated_ignore")))
#else // !defined(__clang__)
#define STACK_ALLOCATED_IGNORE(reason)
#endif // !defined(__clang__)

// If a class or one of its ancestor classes is annotated with STACK_ALLOCATED()
// in its class definition, then instances of the class may not be allocated on
// the heap or as a member variable of a non-stack-allocated class.
#define STACK_ALLOCATED() \
public: \
using IsStackAllocatedTypeMarker [[maybe_unused]] = int; \
\
private: \
void* operator new(size_t) = delete; \
void* operator new(size_t, ::base::NotNullTag, void*) = delete; \
void* operator new(size_t, void*) = delete

namespace base {

// NotNullTag was originally added to WebKit here:
// https://trac.webkit.org/changeset/103243/webkit
// ...with the stated goal of improving the performance of the placement new
// operator and potentially enabling the -fomit-frame-pointer compiler flag.
//
// TODO(szager): The placement new operator which uses this tag is currently
// defined in third_party/blink/renderer/platform/wtf/allocator/allocator.h,
// in the global namespace. It should probably move to /base.
//
// It's unknown at the time of writing whether it still provides any benefit
// (or if it ever did). It is used by placing the kNotNull tag before the
// address of the object when calling placement new.
//
// If the kNotNull tag is specified to placement new for a null pointer,
// Undefined Behaviour can result.
//
// Example:
//
// union { int i; } u;
//
// // Typically placement new looks like this.
// new (&u.i) int(3);
// // But we can promise `&u.i` is not null like this.
// new (base::NotNullTag::kNotNull, &u.i) int(3);
enum class NotNullTag { kNotNull };

} // namespace base

#endif // BASE_MEMORY_STACK_ALLOCATED_H_
5 changes: 5 additions & 0 deletions build/config/clang/BUILD.gn
Expand Up @@ -20,6 +20,11 @@ config("find_bad_constructs") {
"-plugin-arg-find-bad-constructs",
"-Xclang",
"raw-ref-template-as-trivial-member",

"-Xclang",
"-plugin-arg-find-bad-constructs",
"-Xclang",
"check-stack-allocated",
]

if (is_linux || is_chromeos || is_android || is_fuchsia) {
Expand Down
21 changes: 11 additions & 10 deletions third_party/blink/renderer/core/css/style_change_reason.cc
Expand Up @@ -69,18 +69,19 @@ DEFINE_GLOBAL(AtomicString, g_unresolved);
void Init() {
DCHECK(IsMainThread());

new (NotNullTag::kNotNull, (void*)&g_active) AtomicString(":active");
new (NotNullTag::kNotNull, (void*)&g_disabled) AtomicString(":disabled");
new (NotNullTag::kNotNull, (void*)&g_drag) AtomicString(":-webkit-drag");
new (NotNullTag::kNotNull, (void*)&g_focus) AtomicString(":focus");
new (NotNullTag::kNotNull, (void*)&g_focus_visible)
new (WTF::NotNullTag::kNotNull, (void*)&g_active) AtomicString(":active");
new (WTF::NotNullTag::kNotNull, (void*)&g_disabled) AtomicString(":disabled");
new (WTF::NotNullTag::kNotNull, (void*)&g_drag) AtomicString(":-webkit-drag");
new (WTF::NotNullTag::kNotNull, (void*)&g_focus) AtomicString(":focus");
new (WTF::NotNullTag::kNotNull, (void*)&g_focus_visible)
AtomicString(":focus-visible");
new (NotNullTag::kNotNull, (void*)&g_focus_within)
new (WTF::NotNullTag::kNotNull, (void*)&g_focus_within)
AtomicString(":focus-within");
new (NotNullTag::kNotNull, (void*)&g_hover) AtomicString(":hover");
new (NotNullTag::kNotNull, (void*)&g_past) AtomicString(":past");
new (NotNullTag::kNotNull, (void*)&g_toggle) AtomicString(":toggle");
new (NotNullTag::kNotNull, (void*)&g_unresolved) AtomicString(":unresolved");
new (WTF::NotNullTag::kNotNull, (void*)&g_hover) AtomicString(":hover");
new (WTF::NotNullTag::kNotNull, (void*)&g_past) AtomicString(":past");
new (WTF::NotNullTag::kNotNull, (void*)&g_toggle) AtomicString(":toggle");
new (WTF::NotNullTag::kNotNull, (void*)&g_unresolved)
AtomicString(":unresolved");
}

} // namespace style_change_extra_data
Expand Down
Expand Up @@ -79,7 +79,7 @@ struct LegacyDOMSnapshotAgent::VectorStringHashTraits
}

static void ConstructDeletedValue(Vector<String>& vec) {
new (NotNullTag::kNotNull, &vec)
new (WTF::NotNullTag::kNotNull, &vec)
Vector<String>(WTF::kHashTableDeletedValue);
}

Expand Down
107 changes: 56 additions & 51 deletions third_party/blink/renderer/platform/wtf/allocator/allocator.h
Expand Up @@ -6,12 +6,15 @@
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_ALLOCATOR_ALLOCATOR_H_

#include "base/check.h"
#include "base/memory/stack_allocated.h"
#include "build/build_config.h"
#include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
#include "third_party/blink/renderer/platform/wtf/type_traits.h"

namespace WTF {

using base::NotNullTag;

namespace internal {
// A dummy class used in following macros.
class __thisIsHereToForceASemicolonAfterThisMacro;
Expand All @@ -23,41 +26,36 @@ class __thisIsHereToForceASemicolonAfterThisMacro;
// is able to discover their references. These macros will be useful for
// non-garbage-collected objects to avoid unintended allocations.
//
// STACK_ALLOCATED(): Use if the object is only stack allocated.
// Garbage-collected objects should be in raw pointers.
// STACK_ALLOCATED() classes may contain raw pointers to garbage-collected
// objects.
//
// DISALLOW_NEW(): Cannot be allocated with new operators but can be a
// part of object, a value object in collections or stack allocated. If it has
// Members you need a trace method and the containing object needs to call that
// trace method.
//
#define DISALLOW_NEW() \
public: \
using IsDisallowNewMarker [[maybe_unused]] = int; \
void* operator new(size_t, NotNullTag, void* location) { return location; } \
void* operator new(size_t, void* location) { return location; } \
\
private: \
void* operator new(size_t) = delete; \
\
public: \
#define DISALLOW_NEW() \
public: \
using IsDisallowNewMarker [[maybe_unused]] = int; \
void* operator new(size_t, WTF::NotNullTag, void* location) { \
return location; \
} \
void* operator new(size_t, void* location) { \
return location; \
} \
\
private: \
void* operator new(size_t) = delete; \
\
public: \
friend class ::WTF::internal::__thisIsHereToForceASemicolonAfterThisMacro

#define STATIC_ONLY(Type) \
Type() = delete; \
Type(const Type&) = delete; \
Type& operator=(const Type&) = delete; \
void* operator new(size_t) = delete; \
void* operator new(size_t, NotNullTag, void*) = delete; \
void* operator new(size_t, void*) = delete

#define STACK_ALLOCATED() \
public: \
using IsStackAllocatedTypeMarker [[maybe_unused]] = int; \
\
private: \
void* operator new(size_t) = delete; \
void* operator new(size_t, NotNullTag, void*) = delete; \
#define STATIC_ONLY(Type) \
Type() = delete; \
Type(const Type&) = delete; \
Type& operator=(const Type&) = delete; \
void* operator new(size_t) = delete; \
void* operator new(size_t, WTF::NotNullTag, void*) = delete; \
void* operator new(size_t, void*) = delete

// Provides customizable overrides of fastMalloc/fastFree and operator
Expand Down Expand Up @@ -98,35 +96,42 @@ class __thisIsHereToForceASemicolonAfterThisMacro;
#define USING_FAST_MALLOC_WITH_TYPE_NAME(type) \
USING_FAST_MALLOC_INTERNAL(type, #type)

#define USING_FAST_MALLOC_INTERNAL(type, typeName) \
public: \
void* operator new(size_t, void* p) { return p; } \
void* operator new[](size_t, void* p) { return p; } \
\
void* operator new(size_t size) { \
return ::WTF::Partitions::FastMalloc(size, typeName); \
} \
\
void operator delete(void* p) { ::WTF::Partitions::FastFree(p); } \
\
void* operator new[](size_t size) { \
return ::WTF::Partitions::FastMalloc(size, typeName); \
} \
\
void operator delete[](void* p) { ::WTF::Partitions::FastFree(p); } \
void* operator new(size_t, NotNullTag, void* location) { \
DCHECK(location); \
return location; \
} \
\
private: \
#define USING_FAST_MALLOC_INTERNAL(type, typeName) \
public: \
void* operator new(size_t, void* p) { \
return p; \
} \
void* operator new[](size_t, void* p) { \
return p; \
} \
\
void* operator new(size_t size) { \
return ::WTF::Partitions::FastMalloc(size, typeName); \
} \
\
void operator delete(void* p) { \
::WTF::Partitions::FastFree(p); \
} \
\
void* operator new[](size_t size) { \
return ::WTF::Partitions::FastMalloc(size, typeName); \
} \
\
void operator delete[](void* p) { \
::WTF::Partitions::FastFree(p); \
} \
void* operator new(size_t, WTF::NotNullTag, void* location) { \
DCHECK(location); \
return location; \
} \
\
private: \
friend class ::WTF::internal::__thisIsHereToForceASemicolonAfterThisMacro

} // namespace WTF

// This version of placement new omits a 0 check.
enum class NotNullTag { kNotNull };
inline void* operator new(size_t, NotNullTag, void* location) {
inline void* operator new(size_t, WTF::NotNullTag, void* location) {
DCHECK(location);
return location;
}
Expand Down
Expand Up @@ -124,24 +124,30 @@ WTF_EXPORT char* PartitionAllocator::AllocateVectorBacking<char>(size_t);

} // namespace WTF

#define USE_ALLOCATOR(ClassName, Allocator) \
public: \
void* operator new(size_t size) { \
return Allocator::template Malloc<void*, ClassName>( \
size, WTF_HEAP_PROFILER_TYPE_NAME(ClassName)); \
} \
void operator delete(void* p) { Allocator::Free(p); } \
void* operator new[](size_t size) { \
return Allocator::template NewArray<ClassName>(size); \
} \
void operator delete[](void* p) { Allocator::DeleteArray(p); } \
void* operator new(size_t, NotNullTag, void* location) { \
DCHECK(location); \
return location; \
} \
void* operator new(size_t, void* location) { return location; } \
\
private: \
#define USE_ALLOCATOR(ClassName, Allocator) \
public: \
void* operator new(size_t size) { \
return Allocator::template Malloc<void*, ClassName>( \
size, WTF_HEAP_PROFILER_TYPE_NAME(ClassName)); \
} \
void operator delete(void* p) { \
Allocator::Free(p); \
} \
void* operator new[](size_t size) { \
return Allocator::template NewArray<ClassName>(size); \
} \
void operator delete[](void* p) { \
Allocator::DeleteArray(p); \
} \
void* operator new(size_t, WTF::NotNullTag, void* location) { \
DCHECK(location); \
return location; \
} \
void* operator new(size_t, void* location) { \
return location; \
} \
\
private: \
typedef int __thisIsHereToForceASemicolonAfterThisMacro

#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_ALLOCATOR_PARTITION_ALLOCATOR_H_
6 changes: 3 additions & 3 deletions third_party/blink/renderer/platform/wtf/gc_plugin.h
Expand Up @@ -10,14 +10,14 @@
// reason must be provided as an argument. In most cases this will be a bug id
// where the bug describes what needs to happen to remove the GC_PLUGIN_IGNORE
// again.
//
// Developer note: this macro must be kept in sync with the definition of
// STACK_ALLOCATED_IGNORE in /base/memory/stack_allocated.h.
#if defined(__clang__)
#define STACK_ALLOCATED_IGNORE(reason) \
__attribute__((annotate("stack_allocated_ignore")))
#define GC_PLUGIN_IGNORE(reason) \
__attribute__((annotate("blink_gc_plugin_ignore"), \
annotate("stack_allocated_ignore")))
#else // !defined(__clang__)
#define STACK_ALLOCATED_IGNORE(reason)
#define GC_PLUGIN_IGNORE(reason)
#endif // !defined(__clang__)

Expand Down

0 comments on commit ce1b867

Please sign in to comment.