Просмотр исходного кода

Fixed segfault caused by variadic function py_callback.

Sander Mathijs van Veen 14 лет назад
Родитель
Сommit
f9a34e5ef4
2 измененных файлов с 79 добавлено и 94 удалено
  1. 78 92
      src/pyrex/bison_.pyx
  2. 1 2
      src/python/bison.py

+ 78 - 92
src/pyrex/bison_.pyx

@@ -1,10 +1,7 @@
-#@+leo-ver=4
-#@+node:@file src/pyrex/bison_.pyx
 """
 """
 Pyrex-generated portion of pybison
 Pyrex-generated portion of pybison
 """
 """
-#@+others
-#@+node:python
+
 cdef extern from "Python.h":
 cdef extern from "Python.h":
     object PyString_FromStringAndSize(char *, int)
     object PyString_FromStringAndSize(char *, int)
     object PyString_FromString(char *)
     object PyString_FromString(char *)
@@ -25,8 +22,6 @@ cdef extern from "Python.h":
     object PyObject_CallObject(object callable_object, object args)
     object PyObject_CallObject(object callable_object, object args)
     int PyObject_SetAttrString(object o, char *attr_name, object v)
     int PyObject_SetAttrString(object o, char *attr_name, object v)
 
 
-#@-node:python
-#@+node:libdl
 # use libdl for now - easy and simple - maybe switch to
 # use libdl for now - easy and simple - maybe switch to
 # glib or libtool if a keen windows dev sends in a patch
 # glib or libtool if a keen windows dev sends in a patch
 
 
@@ -43,18 +38,12 @@ cdef extern from "Python.h":
 #        RTLD_NOLOAD
 #        RTLD_NOLOAD
 #        RTLD_GLOBAL
 #        RTLD_GLOBAL
 
 
-
-#@-node:libdl
-#@+node:stdio.h
 cdef extern from "stdio.h":
 cdef extern from "stdio.h":
     int printf(char *format,...)
     int printf(char *format,...)
 
 
-#@-node:stdio.h
-#@+node:string.h
 cdef extern from "string.h":
 cdef extern from "string.h":
     void *memcpy(void *dest, void *src, long n)
     void *memcpy(void *dest, void *src, long n)
-#@-node:string.h
-#@+node:bisondynlib.h
+
 cdef extern from "../c/bisondynlib.h":
 cdef extern from "../c/bisondynlib.h":
     void *bisondynlib_open(char *filename)
     void *bisondynlib_open(char *filename)
     int bisondynlib_close(void *handle)
     int bisondynlib_close(void *handle)
@@ -65,62 +54,74 @@ cdef extern from "../c/bisondynlib.h":
 
 
     #int bisondynlib_build(char *libName, char *includedir)
     #int bisondynlib_build(char *libName, char *includedir)
 
 
+cdef extern from "stdarg.h":
+    ctypedef struct va_list:
+        pass
+    ctypedef struct fake_type:
+        pass
+    void va_start(va_list, void* arg)
+    void* va_arg(va_list, fake_type)
+    void va_end(va_list)
+    fake_type void_type "void *"
+    fake_type str_type "char *"
 
 
-#@-node:bisondynlib.h
-#@+node:py_callback
 # Callback function which is invoked by target handlers
 # Callback function which is invoked by target handlers
 # within the C yyparse() function.
 # within the C yyparse() function.
 
 
 cdef public object py_callback(object parser, char *target, int option, \
 cdef public object py_callback(object parser, char *target, int option, \
-        int nargs, void *args):
-    #cdef int *pargs
-    #pargs = <int *>(&args)
+        int nargs, ...):
+
+    cdef int i
+    cdef va_list ap
+    va_start(ap, <void*>nargs)
+
     cdef void *objptr
     cdef void *objptr
     cdef object obj
     cdef object obj
-    cdef int i
     cdef object valobj
     cdef object valobj
     cdef void *val
     cdef void *val
     cdef char *tokval
     cdef char *tokval
+    cdef char *termname
 
 
-    if parser.verbose:
-        print 'py_callback: called with nargs=%d' % nargs
+    #if parser.verbose:
+    #    print 'py_callback: called with nargs=%d' % nargs
 
 
     try:
     try:
-        names = PyList_New(0)
-        values = PyList_New(0)
-        #names = PyList_New(nargs)
-        #values = PyList_New(nargs)
+        names = PyList_New(nargs)
+        values = PyList_New(nargs)
+
+        Py_INCREF(names)
+        Py_INCREF(values)
 
 
         #for i in range(nargs):
         #for i in range(nargs):
