def test_list_of_str0_unchecked(self): str0 = SomeString(no_nul=True) def os_execve(l): pass register_external(os_execve, [[str0]], None) def f(l): return os_execve(l) policy = AnnotatorPolicy() a = RPythonAnnotator(policy=policy) assert a.translator.config.translation.check_str_without_nul == False a.build_types(f, [[str]]) # Does not raise # Now enable the str0 check, and try again with a similar function a.translator.config.translation.check_str_without_nul=True def g(l): return os_execve(l) with py.test.raises(AnnotatorError): # fails with TooLateForChange a.build_types(g, [[str]]) a.build_types(g, [[str0]]) # Does not raise
def test_register_external_signature(self): """ Test the standard interface for external functions. """ def dd(): pass register_external(dd, [int], int) def f(): return dd(3) policy = AnnotatorPolicy() a = RPythonAnnotator(policy=policy) s = a.build_types(f, []) assert isinstance(s, annmodel.SomeInteger)
def test_register_external_signature(self): """ Test the standard interface for external functions. """ def dd(): pass register_external(dd, [int], int) def f(): return dd(3) policy = AnnotatorPolicy() a = RPythonAnnotator(policy=policy) s = a.build_types(f, []) assert isinstance(s, SomeInteger)
def test_register_external_specialcase(self): """ When args=None, the external function accepts any arguments unmodified. """ def function_withspecialcase(arg): return repr(arg) register_external(function_withspecialcase, args=None, result=str) def f(): x = function_withspecialcase return x(33) + x("aaa") + x([]) + "\n" policy = AnnotatorPolicy() a = RPythonAnnotator(policy=policy) s = a.build_types(f, []) assert isinstance(s, SomeString)
def test_register_external_specialcase(self): """ When args=None, the external function accepts any arguments unmodified. """ def function_withspecialcase(arg): return repr(arg) register_external(function_withspecialcase, args=None, result=str) def f(): x = function_withspecialcase return x(33) + x("aaa") + x([]) + "\n" policy = AnnotatorPolicy() a = RPythonAnnotator(policy=policy) s = a.build_types(f, []) assert isinstance(s, annmodel.SomeString)
def test_list_of_str0(self): str0 = annmodel.SomeString(no_nul=True) def os_execve(l): pass register_external(os_execve, [[str0]], None) def f(l): return os_execve(l) policy = AnnotatorPolicy() a = RPythonAnnotator(policy=policy) a.build_types(f, [[str]]) # Does not raise assert a.translator.config.translation.check_str_without_nul == False # Now enable the str0 check, and try again with a similar function a.translator.config.translation.check_str_without_nul=True def g(l): return os_execve(l) py.test.raises(Exception, a.build_types, g, [[str]]) a.build_types(g, [[str0]]) # Does not raise
def test_str0(self): str0 = SomeString(no_nul=True) def os_open(s): pass register_external(os_open, [str0], None) def f(s): return os_open(s) policy = AnnotatorPolicy() a = RPythonAnnotator(policy=policy) a.build_types(f, [str]) # Does not raise assert a.translator.config.translation.check_str_without_nul == False # Now enable the str0 check, and try again with a similar function a.translator.config.translation.check_str_without_nul=True def g(s): return os_open(s) with py.test.raises(SignatureError): a.build_types(g, [str]) a.build_types(g, [str0]) # Does not raise
def test_lltypeimpl(self): """ interpret() calls lltypeimpl instead of of the function/ """ def c(y, x): yyy def llimpl(y, x): return y + x register_external(c, [int, int], result=int, llimpl=llimpl, export_name='ccc') def f(): return c(3, 4) res = interpret(f, []) assert res == 7
def test_register_external_llfakeimpl(self): def a(i): return i def a_llimpl(i): return i * 2 def a_llfakeimpl(i): return i * 3 register_external(a, [int], int, llimpl=a_llimpl, llfakeimpl=a_llfakeimpl) def f(i): return a(i) res = interpret(f, [7]) assert res == 21 from rpython.translator.c.test.test_genc import compile fc = compile(f, [int]) assert fc(7) == 14
def test_register_external_return_goes_back(self): """ Check whether it works to pass the same list from one external fun to another [bookkeeper and list joining issues] """ def function_with_list(): pass register_external(function_with_list, [[int]], int) def function_returning_list(): pass register_external(function_returning_list, [], [int]) def f(): return function_with_list(function_returning_list()) policy = AnnotatorPolicy() a = RPythonAnnotator(policy=policy) s = a.build_types(f, []) assert isinstance(s, SomeInteger)
def test_basic(self): """ A ExtFuncEntry provides an annotation for a function, no need to flow its graph. """ def b(x): "NOT_RPYTHON" return eval("x+40") register_external(b, [int], result=int) def f(): return b(2) policy = AnnotatorPolicy() a = RPythonAnnotator(policy=policy) s = a.build_types(f, []) assert isinstance(s, SomeInteger) res = interpret(f, []) assert res == 42
def test_register_external_tuple_args(self): """ Verify the annotation of a registered external function which takes a tuple argument. """ def function_with_tuple_arg(): """ Dummy function which is declared via register_external to take a tuple as an argument so that register_external's behavior for tuple-taking functions can be verified. """ register_external(function_with_tuple_arg, [(int,)], int) def f(): return function_with_tuple_arg((1,)) policy = AnnotatorPolicy() a = RPythonAnnotator(policy=policy) s = a.build_types(f, []) # Not a very good assertion, but at least it means _something_ happened. assert isinstance(s, SomeInteger)
def test_raising_llimpl(): from rpython.rtyper.extfunc import register_external def external(): pass def raising(): raise OSError(15, "abcd") ext = register_external(external, [], llimpl=raising, llfakeimpl=raising) def f(): # this is a useful llfakeimpl that raises an exception try: external() return True except OSError: return False res = interpret(f, []) assert not res
from rpython.rtyper.lltypesystem.module import ll_math from rpython.rtyper.module import ll_os from rpython.rtyper.module import ll_time from rpython.rtyper.module import ll_pdb from rpython.rlib import rfloat # the following functions all take one float, return one float # and are part of math.h for name in ll_math.unary_math_functions: llimpl = getattr(ll_math, 'll_math_%s' % name, None) try: f = getattr(math, name) except AttributeError: f = getattr(rfloat, name) register_external(f, [float], float, export_name="ll_math.ll_math_%s" % name, sandboxsafe=True, llimpl=llimpl) _register = [ # (module, [(method name, arg types, return type), ...], ...) (rfloat, [ ('isinf', [float], bool), ('isnan', [float], bool), ('isfinite', [float], bool), ('copysign', [float, float], float), ]), (math, [ ('floor', [float], float), ('sqrt', [float], float), ('log', [float], float), ('log10', [float], float), ('log1p', [float], float),
try: if c_tcgetattr(fd, c_struct) < 0: raise OSError(rposix.get_errno(), 'tcgetattr failed') cc = [chr(c_struct.c_c_cc[i]) for i in range(NCCS)] ispeed = c_cfgetispeed(c_struct) ospeed = c_cfgetospeed(c_struct) result = (intmask(c_struct.c_c_iflag), intmask(c_struct.c_c_oflag), intmask(c_struct.c_c_cflag), intmask(c_struct.c_c_lflag), intmask(ispeed), intmask(ospeed), cc) return result finally: lltype.free(c_struct, flavor='raw') register_external(rtermios.tcgetattr, [int], (int, int, int, int, int, int, [str]), llimpl=tcgetattr_llimpl, export_name='termios.tcgetattr') def tcsetattr_llimpl(fd, when, attributes): c_struct = lltype.malloc(TERMIOSP.TO, flavor='raw') try: c_struct.c_c_iflag = r_uint(attributes[0]) c_struct.c_c_oflag = r_uint(attributes[1]) c_struct.c_c_cflag = r_uint(attributes[2]) c_struct.c_c_lflag = r_uint(attributes[3]) ispeed = r_uint(attributes[4]) ospeed = r_uint(attributes[5]) cc = attributes[6] for i in range(NCCS): c_struct.c_c_cc[i] = rffi.r_uchar(ord(cc[i][0]))
c_struct = lltype.malloc(TERMIOSP.TO, flavor='raw') try: if c_tcgetattr(fd, c_struct) < 0: raise OSError(rposix.get_errno(), 'tcgetattr failed') cc = [chr(c_struct.c_c_cc[i]) for i in range(NCCS)] ispeed = c_cfgetispeed(c_struct) ospeed = c_cfgetospeed(c_struct) result = (intmask(c_struct.c_c_iflag), intmask(c_struct.c_c_oflag), intmask(c_struct.c_c_cflag), intmask(c_struct.c_c_lflag), intmask(ispeed), intmask(ospeed), cc) return result finally: lltype.free(c_struct, flavor='raw') register_external(rtermios.tcgetattr, [int], (int, int, int, int, int, int, [str]), llimpl=tcgetattr_llimpl, export_name='termios.tcgetattr') def tcsetattr_llimpl(fd, when, attributes): c_struct = lltype.malloc(TERMIOSP.TO, flavor='raw') try: c_struct.c_c_iflag = r_uint(attributes[0]) c_struct.c_c_oflag = r_uint(attributes[1]) c_struct.c_c_cflag = r_uint(attributes[2]) c_struct.c_c_lflag = r_uint(attributes[3]) ispeed = r_uint(attributes[4]) ospeed = r_uint(attributes[5]) cc = attributes[6] for i in range(NCCS): c_struct.c_c_cc[i] = rffi.r_uchar(ord(cc[i][0])) if c_cfsetispeed(c_struct, ispeed) < 0: raise OSError(rposix.get_errno(), 'tcsetattr failed')
import math from rpython.rtyper.lltypesystem.module import ll_math from rpython.rtyper.module import ll_os from rpython.rtyper.module import ll_time from rpython.rlib import rfloat # the following functions all take one float, return one float # and are part of math.h for name in ll_math.unary_math_functions: llimpl = getattr(ll_math, 'll_math_%s' % name, None) try: f = getattr(math, name) except AttributeError: f = getattr(rfloat, name) register_external(f, [float], float, export_name="ll_math.ll_math_%s" % name, sandboxsafe=True, llimpl=llimpl) _register = [ # (module, [(method name, arg types, return type), ...], ...) (rfloat, [ ('isinf', [float], bool), ('isnan', [float], bool), ('isfinite', [float], bool), ('copysign', [float, float], float), ]), (math, [ ('floor', [float], float), ('sqrt', [float], float), ('log', [float], float), ('log10', [float], float), ('log1p', [float], float),
_lconv = lltype.Ptr(cConfig.lconv) localeconv = external('localeconv', [], _lconv) def numeric_formatting(): """Specialized function to get formatting for numbers""" return numeric_formatting_impl() def numeric_formatting_impl(): conv = localeconv() decimal_point = rffi.charp2str(conv.c_decimal_point) thousands_sep = rffi.charp2str(conv.c_thousands_sep) grouping = rffi.charp2str(conv.c_grouping) return decimal_point, thousands_sep, grouping register_external(numeric_formatting, [], (str, str, str), llimpl=numeric_formatting_impl, sandboxsafe=True) _setlocale = external('setlocale', [rffi.INT, rffi.CCHARP], rffi.CCHARP) def setlocale(category, locale): if cConfig.LC_MAX is not None: if not cConfig.LC_MIN <= category <= cConfig.LC_MAX: raise LocaleError("invalid locale category") ll_result = _setlocale(rffi.cast(rffi.INT, category), locale) if not ll_result: raise LocaleError("unsupported locale setting") return rffi.charp2str(ll_result) isalpha = external('isalpha', [rffi.INT], rffi.INT, oo_primitive='locale_isalpha')
def envkeys_llimpl(): environ = os_get_environ() result = [] i = 0 while environ[i]: name_value = rffi.charp2str(environ[i]) p = name_value.find("=") if p >= 0: result.append(name_value[:p]) i += 1 return result register_external( r_envkeys, [], [str0], export_name="ll_os.ll_os_envkeys", llimpl=envkeys_llimpl # returns a list of strings ) # ____________________________________________________________ def r_envitems(): just_a_placeholder def r_getenv(name): just_a_placeholder # should return None if name not found def r_putenv(name, value): just_a_placeholder
sandboxsafe=True, _nowrapper=True) def llimpl_arena_malloc(nbytes, zero): if zero: addr = llimpl_calloc(nbytes, 1) else: addr = llimpl_malloc(nbytes) return addr llimpl_arena_malloc._always_inline_ = True register_external(arena_malloc, [int, int], llmemory.Address, 'll_arena.arena_malloc', llimpl=llimpl_arena_malloc, llfakeimpl=arena_malloc, sandboxsafe=True) register_external(arena_free, [llmemory.Address], None, 'll_arena.arena_free', llimpl=llimpl_free, llfakeimpl=arena_free, sandboxsafe=True) def llimpl_arena_reset(arena_addr, size, zero): if zero: if zero == 1: clear_large_memory_chunk(arena_addr, size)
def allow_attach(): pass def impl_attach_gdb(): import os allow_attach() pid = os.getpid() gdbpid = os.fork() if gdbpid == 0: shell = os.environ.get("SHELL") or "/bin/sh" sepidx = shell.rfind(os.sep) + 1 if sepidx > 0: argv0 = shell[sepidx:] else: argv0 = shell try: os.execv(shell, [argv0, "-c", "gdb -p %d" % pid]) except OSError as e: os.write(2, "Could not start GDB: %s" % ( os.strerror(e.errno))) raise SystemExit else: time.sleep(1) # give the GDB time to attach else: def impl_attach_gdb(): print "Don't know how to attach GDB on Windows" register_external(attach_gdb, [], result=None, export_name="impl_attach_gdb", llimpl=impl_attach_gdb)
interp_curses.module_info.setupterm_called = True finally: lltype.free(intp, flavor='raw') def curses_setupterm_null_llimpl(fd): curses_setupterm(lltype.nullptr(rffi.CCHARP.TO), fd) def curses_setupterm_llimpl(term, fd): ll_s = rffi.str2charp(term) try: curses_setupterm(ll_s, fd) finally: rffi.free_charp(ll_s) register_external(interp_curses._curses_setupterm_null, [int], llimpl=curses_setupterm_null_llimpl, export_name='_curses.setupterm_null') register_external(interp_curses._curses_setupterm, [str, int], llimpl=curses_setupterm_llimpl, export_name='_curses.setupterm') def check_setup_invoked(): if not interp_curses.module_info.setupterm_called: raise interp_curses.curses_error("must call (at least) setupterm() first") def tigetstr_llimpl(cap): check_setup_invoked() ll_cap = rffi.str2charp(cap) try: ll_res = c_tigetstr(ll_cap) num = lltype.cast_ptr_to_int(ll_res)
just_a_placeholder def envkeys_llimpl(): environ = os_get_environ() result = [] i = 0 while environ[i]: name_value = rffi.charp2str(environ[i]) p = name_value.find('=') if p >= 0: result.append(name_value[:p]) i += 1 return result register_external(r_envkeys, [], [str0], # returns a list of strings export_name='ll_os.ll_os_envkeys', llimpl=envkeys_llimpl) # ____________________________________________________________ def r_envitems(): just_a_placeholder def r_getenv(name): just_a_placeholder # should return None if name not found def r_putenv(name, value): just_a_placeholder os_getenv = llexternal('getenv', [rffi.CCHARP], rffi.CCHARP) os_putenv = llexternal(prefix + 'putenv', [rffi.CCHARP], rffi.INT,
def curses_setupterm_null_llimpl(fd): curses_setupterm(lltype.nullptr(rffi.CCHARP.TO), fd) def curses_setupterm_llimpl(term, fd): ll_s = rffi.str2charp(term) try: curses_setupterm(ll_s, fd) finally: rffi.free_charp(ll_s) register_external(interp_curses._curses_setupterm_null, [int], llimpl=curses_setupterm_null_llimpl, export_name='_curses.setupterm_null') register_external(interp_curses._curses_setupterm, [str, int], llimpl=curses_setupterm_llimpl, export_name='_curses.setupterm') def check_setup_invoked(): if not interp_curses.module_info.setupterm_called: raise interp_curses.curses_error( "must call (at least) setupterm() first") def tigetstr_llimpl(cap): check_setup_invoked() ll_cap = rffi.str2charp(cap)
llimpl_calloc = rffi.llexternal('calloc', [lltype.Signed, lltype.Signed], llmemory.Address, sandboxsafe=True, _nowrapper=True) llimpl_free = rffi.llexternal('free', [llmemory.Address], lltype.Void, sandboxsafe=True, _nowrapper=True) def llimpl_arena_malloc(nbytes, zero): if zero: addr = llimpl_calloc(nbytes, 1) else: addr = llimpl_malloc(nbytes) return addr llimpl_arena_malloc._always_inline_ = True register_external(arena_malloc, [int, int], llmemory.Address, 'll_arena.arena_malloc', llimpl=llimpl_arena_malloc, llfakeimpl=arena_malloc, sandboxsafe=True) register_external(arena_free, [llmemory.Address], None, 'll_arena.arena_free', llimpl=llimpl_free, llfakeimpl=arena_free, sandboxsafe=True) def llimpl_arena_reset(arena_addr, size, zero): if zero: if zero == 1: clear_large_memory_chunk(arena_addr, size) elif zero == 3: llop.raw_memset(lltype.Void, arena_addr, ord('#'), size) elif zero == 4:
def impl_attach_gdb(): import os allow_attach() pid = os.getpid() gdbpid = os.fork() if gdbpid == 0: shell = os.environ.get("SHELL") or "/bin/sh" sepidx = shell.rfind(os.sep) + 1 if sepidx > 0: argv0 = shell[sepidx:] else: argv0 = shell try: os.execv(shell, [argv0, "-c", "gdb -p %d" % pid]) except OSError as e: os.write(2, "Could not start GDB: %s" % (os.strerror(e.errno))) raise SystemExit else: time.sleep(1) # give the GDB time to attach else: def impl_attach_gdb(): print "Don't know how to attach GDB on Windows" register_external(attach_gdb, [], result=None, export_name="impl_attach_gdb", llimpl=impl_attach_gdb)
def numeric_formatting(): """Specialized function to get formatting for numbers""" return numeric_formatting_impl() def numeric_formatting_impl(): conv = localeconv() decimal_point = rffi.charp2str(conv.c_decimal_point) thousands_sep = rffi.charp2str(conv.c_thousands_sep) grouping = rffi.charp2str(conv.c_grouping) return decimal_point, thousands_sep, grouping register_external(numeric_formatting, [], (str, str, str), llimpl=numeric_formatting_impl, sandboxsafe=True) _setlocale = external('setlocale', [rffi.INT, rffi.CCHARP], rffi.CCHARP) def setlocale(category, locale): if cConfig.LC_MAX is not None: if not cConfig.LC_MIN <= category <= cConfig.LC_MAX: raise LocaleError("invalid locale category") ll_result = _setlocale(rffi.cast(rffi.INT, category), locale) if not ll_result: raise LocaleError("unsupported locale setting") return rffi.charp2str(ll_result)