[ubsan] Make Isolate inherit from Factory

Previously Isolate and Factory relied on the undefined behavior of
reinterpret_cast to switch between the two unrelated classes (which worked
because Factory had no data members).

With Isolate inheriting from Factory, it's now possible to switch between the
two classes using c-style casts. These are allowed under the C++ standard.

The inheritance is private which allows the continuing separation of the
Factory and Isolate namespaces.

This is a defensive clean-up, since ubsan does not yet detect the previous
undefined behavior.

Bug: v8:3770
Change-Id: I0ccf09f1d34f747550812ce698ab7e182812409e
Reviewed-on: https://chromium-review.googlesource.com/1010122
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Commit-Queue: Dan Elphick <delphick@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52615}
This commit is contained in:
Dan Elphick 2018-04-12 17:25:46 +01:00 committed by Michael Achenbach
parent a440efb27f
commit 5ed349d66d
2 changed files with 17 additions and 5 deletions

View File

@ -81,7 +81,7 @@ enum FunctionMode {
}; };
// Interface for handle based allocation. // Interface for handle based allocation.
class V8_EXPORT_PRIVATE Factory final { class V8_EXPORT_PRIVATE Factory {
public: public:
Handle<Oddball> NewOddball(Handle<Map> map, const char* to_string, Handle<Oddball> NewOddball(Handle<Map> map, const char* to_string,
Handle<Object> to_number, const char* type_of, Handle<Object> to_number, const char* type_of,
@ -894,7 +894,12 @@ class V8_EXPORT_PRIVATE Factory final {
} }
private: private:
Isolate* isolate() { return reinterpret_cast<Isolate*>(this); } Isolate* isolate() {
// Downcast to the privately inherited sub-class using c-style casts to
// avoid undefined behavior (as static_cast cannot cast across private
// bases).
return (Isolate*)this; // NOLINT(readability/casting)
}
HeapObject* AllocateRawWithImmortalMap( HeapObject* AllocateRawWithImmortalMap(
int size, PretenureFlag pretenure, Map* map, int size, PretenureFlag pretenure, Map* map,

View File

@ -23,6 +23,7 @@
#include "src/futex-emulation.h" #include "src/futex-emulation.h"
#include "src/globals.h" #include "src/globals.h"
#include "src/handles.h" #include "src/handles.h"
#include "src/heap/factory.h"
#include "src/heap/heap.h" #include "src/heap/heap.h"
#include "src/messages.h" #include "src/messages.h"
#include "src/objects/code.h" #include "src/objects/code.h"
@ -72,7 +73,6 @@ class DescriptorLookupCache;
class EmptyStatement; class EmptyStatement;
class EternalHandles; class EternalHandles;
class ExternalCallbackScope; class ExternalCallbackScope;
class Factory;
class HandleScopeImplementer; class HandleScopeImplementer;
class HeapObjectToIndexHashMap; class HeapObjectToIndexHashMap;
class HeapProfiler; class HeapProfiler;
@ -454,8 +454,11 @@ typedef std::vector<HeapObject*> DebugObjectCache;
#define THREAD_LOCAL_TOP_ADDRESS(type, name) \ #define THREAD_LOCAL_TOP_ADDRESS(type, name) \
type* name##_address() { return &thread_local_top_.name##_; } type* name##_address() { return &thread_local_top_.name##_; }
// HiddenFactory exists so Isolate can privately inherit from it without making
// Factory's members available to Isolate directly.
class V8_EXPORT_PRIVATE HiddenFactory : private Factory {};
class Isolate { class Isolate : private HiddenFactory {
// These forward declarations are required to make the friend declarations in // These forward declarations are required to make the friend declarations in
// PerIsolateThreadData work on some older versions of gcc. // PerIsolateThreadData work on some older versions of gcc.
class ThreadDataTable; class ThreadDataTable;
@ -983,7 +986,11 @@ class Isolate {
} }
#endif #endif
Factory* factory() { return reinterpret_cast<Factory*>(this); } v8::internal::Factory* factory() {
// Upcast to the privately inherited base-class using c-style casts to avoid
// undefined behavior (as static_cast cannot cast across private bases).
return (v8::internal::Factory*)this; // NOLINT(readability/casting)
}
static const int kJSRegexpStaticOffsetsVectorSize = 128; static const int kJSRegexpStaticOffsetsVectorSize = 128;