From 747f777a2441f3b5192eb5d7b84d5b5f14186c78 Mon Sep 17 00:00:00 2001 From: ChJR Date: Fri, 16 Aug 2019 18:01:39 +0900 Subject: [PATCH 1/4] Add test code from the CPython repository(Lib/test/test_bool.py). --- tests/snippets/bools.py | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/tests/snippets/bools.py b/tests/snippets/bools.py index c33fcff0fc..5becc16455 100644 --- a/tests/snippets/bools.py +++ b/tests/snippets/bools.py @@ -137,4 +137,39 @@ def __len__(self): with assertRaises(TypeError): - bool(TestLenThrowError()) \ No newline at end of file + bool(TestLenThrowError()) + +# Verify that TypeError occurs when bad things are returned +# from __bool__(). This isn't really a bool test, but +# it's related. +def check(o): + with assertRaises(TypeError): + bool(o) + +class Foo(object): + def __bool__(self): + return self +check(Foo()) + +class Bar(object): + def __bool__(self): + return "Yes" +check(Bar()) + +class Baz(int): + def __bool__(self): + return self +check(Baz()) + +# __bool__() must return a bool not an int +class Spam(int): + def __bool__(self): + return 1 +check(Spam()) + +class Eggs: + def __len__(self): + return -1 + +with assertRaises(ValueError): + bool(Eggs()) \ No newline at end of file From 7b980920b9c92e57a47a81815d2e58c2741b023e Mon Sep 17 00:00:00 2001 From: ChJR Date: Sun, 8 Sep 2019 17:09:47 +0900 Subject: [PATCH 2/4] Check __bool__() returns only bool value --- vm/src/obj/objbool.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/vm/src/obj/objbool.rs b/vm/src/obj/objbool.rs index 91d47c6266..c68df24b5f 100644 --- a/vm/src/obj/objbool.rs +++ b/vm/src/obj/objbool.rs @@ -29,6 +29,13 @@ pub fn boolval(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { // If descriptor returns Error, propagate it further let method = method_or_err?; let bool_obj = vm.invoke(&method, PyFuncArgs::default())?; + if !objtype::isinstance(&bool_obj, &vm.ctx.bool_type()) { + return Err(vm.new_type_error(format!( + "__bool__ should return bool, returned type {}", + bool_obj.class().name + ))); + } + match bool_obj.payload::() { Some(int_obj) => !int_obj.as_bigint().is_zero(), None => { From 21821b7a726bf9fc6340d7c555de66038a1b4f26 Mon Sep 17 00:00:00 2001 From: ChJR Date: Sun, 8 Sep 2019 17:42:02 +0900 Subject: [PATCH 3/4] Throw ValueError when __len__() is a negative value --- vm/src/obj/objbool.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/vm/src/obj/objbool.rs b/vm/src/obj/objbool.rs index c68df24b5f..aa4a777ffc 100644 --- a/vm/src/obj/objbool.rs +++ b/vm/src/obj/objbool.rs @@ -1,3 +1,4 @@ +use num_bigint::Sign; use num_traits::Zero; use crate::function::PyFuncArgs; @@ -51,7 +52,16 @@ pub fn boolval(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { let method = method_or_err?; let bool_obj = vm.invoke(&method, PyFuncArgs::default())?; match bool_obj.payload::() { - Some(int_obj) => !int_obj.as_bigint().is_zero(), + Some(int_obj) => { + let len_val = int_obj.as_bigint(); + if len_val.sign() == Sign::Minus { + return Err( + vm.new_value_error("__len__() should return >= 0".to_string()) + ); + } + + !len_val.is_zero() + } None => { return Err(vm.new_type_error(format!( "{} object cannot be interpreted as integer", From da020293d23bc1281513e48972c776b93b4bca9e Mon Sep 17 00:00:00 2001 From: ChJR Date: Sun, 8 Sep 2019 18:19:52 +0900 Subject: [PATCH 4/4] Refactor boolval() --- vm/src/obj/objbool.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/vm/src/obj/objbool.rs b/vm/src/obj/objbool.rs index aa4a777ffc..eef179353d 100644 --- a/vm/src/obj/objbool.rs +++ b/vm/src/obj/objbool.rs @@ -37,15 +37,7 @@ pub fn boolval(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult { ))); } - match bool_obj.payload::() { - Some(int_obj) => !int_obj.as_bigint().is_zero(), - None => { - return Err(vm.new_type_error(format!( - "__bool__ should return bool, returned type {}", - bool_obj.class().name - ))) - } - } + get_value(&bool_obj) } None => match vm.get_method(obj.clone(), "__len__") { Some(method_or_err) => {