Fixed segfault caused by variadic function py_callback.

parent 9c01c2ce
#@+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": ...@@ -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": ...@@ -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": ...@@ -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): int nargs, ...):
#cdef int *pargs
#pargs = <int *>(&args) 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: #if parser.verbose:
print 'py_callback: called with nargs=%d' % nargs # print 'py_callback: called with nargs=%d' % nargs
try: try:
names = PyList_New(0) names = PyList_New(nargs)
values = PyList_New(0) 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]) for i in range(nargs):
# Py_INCREF(termname) termname = <char*>va_arg(ap, str_type)
# print 'termname:', termname Py_INCREF(termname)
# PyList_SetItem(names, i, termname) PyList_SetItem(names, i, termname)
# val = <void *>(pargs[i*2+1]) val = <void *>va_arg(ap, void_type)
# valobj = <object>val valobj = <object>val
# Py_INCREF(valobj) Py_INCREF(valobj)
# print 'valobj:', valobj PyList_SetItem(values, i, valobj)
# PyList_SetItem(values, i, valobj)
if parser.verbose: #if parser.verbose:
print 'py_callback: calling handler for target "%s"' % target # print 'py_callback: calling handler:', \
print 'py_callback: with args:', (target, option, names, values) # (target, option, names, values)
res = parser._handle(target, option, names, values) res = parser._handle(target, option, names, values)
if parser.verbose: #if parser.verbose:
print 'py_callback: handler returned:', res # print 'py_callback: handler returned:', res
return 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): ...@@ -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 Wraps the interface to the binary bison/lex-generated parser engine dynamic
parser engine dynamic library. 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: ...@@ -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 In the course of initialisation, we check the library against the
against the parser object's rules. If the lib doesn't parser object's rules. If the lib doesn't exist, or can't be loaded, or
exist, or can't be loaded, or doesn't match, we build doesn't match, we build a new library.
a new library.
Either way, we end up with a binary parser engine which matches the
Either way, we end up with a binary parser engine which current rules in the parser object.
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. Tests if library exists and is current. If not, builds a fresh one.
If not, builds a fresh one
Opens the library and imports the parser entry point.
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: ...@@ -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, Loads the parser engine's dynamic library, and extracts the following
and extracts the following symbols: 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: ...@@ -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,
......
...@@ -243,7 +243,7 @@ class BisonParser(object): ...@@ -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): ...@@ -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:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment