Author: Armin Rigo <[email protected]>
Branch: cffi-1.0
Changeset: r1832:fd16324ee375
Date: 2015-04-26 10:46 +0200
http://bitbucket.org/cffi/cffi/changeset/fd16324ee375/
Log: Array lengths given directly by constants
diff --git a/_cffi1/parse_c_type.c b/_cffi1/parse_c_type.c
--- a/_cffi1/parse_c_type.c
+++ b/_cffi1/parse_c_type.c
@@ -203,6 +203,8 @@
return index;
}
+#define MAX_SSIZE_T (((size_t)-1) >> 1)
+
static int parse_complete(token_t *tok);
static int parse_sequel(token_t *tok, int outer)
@@ -329,17 +331,44 @@
next_token(tok);
if (tok->kind != TOK_CLOSE_BRACKET) {
size_t length;
+ int gindex;
- if (tok->kind != TOK_INTEGER)
+ switch (tok->kind) {
+
+ case TOK_INTEGER:
+ errno = 0;
+ if (sizeof(length) > sizeof(unsigned long))
+ length = strtoull(tok->p, NULL, 10);
+ else
+ length = strtoul(tok->p, NULL, 10);
+ if (errno == ERANGE || length > MAX_SSIZE_T)
+ return parse_error(tok, "number too large");
+ break;
+
+ case TOK_IDENTIFIER:
+ gindex = search_in_globals(tok->info->ctx, tok->p, tok->size);
+ if (gindex >= 0) {
+ const struct _cffi_global_s *g;
+ g = &tok->info->ctx->globals[gindex];
+ if (_CFFI_GETOP(g->type_op) == _CFFI_OP_CONSTANT_INT ||
+ _CFFI_GETOP(g->type_op) == _CFFI_OP_ENUM) {
+ unsigned long long value;
+ int neg = ((int(*)(unsigned long long*))g->address)
+ (&value);
+ if (!neg && value > MAX_SSIZE_T)
+ return parse_error(tok,
+ "integer constant too large");
+ if (!neg || value == 0) {
+ length = (size_t)value;
+ break;
+ }
+ }
+ }
+ /* fall-through to the default case */
+ default:
return parse_error(tok, "expected a positive integer
constant");
+ }
- errno = 0;
- if (sizeof(length) > sizeof(unsigned long))
- length = strtoull(tok->p, NULL, 10);
- else
- length = strtoul(tok->p, NULL, 10);
- if (errno == ERANGE || ((ssize_t)length) < 0)
- return parse_error(tok, "number too large");
next_token(tok);
write_ds(tok, _CFFI_OP(_CFFI_OP_ARRAY, 0));
diff --git a/_cffi1/realize_c_type.c b/_cffi1/realize_c_type.c
--- a/_cffi1/realize_c_type.c
+++ b/_cffi1/realize_c_type.c
@@ -219,6 +219,8 @@
{
PyObject *x;
unsigned long long value;
+ /* note: we cast g->address to this function type; we do the same
+ in parse_c_type:parse_sequel() too */
int neg = ((int(*)(unsigned long long*))g->address)(&value);
if (!neg) {
if (value <= (unsigned long long)LONG_MAX)
diff --git a/_cffi1/test_parse_c_type.py b/_cffi1/test_parse_c_type.py
--- a/_cffi1/test_parse_c_type.py
+++ b/_cffi1/test_parse_c_type.py
@@ -1,7 +1,6 @@
-import re
-import os
-import py
+import sys, re, os, py
import cffi
+from . import cffi_opcode
r_macro = re.compile(r"#define \w+[(][^\n]*|#include [^\n]*")
r_define = re.compile(r"(#define \w+) [^\n]*")
@@ -29,6 +28,9 @@
identifier_names = ["id", "id0", "id05", "id05b", "tail"]
assert identifier_names == sorted(identifier_names)
+global_names = ["FIVE", "NEG", "ZERO"]
+assert global_names == sorted(global_names)
+
ctx = ffi.new("struct _cffi_type_context_s *")
c_struct_names = [ffi.new("char[]", _n) for _n in struct_names]
ctx_structs = ffi.new("struct _cffi_struct_union_s[]", len(struct_names))
@@ -53,6 +55,32 @@
ctx.typenames = ctx_identifiers
ctx.num_typenames = len(identifier_names)
[email protected]("int(unsigned long long *)")
+def fetch_constant_five(p):
+ p[0] = 5
+ return 0
[email protected]("int(unsigned long long *)")
+def fetch_constant_zero(p):
+ p[0] = 0
+ return 1
[email protected]("int(unsigned long long *)")
+def fetch_constant_neg(p):
+ p[0] = 123321
+ return 1
+
+ctx_globals = ffi.new("struct _cffi_global_s[]", len(global_names))
+c_glob_names = [ffi.new("char[]", _n) for _n in global_names]
+for _i, _fn in enumerate([fetch_constant_five,
+ fetch_constant_neg,
+ fetch_constant_zero]):
+ ctx_globals[_i].name = c_glob_names[_i]
+ ctx_globals[_i].address = _fn
+ ctx_globals[_i].type_op = ffi.cast("_cffi_opcode_t",
+ cffi_opcode.OP_CONSTANT_INT if _i != 1
+ else cffi_opcode.OP_ENUM)
+ctx.globals = ctx_globals
+ctx.num_globals = len(global_names)
+
def parse(input):
out = ffi.new("_cffi_opcode_t[]", 100)
@@ -243,6 +271,12 @@
parse_error("int a(*)", "identifier expected", 6)
parse_error("int[123456789012345678901234567890]", "number too large", 4)
+def test_number_too_large():
+ num_max = sys.maxsize
+ assert parse("char[%d]" % num_max) == [Prim(lib._CFFI_PRIM_CHAR),
+ '->', Array(0), num_max]
+ parse_error("char[%d]" % (num_max + 1), "number too large", 5)
+
def test_complexity_limit():
parse_error("int" + "[]" * 2500, "internal type complexity limit reached",
202)
@@ -270,9 +304,15 @@
'->', Pointer(0)]
def test_cffi_opcode_sync():
- import cffi_opcode, cffi.model
+ import cffi.model
for name in dir(lib):
if name.startswith('_CFFI_'):
assert getattr(cffi_opcode, name[6:]) == getattr(lib, name)
assert sorted(cffi_opcode.PRIMITIVE_TO_INDEX.keys()) == (
sorted(cffi.model.PrimitiveType.ALL_PRIMITIVE_TYPES.keys()))
+
+def test_array_length_from_constant():
+ parse_error("int[UNKNOWN]", "expected a positive integer constant", 4)
+ assert parse("int[FIVE]") == [Prim(lib._CFFI_PRIM_INT), '->', Array(0), 5]
+ assert parse("int[ZERO]") == [Prim(lib._CFFI_PRIM_INT), '->', Array(0), 0]
+ parse_error("int[NEG]", "expected a positive integer constant", 4)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit