11pub mod instructions;
22
3- use super :: objects:: { Object , Code , ObjectStore , ObjectRef , ObjectContent } ;
3+ use super :: objects:: { Code , ObjectStore , ObjectRef , ObjectContent } ;
44use super :: sandbox:: EnvProxy ;
55use super :: stack:: { Stack , VectorStack } ;
66use self :: instructions:: Instruction ;
77use std:: fmt;
8+ use std:: collections:: HashMap ;
9+ use std:: io:: Write ;
810
911#[ derive( Debug ) ]
1012pub enum ProcessorError {
@@ -16,6 +18,8 @@ pub enum ProcessorError {
1618 StackTooSmall ,
1719 InvalidConstIndex ,
1820 InvalidNameIndex ,
21+ UnknownBuiltin ( String ) ,
22+ Exception ( String ) ,
1923}
2024
2125impl fmt:: Display for ProcessorError {
@@ -24,45 +28,98 @@ impl fmt::Display for ProcessorError {
2428 }
2529}
2630
27- fn call_function < EP : EnvProxy > ( envproxy : & mut EP , store : & mut ObjectStore , func_ref : & ObjectRef , args : Vec < ObjectRef > , kwags : Vec < ObjectRef > ) -> Result < ObjectRef , ProcessorError > {
28- let code = match store. deref ( func_ref) . content {
29- ObjectContent :: Code ( ref code) => code. clone ( ) ,
30- ref o => return Err ( ProcessorError :: NotACodeObject ( format ! ( "{:?}" , o) ) ) ,
31- } ;
32- run_code ( envproxy, store, code)
33- }
34-
35- fn run_code < EP : EnvProxy > ( envproxy : & mut EP , store : & mut ObjectStore , code : Code ) -> Result < ObjectRef , ProcessorError > {
36- let bytecode: Vec < u8 > = code. code ;
37- let instructions: Vec < Instruction > = instructions:: InstructionDecoder :: new ( bytecode. iter ( ) ) . into_iter ( ) . collect ( ) ;
38- let mut program_counter = 0 as usize ;
39- let mut stack = VectorStack :: new ( ) ;
40- while true {
41- let instruction = try!( instructions. get ( program_counter) . ok_or ( ProcessorError :: InvalidProgramCounter ) ) ;
42- program_counter += 1 ;
43- match * instruction {
44- Instruction :: ReturnValue => return Ok ( try!( stack. pop ( ) . ok_or ( ProcessorError :: StackTooSmall ) ) ) ,
45- Instruction :: LoadConst ( i) => stack. push ( try!( code. names . get ( i) . ok_or ( ProcessorError :: InvalidConstIndex ) ) . clone ( ) ) ,
46- Instruction :: LoadName ( i) => stack. push ( try!( code. names . get ( i) . ok_or ( ProcessorError :: InvalidNameIndex ) ) . clone ( ) ) ,
47- Instruction :: CallFunction ( nb_args, nb_kwargs) => {
48- // See “Call constructs” at:
49- // http://security.coverity.com/blog/2014/Nov/understanding-python-bytecode.html
50- let kwargs = try!( stack. pop_many ( nb_kwargs* 2 ) . ok_or ( ProcessorError :: StackTooSmall ) ) ;
51- let args = try!( stack. pop_many ( nb_args) . ok_or ( ProcessorError :: StackTooSmall ) ) ;
52- let func = try!( stack. pop ( ) . ok_or ( ProcessorError :: StackTooSmall ) ) ;
53- let ret_value = call_function ( envproxy, store, & func, args, kwargs) ;
54- stack. push ( try!( ret_value) )
31+ fn builtin_print < EP : EnvProxy > ( processor : & mut Processor < EP > , args : Vec < ObjectRef > , kwargs : HashMap < String , ObjectRef > ) -> Result < ObjectRef , ProcessorError > {
32+ if args. len ( ) > 1 {
33+ return Err ( ProcessorError :: Exception ( format ! ( "print takes exactly one argument, not {}." , args. len( ) ) ) )
34+ }
35+ else {
36+ let obj_ref = args. get ( 0 ) . unwrap ( ) ;
37+ match processor. store . deref ( obj_ref) . content {
38+ ObjectContent :: String ( ref s) => {
39+ processor. envproxy . stdout ( ) . write ( s. clone ( ) . into_bytes ( ) . as_slice ( ) ) . unwrap ( ) ; // TODO: check
40+ processor. envproxy . stdout ( ) . write ( b"\n " ) . unwrap ( ) ; // TODO: check
5541 }
56- _ => panic ! ( format!( "todo: instruction {:?}" , * instruction ) ) ,
42+ ref o => return Err ( ProcessorError :: Exception ( format ! ( "print takes a string, not {:?}" , o ) ) ) ,
5743 }
58- } ;
59- panic ! ( "Unreachable" )
44+ }
45+ Ok ( processor . store . allocate ( ObjectContent :: None ) )
6046}
6147
62- pub fn run_code_object < EP : EnvProxy > ( envproxy : & mut EP , store : & mut ObjectStore , module : ObjectRef ) -> Result < ObjectRef , ProcessorError > {
63- let code = match store. deref ( & module) . content {
64- ObjectContent :: Code ( ref code) => code. clone ( ) ,
65- ref o => return Err ( ProcessorError :: NotACodeObject ( format ! ( "{:?}" , o) ) ) ,
66- } ;
67- run_code ( envproxy, store, code)
48+ pub type PyFunction < EP > = fn ( & mut Processor < EP > , /*args:*/ Vec < ObjectRef > , /*kwargs:*/ HashMap < String , ObjectRef > ) -> Result < ObjectRef , ProcessorError > ;
49+
50+ pub struct Processor < EP : EnvProxy > {
51+ pub envproxy : EP ,
52+ pub store : ObjectStore ,
53+ pub builtin_functions : HashMap < String , PyFunction < EP > > ,
54+ }
55+
56+ impl < EP : EnvProxy > Processor < EP > {
57+ pub fn get_default_builtins ( ) -> HashMap < String , PyFunction < EP > > {
58+ let mut builtins: HashMap < String , PyFunction < EP > > = HashMap :: new ( ) ;
59+ builtins. insert ( "print" . to_string ( ) , builtin_print) ;
60+ builtins
61+ }
62+
63+ fn load_name ( & mut self , name : String ) -> Result < ObjectRef , ProcessorError > {
64+ Ok ( self . store . allocate ( ObjectContent :: BuiltinFunction ( name) ) )
65+ }
66+
67+ fn call_function ( & mut self , func_ref : & ObjectRef , args : Vec < ObjectRef > , kwargs : Vec < ObjectRef > ) -> Result < ObjectRef , ProcessorError > {
68+ // TODO: clone only if necessary
69+ match self . store . deref ( func_ref) . content . clone ( ) {
70+ ObjectContent :: Code ( code) => {
71+ self . run_code ( code)
72+ } ,
73+ ObjectContent :: BuiltinFunction ( name) => {
74+ let f = match self . builtin_functions . get ( & name) {
75+ Some ( f) => f. clone ( ) ,
76+ None => return Err ( ProcessorError :: UnknownBuiltin ( name. clone ( ) ) ) ,
77+ } ;
78+ f ( self , args, HashMap :: new ( ) ) // TODO: use the real kwargs
79+ } ,
80+ ref o => return Err ( ProcessorError :: NotACodeObject ( format ! ( "{:?}" , o) ) ) ,
81+ }
82+ }
83+
84+ fn run_code ( & mut self , code : Code ) -> Result < ObjectRef , ProcessorError > {
85+ let bytecode: Vec < u8 > = code. code ;
86+ let instructions: Vec < Instruction > = instructions:: InstructionDecoder :: new ( bytecode. iter ( ) ) . into_iter ( ) . collect ( ) ;
87+ let mut program_counter = 0 as usize ;
88+ let mut stack = VectorStack :: new ( ) ;
89+ while true {
90+ let instruction = try!( instructions. get ( program_counter) . ok_or ( ProcessorError :: InvalidProgramCounter ) ) ;
91+ program_counter += 1 ;
92+ match * instruction {
93+ Instruction :: PopTop => {
94+ try!( stack. pop ( ) . ok_or ( ProcessorError :: StackTooSmall ) ) ;
95+ ( )
96+ } ,
97+ Instruction :: ReturnValue => return Ok ( try!( stack. pop ( ) . ok_or ( ProcessorError :: StackTooSmall ) ) ) ,
98+ Instruction :: LoadConst ( i) => stack. push ( try!( code. consts . get ( i) . ok_or ( ProcessorError :: InvalidConstIndex ) ) . clone ( ) ) ,
99+ Instruction :: LoadName ( i) => {
100+ let name = try!( code. names . get ( i) . ok_or ( ProcessorError :: InvalidNameIndex ) ) . clone ( ) ;
101+ stack. push ( try!( self . load_name ( name) ) )
102+ }
103+ Instruction :: CallFunction ( nb_args, nb_kwargs) => {
104+ // See “Call constructs” at:
105+ // http://security.coverity.com/blog/2014/Nov/understanding-python-bytecode.html
106+ let kwargs = try!( stack. pop_many ( nb_kwargs* 2 ) . ok_or ( ProcessorError :: StackTooSmall ) ) ;
107+ let args = try!( stack. pop_many ( nb_args) . ok_or ( ProcessorError :: StackTooSmall ) ) ;
108+ let func = try!( stack. pop ( ) . ok_or ( ProcessorError :: StackTooSmall ) ) ;
109+ let ret_value = self . call_function ( & func, args, kwargs) ;
110+ stack. push ( try!( ret_value) )
111+ }
112+ _ => panic ! ( format!( "todo: instruction {:?}" , * instruction) ) ,
113+ }
114+ } ;
115+ panic ! ( "Unreachable" )
116+ }
117+
118+ pub fn run_code_object ( & mut self , module : ObjectRef ) -> Result < ObjectRef , ProcessorError > {
119+ let code = match self . store . deref ( & module) . content {
120+ ObjectContent :: Code ( ref code) => code. clone ( ) ,
121+ ref o => return Err ( ProcessorError :: NotACodeObject ( format ! ( "{:?}" , o) ) ) ,
122+ } ;
123+ self . run_code ( code)
124+ }
68125}
0 commit comments