Skip to content

Commit

Permalink
Panic on get or set of out of range internal field index.
Browse files Browse the repository at this point in the history
  • Loading branch information
dylanahsmith committed Oct 18, 2021
1 parent 9a597db commit d064e79
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 26 deletions.
8 changes: 8 additions & 0 deletions helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,11 @@ func fatalIf(t *testing.T, err error) {
t.Fatal(err)
}
}

func recoverPanic(f func()) (recovered interface{}) {
defer func() {
recovered = recover()
}()
f()
return nil
}
23 changes: 18 additions & 5 deletions object.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ func (o *Object) SetIdx(idx uint32, val interface{}) error {
return nil
}

// SetInternalField sets the value of an internal field.
// SetInternalField sets the value of an internal field for an ObjectTemplate instance.
// Panics if the index isn't in the range set by (*ObjectTemplate).SetInternalFieldCount.
func (o *Object) SetInternalField(idx uint32, val interface{}) error {
value, err := coerceValue(o.ctx.iso, val)

Expand All @@ -95,12 +96,18 @@ func (o *Object) SetInternalField(idx uint32, val interface{}) error {
inserted := C.ObjectSetInternalField(o.ptr, C.uint32_t(idx), value.ptr)

if inserted == 0 {
return errors.New("v8go: index exceeded internal field count")
panic(fmt.Errorf("index out of range [%v] with length %v", idx, o.InternalFieldCount()))
}

return nil
}

// InternalFieldCount returns the number of internal fields this Object has.
func (o *Object) InternalFieldCount() uint32 {
count := C.ObjectInternalFieldCount(o.ptr)
return uint32(count)
}

// Get tries to get a Value for a given Object property key.
func (o *Object) Get(key string) (*Value, error) {
ckey := C.CString(key)
Expand All @@ -110,10 +117,16 @@ func (o *Object) Get(key string) (*Value, error) {
return valueResult(o.ctx, rtn)
}

// GetInternalField tries to get a Value for a given Object internal property key.
func (o *Object) GetInternalField(idx uint32) (*Value, error) {
// GetInternalField gets the Value set by SetInternalField for the given index
// or the JS undefined value if the index hadn't been set.
// Panics if given an out of range index.
func (o *Object) GetInternalField(idx uint32) *Value {
rtn := C.ObjectGetInternalField(o.ptr, C.uint32_t(idx))
return valueResult(o.ctx, rtn)
if rtn == nil {
panic(fmt.Errorf("index out of range [%v] with length %v", idx, o.InternalFieldCount()))
}
return &Value{rtn, o.ctx}

}

// GetIdx tries to get a Value at a give Object index.
Expand Down
10 changes: 8 additions & 2 deletions object_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,18 @@ func (o *ObjectTemplate) NewInstance(ctx *Context) (*Object, error) {
return objectResult(ctx, rtn)
}

// SetInternalFieldCount sets the amount of internal fields that we want our
// object to have.
// SetInternalFieldCount sets the number of internal fields that instances of this
// template will have.
func (o *ObjectTemplate) SetInternalFieldCount(fieldCount uint32) {
C.ObjectTemplateSetInternalFieldCount(o.ptr, C.uint32_t(fieldCount))
}

// InternalFieldCount returns the number of internal fields that instances of this
// template will have.
func (o *ObjectTemplate) InternalFieldCount() uint32 {
return uint32(C.ObjectTemplateInternalFieldCount(o.ptr))
}

func (o *ObjectTemplate) apply(opts *contextOptions) {
opts.gTmpl = o
}
35 changes: 22 additions & 13 deletions object_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,29 +80,38 @@ func TestObjectInternalFields(t *testing.T) {
defer ctx.Close()

tmpl := v8.NewObjectTemplate(iso)
obj, _ := tmpl.NewInstance(ctx)
err := obj.SetInternalField(0, "This should fail")

if err == nil {
t.Errorf("Setting an internal field without calling SetInternalFieldCount should fail")
obj, err := tmpl.NewInstance(ctx)
fatalIf(t, err)
if count := obj.InternalFieldCount(); count != 0 {
t.Errorf("expected 0 got %v", count)
}
if recoverPanic(func() { obj.GetInternalField(0) }) == nil {
t.Error("expected panic")
}

tmpl = v8.NewObjectTemplate(iso)
tmpl.SetInternalFieldCount(1)
if count := tmpl.InternalFieldCount(); count != 1 {
t.Errorf("expected 1 got %v", count)
}

obj, _ = tmpl.NewInstance(ctx)

obj.SetInternalField(0, "baz")
v, err := obj.GetInternalField(0)
obj, err = tmpl.NewInstance(ctx)
fatalIf(t, err)
if count := obj.InternalFieldCount(); count != 1 {
t.Errorf("expected 1 got %v", count)
}

if v.String() != "baz" || err != nil {
if v := obj.GetInternalField(0); !v.SameValue(v8.Undefined(iso)) {
t.Errorf("unexpected value: %q", v)
}

err = obj.SetInternalField(1, "baz")
obj.SetInternalField(0, "baz")
if v := obj.GetInternalField(0); v.String() != "baz" {
t.Errorf("unexpected value: %q", v)
}

if err == nil {
t.Error("Should get \"index exceeded internal field count\" error")
if recoverPanic(func() { obj.SetInternalField(1, "baz") }) == nil {
t.Error("expected panic from index out of bounds")
}
}

Expand Down
24 changes: 19 additions & 5 deletions v8go.cc
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,13 @@ void ObjectTemplateSetInternalFieldCount(TemplatePtr ptr, uint32_t field_count)
obj_tmpl->SetInternalFieldCount(field_count);
}

int ObjectTemplateInternalFieldCount(TemplatePtr ptr) {
LOCAL_TEMPLATE(ptr);

Local<ObjectTemplate> obj_tmpl = tmpl.As<ObjectTemplate>();
return obj_tmpl->InternalFieldCount();
}

/********** FunctionTemplate **********/

static void FunctionTemplateCallback(const FunctionCallbackInfo<Value>& info) {
Expand Down Expand Up @@ -1059,7 +1066,7 @@ int ObjectSetInternalField(ValuePtr ptr, uint32_t idx, ValuePtr val_ptr) {
LOCAL_OBJECT(ptr);
m_value* prop_val = static_cast<m_value*>(val_ptr);

if (obj->InternalFieldCount() <= idx) {
if (idx >= obj->InternalFieldCount()) {
return 0;
}

Expand All @@ -1068,6 +1075,11 @@ int ObjectSetInternalField(ValuePtr ptr, uint32_t idx, ValuePtr val_ptr) {
return 1;
}

int ObjectInternalFieldCount(ValuePtr ptr) {
LOCAL_OBJECT(ptr);
return obj->InternalFieldCount();
}

RtnValue ObjectGet(ValuePtr ptr, const char* key) {
LOCAL_OBJECT(ptr);
RtnValue rtn = {nullptr, nullptr};
Expand All @@ -1093,9 +1105,12 @@ RtnValue ObjectGet(ValuePtr ptr, const char* key) {
return rtn;
}

RtnValue ObjectGetInternalField(ValuePtr ptr, uint32_t idx) {
ValuePtr ObjectGetInternalField(ValuePtr ptr, uint32_t idx) {
LOCAL_OBJECT(ptr);
RtnValue rtn = {nullptr, nullptr};

if (idx >= obj->InternalFieldCount()) {
return nullptr;
}

Local<Value> result = obj->GetInternalField(idx);

Expand All @@ -1105,8 +1120,7 @@ RtnValue ObjectGetInternalField(ValuePtr ptr, uint32_t idx) {
new_val->ptr = Persistent<Value, CopyablePersistentTraits<Value>>(
iso, result);

rtn.value = tracked_value(ctx, new_val);
return rtn;
return tracked_value(ctx, new_val);
}

RtnValue ObjectGetIdx(ValuePtr ptr, uint32_t idx) {
Expand Down
4 changes: 3 additions & 1 deletion v8go.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ extern void TemplateSetTemplate(TemplatePtr ptr,
extern TemplatePtr NewObjectTemplate(IsolatePtr iso_ptr);
extern RtnValue ObjectTemplateNewInstance(TemplatePtr ptr, ContextPtr ctx_ptr);
extern void ObjectTemplateSetInternalFieldCount(TemplatePtr ptr, uint32_t field_count);
extern int ObjectTemplateInternalFieldCount(TemplatePtr ptr);

extern TemplatePtr NewFunctionTemplate(IsolatePtr iso_ptr, int callback_ref);
extern RtnValue FunctionTemplateGetFunction(TemplatePtr ptr,
Expand Down Expand Up @@ -185,9 +186,10 @@ int ValueIsModuleNamespaceObject(ValuePtr ptr);
extern void ObjectSet(ValuePtr ptr, const char* key, ValuePtr val_ptr);
extern void ObjectSetIdx(ValuePtr ptr, uint32_t idx, ValuePtr val_ptr);
extern int ObjectSetInternalField(ValuePtr ptr, uint32_t idx, ValuePtr val_ptr);
extern int ObjectInternalFieldCount(ValuePtr ptr);
extern RtnValue ObjectGet(ValuePtr ptr, const char* key);
extern RtnValue ObjectGetIdx(ValuePtr ptr, uint32_t idx);
extern RtnValue ObjectGetInternalField(ValuePtr ptr, uint32_t idx);
extern ValuePtr ObjectGetInternalField(ValuePtr ptr, uint32_t idx);
int ObjectHas(ValuePtr ptr, const char* key);
int ObjectHasIdx(ValuePtr ptr, uint32_t idx);
int ObjectDelete(ValuePtr ptr, const char* key);
Expand Down

0 comments on commit d064e79

Please sign in to comment.