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

Reply via email to