-        #    print 'i:', i
+        #    print 'i=%d' % i , <char*>va_arg(ap, str_type), \
+        #                       hex(<int>va_arg(ap, str_type))
 
 
-        #    termname = <char *>(pargs[i*2])
-        #    Py_INCREF(termname)
-        #    print 'termname:', termname
-        #    PyList_SetItem(names, i, termname)
+        for i in range(nargs):
+            termname = <char*>va_arg(ap, str_type)
+            Py_INCREF(termname)
+            PyList_SetItem(names, i, termname)
 
 
-        #    val = <void *>(pargs[i*2+1])
-        #    valobj = <object>val
-        #    Py_INCREF(valobj)
-        #    print 'valobj:', valobj
-        #    PyList_SetItem(values, i, valobj)
+            val = <void *>va_arg(ap, void_type)
+            valobj = <object>val
+            Py_INCREF(valobj)
+            PyList_SetItem(values, i, valobj)
 
 
-        if parser.verbose:
-            print 'py_callback: calling handler for target "%s"' % target
-            print 'py_callback: with args:', (target, option, names, values)
+        #if parser.verbose:
+        #    print 'py_callback: calling handler:', \
+        #          (target, option, names, values)
 
 
         res = parser._handle(target, option, names, values)
         res = parser._handle(target, option, names, values)
 
 
-        if parser.verbose:
-            print 'py_callback: handler returned:', res
-
-        return res
+        #if parser.verbose:
+        #    print 'py_callback: handler returned:', res
     except:
     except:
         traceback.print_exc()
         traceback.print_exc()
-        return None
+        res = None
+
+    va_end(ap)
+
+    return res
 
 
-#@-node:py_callback
-#@+node:py_input
 # callback routine for reading input
 # callback routine for reading input
 cdef public void py_input(object parser, char *buf, int *result, int max_size):
 cdef public void py_input(object parser, char *buf, int *result, int max_size):
     cdef char *buf1
     cdef char *buf1
@@ -138,28 +139,22 @@ cdef public void py_input(object parser, char *buf, int *result, int max_size):
         print "\npy_input: got %s bytes" % buflen
         print "\npy_input: got %s bytes" % buflen
 
 
 
 
-#@-node:py_input
-#@+node:Python imports
 import sys, os, sha, re, imp, traceback
 import sys, os, sha, re, imp, traceback
 import shutil
 import shutil
 import distutils.sysconfig
 import distutils.sysconfig
 import distutils.ccompiler
 import distutils.ccompiler
 
 
 
 
-#@-node:Python imports
-#@+node:Python Globals
 reSpaces = re.compile("\\s+")
 reSpaces = re.compile("\\s+")
 
 
 #unquoted = r"""^|[^'"]%s[^'"]?"""
 #unquoted = r"""^|[^'"]%s[^'"]?"""
 unquoted = "[^'\"]%s[^'\"]?"
 unquoted = "[^'\"]%s[^'\"]?"
 
 
-#@-node:Python Globals
-#@+node:cdef class ParserEngine
 cdef class ParserEngine:
 cdef class ParserEngine:
     """
     """
-    Wraps the interface to the binary bison/lex-generated
-    parser engine dynamic library.
-    
+    Wraps the interface to the binary bison/lex-generated parser engine dynamic
+    library.
+
     You shouldn't need to deal with this at all.
     You shouldn't need to deal with this at all.
 
 
     Takes care of:
     Takes care of:
@@ -171,61 +166,53 @@ cdef class ParserEngine:
     Makes direct calls to the platform-dependent routines in 
     Makes direct calls to the platform-dependent routines in 
     bisondynlib-[linux|windows].c
     bisondynlib-[linux|windows].c
     """
     """
-    #@    @+others
-    #@+node:C attribs
     cdef object parser
     cdef object parser
     cdef object parserHash # hash of current python parser object
     cdef object parserHash # hash of current python parser object
     cdef object libFilename_py
     cdef object libFilename_py
-    
+
     cdef void *libHandle
     cdef void *libHandle
-    
+
     # rules hash str embedded in bison parser lib
     # rules hash str embedded in bison parser lib
     cdef char *libHash
     cdef char *libHash
-    
-    #@-node:C attribs
-    #@+node:__init__
+
     def __init__(self, parser, **kw):
     def __init__(self, parser, **kw):
         """
         """
-        Creates a ParserEngine wrapper, and builds/loads the library
-        
+        Creates a ParserEngine wrapper, and builds/loads the library.
+
         Arguments:
         Arguments:
             - parser - an instance of a subclass of Parser
             - parser - an instance of a subclass of Parser
-    
-        In the course of initialisation, we check the library
-        against the parser object's rules. If the lib doesn't
-        exist, or can't be loaded, or doesn't match, we build
-        a new library.
-        
-        Either way, we end up with a binary parser engine which
-        matches the current rules in the parser object
+
+        In the course of initialisation, we check the library against the
+        parser object's rules. If the lib doesn't exist, or can't be loaded, or
+        doesn't match, we build a new library.
+
+        Either way, we end up with a binary parser engine which matches the
+        current rules in the parser object.
         """
         """
         self.parser = parser
         self.parser = parser
