vengine_gen.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. #
  2. # DEPRECATED: implementation for ffi.verify()
  3. #
  4. import sys, os
  5. import types
  6. from . import model
  7. from .error import VerificationError
  8. class VGenericEngine(object):
  9. _class_key = 'g'
  10. _gen_python_module = False
  11. def __init__(self, verifier):
  12. self.verifier = verifier
  13. self.ffi = verifier.ffi
  14. self.export_symbols = []
  15. self._struct_pending_verification = {}
  16. def patch_extension_kwds(self, kwds):
  17. # add 'export_symbols' to the dictionary. Note that we add the
  18. # list before filling it. When we fill it, it will thus also show
  19. # up in kwds['export_symbols'].
  20. kwds.setdefault('export_symbols', self.export_symbols)
  21. def find_module(self, module_name, path, so_suffixes):
  22. for so_suffix in so_suffixes:
  23. basename = module_name + so_suffix
  24. if path is None:
  25. path = sys.path
  26. for dirname in path:
  27. filename = os.path.join(dirname, basename)
  28. if os.path.isfile(filename):
  29. return filename
  30. def collect_types(self):
  31. pass # not needed in the generic engine
  32. def _prnt(self, what=''):
  33. self._f.write(what + '\n')
  34. def write_source_to_f(self):
  35. prnt = self._prnt
  36. # first paste some standard set of lines that are mostly '#include'
  37. prnt(cffimod_header)
  38. # then paste the C source given by the user, verbatim.
  39. prnt(self.verifier.preamble)
  40. #
  41. # call generate_gen_xxx_decl(), for every xxx found from
  42. # ffi._parser._declarations. This generates all the functions.
  43. self._generate('decl')
  44. #
  45. # on Windows, distutils insists on putting init_cffi_xyz in
  46. # 'export_symbols', so instead of fighting it, just give up and
  47. # give it one
  48. if sys.platform == 'win32':
  49. if sys.version_info >= (3,):
  50. prefix = 'PyInit_'
  51. else:
  52. prefix = 'init'
  53. modname = self.verifier.get_module_name()
  54. prnt("void %s%s(void) { }\n" % (prefix, modname))
  55. def load_library(self, flags=0):
  56. # import it with the CFFI backend
  57. backend = self.ffi._backend
  58. # needs to make a path that contains '/', on Posix
  59. filename = os.path.join(os.curdir, self.verifier.modulefilename)
  60. module = backend.load_library(filename, flags)
  61. #
  62. # call loading_gen_struct() to get the struct layout inferred by
  63. # the C compiler
  64. self._load(module, 'loading')
  65. # build the FFILibrary class and instance, this is a module subclass
  66. # because modules are expected to have usually-constant-attributes and
  67. # in PyPy this means the JIT is able to treat attributes as constant,
  68. # which we want.
  69. class FFILibrary(types.ModuleType):
  70. _cffi_generic_module = module
  71. _cffi_ffi = self.ffi
  72. _cffi_dir = []
  73. def __dir__(self):
  74. return FFILibrary._cffi_dir
  75. library = FFILibrary("")
  76. #
  77. # finally, call the loaded_gen_xxx() functions. This will set
  78. # up the 'library' object.
  79. self._load(module, 'loaded', library=library)
  80. return library
  81. def _get_declarations(self):
  82. lst = [(key, tp) for (key, (tp, qual)) in
  83. self.ffi._parser._declarations.items()]
  84. lst.sort()
  85. return lst
  86. def _generate(self, step_name):
  87. for name, tp in self._get_declarations():
  88. kind, realname = name.split(' ', 1)
  89. try:
  90. method = getattr(self, '_generate_gen_%s_%s' % (kind,
  91. step_name))
  92. except AttributeError:
  93. raise VerificationError(
  94. "not implemented in verify(): %r" % name)
  95. try:
  96. method(tp, realname)
  97. except Exception as e:
  98. model.attach_exception_info(e, name)
  99. raise
  100. def _load(self, module, step_name, **kwds):
  101. for name, tp in self._get_declarations():
  102. kind, realname = name.split(' ', 1)
  103. method = getattr(self, '_%s_gen_%s' % (step_name, kind))
  104. try:
  105. method(tp, realname, module, **kwds)
  106. except Exception as e:
  107. model.attach_exception_info(e, name)
  108. raise
  109. def _generate_nothing(self, tp, name):
  110. pass
  111. def _loaded_noop(self, tp, name, module, **kwds):
  112. pass
  113. # ----------
  114. # typedefs: generates no code so far
  115. _generate_gen_typedef_decl = _generate_nothing
  116. _loading_gen_typedef = _loaded_noop
  117. _loaded_gen_typedef = _loaded_noop
  118. # ----------
  119. # function declarations
  120. def _generate_gen_function_decl(self, tp, name):
  121. assert isinstance(tp, model.FunctionPtrType)
  122. if tp.ellipsis:
  123. # cannot support vararg functions better than this: check for its
  124. # exact type (including the fixed arguments), and build it as a
  125. # constant function pointer (no _cffi_f_%s wrapper)
  126. self._generate_gen_const(False, name, tp)
  127. return
  128. prnt = self._prnt
  129. numargs = len(tp.args)
  130. argnames = []
  131. for i, type in enumerate(tp.args):
  132. indirection = ''
  133. if isinstance(type, model.StructOrUnion):
  134. indirection = '*'
  135. argnames.append('%sx%d' % (indirection, i))
  136. context = 'argument of %s' % name
  137. arglist = [type.get_c_name(' %s' % arg, context)
  138. for type, arg in zip(tp.args, argnames)]
  139. tpresult = tp.result
  140. if isinstance(tpresult, model.StructOrUnion):
  141. arglist.insert(0, tpresult.get_c_name(' *r', context))
  142. tpresult = model.void_type
  143. arglist = ', '.join(arglist) or 'void'
  144. wrappername = '_cffi_f_%s' % name
  145. self.export_symbols.append(wrappername)
  146. if tp.abi:
  147. abi = tp.abi + ' '
  148. else:
  149. abi = ''
  150. funcdecl = ' %s%s(%s)' % (abi, wrappername, arglist)
  151. context = 'result of %s' % name
  152. prnt(tpresult.get_c_name(funcdecl, context))
  153. prnt('{')
  154. #
  155. if isinstance(tp.result, model.StructOrUnion):
  156. result_code = '*r = '
  157. elif not isinstance(tp.result, model.VoidType):
  158. result_code = 'return '
  159. else:
  160. result_code = ''
  161. prnt(' %s%s(%s);' % (result_code, name, ', '.join(argnames)))
  162. prnt('}')
  163. prnt()
  164. _loading_gen_function = _loaded_noop
  165. def _loaded_gen_function(self, tp, name, module, library):
  166. assert isinstance(tp, model.FunctionPtrType)
  167. if tp.ellipsis:
  168. newfunction = self._load_constant(False, tp, name, module)
  169. else:
  170. indirections = []
  171. base_tp = tp
  172. if (any(isinstance(typ, model.StructOrUnion) for typ in tp.args)
  173. or isinstance(tp.result, model.StructOrUnion)):
  174. indirect_args = []
  175. for i, typ in enumerate(tp.args):
  176. if isinstance(typ, model.StructOrUnion):
  177. typ = model.PointerType(typ)
  178. indirections.append((i, typ))
  179. indirect_args.append(typ)
  180. indirect_result = tp.result
  181. if isinstance(indirect_result, model.StructOrUnion):
  182. if indirect_result.fldtypes is None:
  183. raise TypeError("'%s' is used as result type, "
  184. "but is opaque" % (
  185. indirect_result._get_c_name(),))
  186. indirect_result = model.PointerType(indirect_result)
  187. indirect_args.insert(0, indirect_result)
  188. indirections.insert(0, ("result", indirect_result))
  189. indirect_result = model.void_type
  190. tp = model.FunctionPtrType(tuple(indirect_args),
  191. indirect_result, tp.ellipsis)
  192. BFunc = self.ffi._get_cached_btype(tp)
  193. wrappername = '_cffi_f_%s' % name
  194. newfunction = module.load_function(BFunc, wrappername)
  195. for i, typ in indirections:
  196. newfunction = self._make_struct_wrapper(newfunction, i, typ,
  197. base_tp)
  198. setattr(library, name, newfunction)
  199. type(library)._cffi_dir.append(name)
  200. def _make_struct_wrapper(self, oldfunc, i, tp, base_tp):
  201. backend = self.ffi._backend
  202. BType = self.ffi._get_cached_btype(tp)
  203. if i == "result":
  204. ffi = self.ffi
  205. def newfunc(*args):
  206. res = ffi.new(BType)
  207. oldfunc(res, *args)
  208. return res[0]
  209. else:
  210. def newfunc(*args):
  211. args = args[:i] + (backend.newp(BType, args[i]),) + args[i+1:]
  212. return oldfunc(*args)
  213. newfunc._cffi_base_type = base_tp
  214. return newfunc
  215. # ----------
  216. # named structs
  217. def _generate_gen_struct_decl(self, tp, name):
  218. assert name == tp.name
  219. self._generate_struct_or_union_decl(tp, 'struct', name)
  220. def _loading_gen_struct(self, tp, name, module):
  221. self._loading_struct_or_union(tp, 'struct', name, module)
  222. def _loaded_gen_struct(self, tp, name, module, **kwds):
  223. self._loaded_struct_or_union(tp)
  224. def _generate_gen_union_decl(self, tp, name):
  225. assert name == tp.name
  226. self._generate_struct_or_union_decl(tp, 'union', name)
  227. def _loading_gen_union(self, tp, name, module):
  228. self._loading_struct_or_union(tp, 'union', name, module)
  229. def _loaded_gen_union(self, tp, name, module, **kwds):
  230. self._loaded_struct_or_union(tp)
  231. def _generate_struct_or_union_decl(self, tp, prefix, name):
  232. if tp.fldnames is None:
  233. return # nothing to do with opaque structs
  234. checkfuncname = '_cffi_check_%s_%s' % (prefix, name)
  235. layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
  236. cname = ('%s %s' % (prefix, name)).strip()
  237. #
  238. prnt = self._prnt
  239. prnt('static void %s(%s *p)' % (checkfuncname, cname))
  240. prnt('{')
  241. prnt(' /* only to generate compile-time warnings or errors */')
  242. prnt(' (void)p;')
  243. for fname, ftype, fbitsize, fqual in tp.enumfields():
  244. if (isinstance(ftype, model.PrimitiveType)
  245. and ftype.is_integer_type()) or fbitsize >= 0:
  246. # accept all integers, but complain on float or double
  247. prnt(' (void)((p->%s) << 1);' % fname)
  248. else:
  249. # only accept exactly the type declared.
  250. try:
  251. prnt(' { %s = &p->%s; (void)tmp; }' % (
  252. ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual),
  253. fname))
  254. except VerificationError as e:
  255. prnt(' /* %s */' % str(e)) # cannot verify it, ignore
  256. prnt('}')
  257. self.export_symbols.append(layoutfuncname)
  258. prnt('intptr_t %s(intptr_t i)' % (layoutfuncname,))
  259. prnt('{')
  260. prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname)
  261. prnt(' static intptr_t nums[] = {')
  262. prnt(' sizeof(%s),' % cname)
  263. prnt(' offsetof(struct _cffi_aligncheck, y),')
  264. for fname, ftype, fbitsize, fqual in tp.enumfields():
  265. if fbitsize >= 0:
  266. continue # xxx ignore fbitsize for now
  267. prnt(' offsetof(%s, %s),' % (cname, fname))
  268. if isinstance(ftype, model.ArrayType) and ftype.length is None:
  269. prnt(' 0, /* %s */' % ftype._get_c_name())
  270. else:
  271. prnt(' sizeof(((%s *)0)->%s),' % (cname, fname))
  272. prnt(' -1')
  273. prnt(' };')
  274. prnt(' return nums[i];')
  275. prnt(' /* the next line is not executed, but compiled */')
  276. prnt(' %s(0);' % (checkfuncname,))
  277. prnt('}')
  278. prnt()
  279. def _loading_struct_or_union(self, tp, prefix, name, module):
  280. if tp.fldnames is None:
  281. return # nothing to do with opaque structs
  282. layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name)
  283. #
  284. BFunc = self.ffi._typeof_locked("intptr_t(*)(intptr_t)")[0]
  285. function = module.load_function(BFunc, layoutfuncname)
  286. layout = []
  287. num = 0
  288. while True:
  289. x = function(num)
  290. if x < 0: break
  291. layout.append(x)
  292. num += 1
  293. if isinstance(tp, model.StructOrUnion) and tp.partial:
  294. # use the function()'s sizes and offsets to guide the
  295. # layout of the struct
  296. totalsize = layout[0]
  297. totalalignment = layout[1]
  298. fieldofs = layout[2::2]
  299. fieldsize = layout[3::2]
  300. tp.force_flatten()
  301. assert len(fieldofs) == len(fieldsize) == len(tp.fldnames)
  302. tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment
  303. else:
  304. cname = ('%s %s' % (prefix, name)).strip()
  305. self._struct_pending_verification[tp] = layout, cname
  306. def _loaded_struct_or_union(self, tp):
  307. if tp.fldnames is None:
  308. return # nothing to do with opaque structs
  309. self.ffi._get_cached_btype(tp) # force 'fixedlayout' to be considered
  310. if tp in self._struct_pending_verification:
  311. # check that the layout sizes and offsets match the real ones
  312. def check(realvalue, expectedvalue, msg):
  313. if realvalue != expectedvalue:
  314. raise VerificationError(
  315. "%s (we have %d, but C compiler says %d)"
  316. % (msg, expectedvalue, realvalue))
  317. ffi = self.ffi
  318. BStruct = ffi._get_cached_btype(tp)
  319. layout, cname = self._struct_pending_verification.pop(tp)
  320. check(layout[0], ffi.sizeof(BStruct), "wrong total size")
  321. check(layout[1], ffi.alignof(BStruct), "wrong total alignment")
  322. i = 2
  323. for fname, ftype, fbitsize, fqual in tp.enumfields():
  324. if fbitsize >= 0:
  325. continue # xxx ignore fbitsize for now
  326. check(layout[i], ffi.offsetof(BStruct, fname),
  327. "wrong offset for field %r" % (fname,))
  328. if layout[i+1] != 0:
  329. BField = ffi._get_cached_btype(ftype)
  330. check(layout[i+1], ffi.sizeof(BField),
  331. "wrong size for field %r" % (fname,))
  332. i += 2
  333. assert i == len(layout)
  334. # ----------
  335. # 'anonymous' declarations. These are produced for anonymous structs
  336. # or unions; the 'name' is obtained by a typedef.
  337. def _generate_gen_anonymous_decl(self, tp, name):
  338. if isinstance(tp, model.EnumType):
  339. self._generate_gen_enum_decl(tp, name, '')
  340. else:
  341. self._generate_struct_or_union_decl(tp, '', name)
  342. def _loading_gen_anonymous(self, tp, name, module):
  343. if isinstance(tp, model.EnumType):
  344. self._loading_gen_enum(tp, name, module, '')
  345. else:
  346. self._loading_struct_or_union(tp, '', name, module)
  347. def _loaded_gen_anonymous(self, tp, name, module, **kwds):
  348. if isinstance(tp, model.EnumType):
  349. self._loaded_gen_enum(tp, name, module, **kwds)
  350. else:
  351. self._loaded_struct_or_union(tp)
  352. # ----------
  353. # constants, likely declared with '#define'
  354. def _generate_gen_const(self, is_int, name, tp=None, category='const',
  355. check_value=None):
  356. prnt = self._prnt
  357. funcname = '_cffi_%s_%s' % (category, name)
  358. self.export_symbols.append(funcname)
  359. if check_value is not None:
  360. assert is_int
  361. assert category == 'const'
  362. prnt('int %s(char *out_error)' % funcname)
  363. prnt('{')
  364. self._check_int_constant_value(name, check_value)
  365. prnt(' return 0;')
  366. prnt('}')
  367. elif is_int:
  368. assert category == 'const'
  369. prnt('int %s(long long *out_value)' % funcname)
  370. prnt('{')
  371. prnt(' *out_value = (long long)(%s);' % (name,))
  372. prnt(' return (%s) <= 0;' % (name,))
  373. prnt('}')
  374. else:
  375. assert tp is not None
  376. assert check_value is None
  377. if category == 'var':
  378. ampersand = '&'
  379. else:
  380. ampersand = ''
  381. extra = ''
  382. if category == 'const' and isinstance(tp, model.StructOrUnion):
  383. extra = 'const *'
  384. ampersand = '&'
  385. prnt(tp.get_c_name(' %s%s(void)' % (extra, funcname), name))
  386. prnt('{')
  387. prnt(' return (%s%s);' % (ampersand, name))
  388. prnt('}')
  389. prnt()
  390. def _generate_gen_constant_decl(self, tp, name):
  391. is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type()
  392. self._generate_gen_const(is_int, name, tp)
  393. _loading_gen_constant = _loaded_noop
  394. def _load_constant(self, is_int, tp, name, module, check_value=None):
  395. funcname = '_cffi_const_%s' % name
  396. if check_value is not None:
  397. assert is_int
  398. self._load_known_int_constant(module, funcname)
  399. value = check_value
  400. elif is_int:
  401. BType = self.ffi._typeof_locked("long long*")[0]
  402. BFunc = self.ffi._typeof_locked("int(*)(long long*)")[0]
  403. function = module.load_function(BFunc, funcname)
  404. p = self.ffi.new(BType)
  405. negative = function(p)
  406. value = int(p[0])
  407. if value < 0 and not negative:
  408. BLongLong = self.ffi._typeof_locked("long long")[0]
  409. value += (1 << (8*self.ffi.sizeof(BLongLong)))
  410. else:
  411. assert check_value is None
  412. fntypeextra = '(*)(void)'
  413. if isinstance(tp, model.StructOrUnion):
  414. fntypeextra = '*' + fntypeextra
  415. BFunc = self.ffi._typeof_locked(tp.get_c_name(fntypeextra, name))[0]
  416. function = module.load_function(BFunc, funcname)
  417. value = function()
  418. if isinstance(tp, model.StructOrUnion):
  419. value = value[0]
  420. return value
  421. def _loaded_gen_constant(self, tp, name, module, library):
  422. is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type()
  423. value = self._load_constant(is_int, tp, name, module)
  424. setattr(library, name, value)
  425. type(library)._cffi_dir.append(name)
  426. # ----------
  427. # enums
  428. def _check_int_constant_value(self, name, value):
  429. prnt = self._prnt
  430. if value <= 0:
  431. prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % (
  432. name, name, value))
  433. else:
  434. prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % (
  435. name, name, value))
  436. prnt(' char buf[64];')
  437. prnt(' if ((%s) <= 0)' % name)
  438. prnt(' sprintf(buf, "%%ld", (long)(%s));' % name)
  439. prnt(' else')
  440. prnt(' sprintf(buf, "%%lu", (unsigned long)(%s));' %
  441. name)
  442. prnt(' sprintf(out_error, "%s has the real value %s, not %s",')
  443. prnt(' "%s", buf, "%d");' % (name[:100], value))
  444. prnt(' return -1;')
  445. prnt(' }')
  446. def _load_known_int_constant(self, module, funcname):
  447. BType = self.ffi._typeof_locked("char[]")[0]
  448. BFunc = self.ffi._typeof_locked("int(*)(char*)")[0]
  449. function = module.load_function(BFunc, funcname)
  450. p = self.ffi.new(BType, 256)
  451. if function(p) < 0:
  452. error = self.ffi.string(p)
  453. if sys.version_info >= (3,):
  454. error = str(error, 'utf-8')
  455. raise VerificationError(error)
  456. def _enum_funcname(self, prefix, name):
  457. # "$enum_$1" => "___D_enum____D_1"
  458. name = name.replace('$', '___D_')
  459. return '_cffi_e_%s_%s' % (prefix, name)
  460. def _generate_gen_enum_decl(self, tp, name, prefix='enum'):
  461. if tp.partial:
  462. for enumerator in tp.enumerators:
  463. self._generate_gen_const(True, enumerator)
  464. return
  465. #
  466. funcname = self._enum_funcname(prefix, name)
  467. self.export_symbols.append(funcname)
  468. prnt = self._prnt
  469. prnt('int %s(char *out_error)' % funcname)
  470. prnt('{')
  471. for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
  472. self._check_int_constant_value(enumerator, enumvalue)
  473. prnt(' return 0;')
  474. prnt('}')
  475. prnt()
  476. def _loading_gen_enum(self, tp, name, module, prefix='enum'):
  477. if tp.partial:
  478. enumvalues = [self._load_constant(True, tp, enumerator, module)
  479. for enumerator in tp.enumerators]
  480. tp.enumvalues = tuple(enumvalues)
  481. tp.partial_resolved = True
  482. else:
  483. funcname = self._enum_funcname(prefix, name)
  484. self._load_known_int_constant(module, funcname)
  485. def _loaded_gen_enum(self, tp, name, module, library):
  486. for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues):
  487. setattr(library, enumerator, enumvalue)
  488. type(library)._cffi_dir.append(enumerator)
  489. # ----------
  490. # macros: for now only for integers
  491. def _generate_gen_macro_decl(self, tp, name):
  492. if tp == '...':
  493. check_value = None
  494. else:
  495. check_value = tp # an integer
  496. self._generate_gen_const(True, name, check_value=check_value)
  497. _loading_gen_macro = _loaded_noop
  498. def _loaded_gen_macro(self, tp, name, module, library):
  499. if tp == '...':
  500. check_value = None
  501. else:
  502. check_value = tp # an integer
  503. value = self._load_constant(True, tp, name, module,
  504. check_value=check_value)
  505. setattr(library, name, value)
  506. type(library)._cffi_dir.append(name)
  507. # ----------
  508. # global variables
  509. def _generate_gen_variable_decl(self, tp, name):
  510. if isinstance(tp, model.ArrayType):
  511. if tp.length_is_unknown():
  512. prnt = self._prnt
  513. funcname = '_cffi_sizeof_%s' % (name,)
  514. self.export_symbols.append(funcname)
  515. prnt("size_t %s(void)" % funcname)
  516. prnt("{")
  517. prnt(" return sizeof(%s);" % (name,))
  518. prnt("}")
  519. tp_ptr = model.PointerType(tp.item)
  520. self._generate_gen_const(False, name, tp_ptr)
  521. else:
  522. tp_ptr = model.PointerType(tp)
  523. self._generate_gen_const(False, name, tp_ptr, category='var')
  524. _loading_gen_variable = _loaded_noop
  525. def _loaded_gen_variable(self, tp, name, module, library):
  526. if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the
  527. # sense that "a=..." is forbidden
  528. if tp.length_is_unknown():
  529. funcname = '_cffi_sizeof_%s' % (name,)
  530. BFunc = self.ffi._typeof_locked('size_t(*)(void)')[0]
  531. function = module.load_function(BFunc, funcname)
  532. size = function()
  533. BItemType = self.ffi._get_cached_btype(tp.item)
  534. length, rest = divmod(size, self.ffi.sizeof(BItemType))
  535. if rest != 0:
  536. raise VerificationError(
  537. "bad size: %r does not seem to be an array of %s" %
  538. (name, tp.item))
  539. tp = tp.resolve_length(length)
  540. tp_ptr = model.PointerType(tp.item)
  541. value = self._load_constant(False, tp_ptr, name, module)
  542. # 'value' is a <cdata 'type *'> which we have to replace with
  543. # a <cdata 'type[N]'> if the N is actually known
  544. if tp.length is not None:
  545. BArray = self.ffi._get_cached_btype(tp)
  546. value = self.ffi.cast(BArray, value)
  547. setattr(library, name, value)
  548. type(library)._cffi_dir.append(name)
  549. return
  550. # remove ptr=<cdata 'int *'> from the library instance, and replace
  551. # it by a property on the class, which reads/writes into ptr[0].
  552. funcname = '_cffi_var_%s' % name
  553. BFunc = self.ffi._typeof_locked(tp.get_c_name('*(*)(void)', name))[0]
  554. function = module.load_function(BFunc, funcname)
  555. ptr = function()
  556. def getter(library):
  557. return ptr[0]
  558. def setter(library, value):
  559. ptr[0] = value
  560. setattr(type(library), name, property(getter, setter))
  561. type(library)._cffi_dir.append(name)
  562. cffimod_header = r'''
  563. #include <stdio.h>
  564. #include <stddef.h>
  565. #include <stdarg.h>
  566. #include <errno.h>
  567. #include <sys/types.h> /* XXX for ssize_t on some platforms */
  568. /* this block of #ifs should be kept exactly identical between
  569. c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py
  570. and cffi/_cffi_include.h */
  571. #if defined(_MSC_VER)
  572. # include <malloc.h> /* for alloca() */
  573. # if _MSC_VER < 1600 /* MSVC < 2010 */
  574. typedef __int8 int8_t;
  575. typedef __int16 int16_t;
  576. typedef __int32 int32_t;
  577. typedef __int64 int64_t;
  578. typedef unsigned __int8 uint8_t;
  579. typedef unsigned __int16 uint16_t;
  580. typedef unsigned __int32 uint32_t;
  581. typedef unsigned __int64 uint64_t;
  582. typedef __int8 int_least8_t;
  583. typedef __int16 int_least16_t;
  584. typedef __int32 int_least32_t;
  585. typedef __int64 int_least64_t;
  586. typedef unsigned __int8 uint_least8_t;
  587. typedef unsigned __int16 uint_least16_t;
  588. typedef unsigned __int32 uint_least32_t;
  589. typedef unsigned __int64 uint_least64_t;
  590. typedef __int8 int_fast8_t;
  591. typedef __int16 int_fast16_t;
  592. typedef __int32 int_fast32_t;
  593. typedef __int64 int_fast64_t;
  594. typedef unsigned __int8 uint_fast8_t;
  595. typedef unsigned __int16 uint_fast16_t;
  596. typedef unsigned __int32 uint_fast32_t;
  597. typedef unsigned __int64 uint_fast64_t;
  598. typedef __int64 intmax_t;
  599. typedef unsigned __int64 uintmax_t;
  600. # else
  601. # include <stdint.h>
  602. # endif
  603. # if _MSC_VER < 1800 /* MSVC < 2013 */
  604. # ifndef __cplusplus
  605. typedef unsigned char _Bool;
  606. # endif
  607. # endif
  608. #else
  609. # include <stdint.h>
  610. # if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux)
  611. # include <alloca.h>
  612. # endif
  613. #endif
  614. '''