-        
+
         self.libFilename_py = parser.buildDirectory \
         self.libFilename_py = parser.buildDirectory \
                               + parser.bisonEngineLibName \
                               + parser.bisonEngineLibName \
                               + imp.get_suffixes()[0][0]
                               + imp.get_suffixes()[0][0]
-    
+
         self.parserHash = hashParserObject(self.parser)
         self.parserHash = hashParserObject(self.parser)
-    
+
         self.openCurrentLib()
         self.openCurrentLib()
-    
-    #@-node:__init__
-    #@+node:openCurrentLib
+
     def openCurrentLib(self):
     def openCurrentLib(self):
         """
         """
-        Tests if library exists and is current.
-        If not, builds a fresh one
-        
-        Opens the library and imports the parser entry point
+        Tests if library exists and is current. If not, builds a fresh one.
+
+        Opens the library and imports the parser entry point.
         """
         """
         parser = self.parser
         parser = self.parser
         verbose = parser.verbose
         verbose = parser.verbose
-    
+
         if not os.path.isfile(self.libFilename_py):
         if not os.path.isfile(self.libFilename_py):
             self.buildLib()
             self.buildLib()
-        
+
         self.openLib()
         self.openLib()
-    
+
         # hash our parser spec, compare to hash val stored in lib
         # hash our parser spec, compare to hash val stored in lib
         libHash = PyString_FromString(self.libHash)
         libHash = PyString_FromString(self.libHash)
         if self.parserHash != libHash:
         if self.parserHash != libHash:
@@ -239,19 +226,18 @@ cdef class ParserEngine:
         else:
         else:
             if verbose:
             if verbose:
                 print "Hashes match, no need to rebuild bison engine lib"
                 print "Hashes match, no need to rebuild bison engine lib"
-    #@-node:openCurrentLib
-    #@+node:openLib
+
     def openLib(self):
     def openLib(self):
         """
         """
-        Loads the parser engine's dynamic library,
-        and extracts the following symbols:
-    
+        Loads the parser engine's dynamic library, and extracts the following
+        symbols:
+
             - void *do_parse() (runs parser)
             - void *do_parse() (runs parser)
             - char *parserHash (contains hash of python parser rules)
             - char *parserHash (contains hash of python parser rules)
-    
+
         Returns lib handle, plus pointer to do_parse() function, as long ints
         Returns lib handle, plus pointer to do_parse() function, as long ints
         (which later need to be cast to pointers)
         (which later need to be cast to pointers)
-    
+
         Important note -this is totally linux-specific.
         Important note -this is totally linux-specific.
         If you want windows support, you'll have to modify these funcs to
         If you want windows support, you'll have to modify these funcs to
         use glib instead (or create windows equivalents), in which case I'd
         use glib instead (or create windows equivalents), in which case I'd
@@ -341,7 +327,7 @@ cdef class ParserEngine:
             "extern char *yytext;",
             "extern char *yytext;",
             "#define YYSTYPE void*",
             "#define YYSTYPE void*",
             #'extern void *py_callback(void *, char *, int, void*, ...);',
             #'extern void *py_callback(void *, char *, int, void*, ...);',
-            'void *(*py_callback)(void *, char *, int, int, void *, ...);',
+            'void *(*py_callback)(void *, char *, int, int, ...);',
             'void (*py_input)(void *, char *, int *, int);',
             'void (*py_input)(void *, char *, int *, int);',
             'void *py_parser;',
             'void *py_parser;',
             'char *rules_hash = "%s";' % self.parserHash,
             'char *rules_hash = "%s";' % self.parserHash,

+ 1 - 2
src/python/bison.py

@@ -243,7 +243,7 @@ class BisonParser(object):
     flexCFile1 = "tmp.lex.c" # c output file from lex gets renamed to this
     flexCFile1 = "tmp.lex.c" # c output file from lex gets renamed to this
 
 
     cflags_pre = ['-fPIC']  # = CFLAGS added before all arguments.
     cflags_pre = ['-fPIC']  # = CFLAGS added before all arguments.
-    cflags_post = ['-O0','-g']  # = CFLAGS added after all arguments.
+    cflags_post = ['-O3','-g']  # = CFLAGS added after all arguments.
 
 
     buildDirectory = './' # Directory used to store the generated / compiled files.
     buildDirectory = './' # Directory used to store the generated / compiled files.
     debugSymbols = 1  # Add debugging symbols to the binary files.
     debugSymbols = 1  # Add debugging symbols to the binary files.
@@ -338,7 +338,6 @@ class BisonParser(object):
                 print '_handle: invoking handler at line %s for "%s"' \
                 print '_handle: invoking handler at line %s for "%s"' \
                       % (hdlrline, targetname)
                       % (hdlrline, targetname)
 
 
-            print handler
             self.last = handler(target=targetname, option=option, names=names,
             self.last = handler(target=targetname, option=option, names=names,
                                 values=values)
                                 values=values)
             #if self.verbose:
             #if self.verbose: