Peter Wu
2014-Aug-04 08:47 UTC
[Libguestfs] [hivex] Segfault for an integer value to node_set_value
Hi, When an integer argument is passed as value, node_set_value segfaults. Reproducer is at the end of this message The backtrace points at hivex-py.c, function get_value. While obj is non-NULL, `bytes = PyUnicode_AsUTF8String (obj);` returns NULL. Kind regards, Peter https://lekensteyn.nl #!/usr/bin/env python3 import hivex, sys h = hivex.Hivex(sys.argv[1]) print(h) val = { 'key': 'broken', 't': 4, 'value': 1234 } print(val) r = h.node_set_value(h.root(), val) print(r)
Hilko Bengen
2014-Aug-05 18:58 UTC
Re: [Libguestfs] [hivex] Segfault for an integer value to node_set_value
* Peter Wu:> When an integer argument is passed as value, node_set_value > segfaults. Reproducer is at the end of this messageUh-oh. It looks like the handling of values is broken for non-string cases. bytes = PyUnicode_AsUTF8String (obj); with obj derived from the numeric 1234 causes bytes to be set to null. A line of error handling code tells us why: TypeError: bad argument type for built-in operation For Python2, ret->len is set to a value that is too large for size_t, and thus malloc(), so Python crashes with... RuntimeError: Cannot allocate memory I am looking at fixing this. Cheers, -Hilko
Peter Wu
2014-Aug-05 19:40 UTC
Re: [Libguestfs] [hivex] Segfault for an integer value to node_set_value
It is even worse, in py2, strings are bytes. In py 3, strings are Unicode. Result: I have now corrupted the registry since I tried to write hex 31 for a dword (instead of a 32-bit into). There is also an invalid reg_sz which should be utf16 instead of the gibberish that is now contained in it. I have not checked with py2, but does it require bytes ("str") or can you also pass an int? Is the type t used? (It probably should) Kind regards, Peter https://lekensteyn.nl (pardon my brevity, top-posting and formatting, sent from my phone) On August 5, 2014 8:58:06 PM CEST, Hilko Bengen <bengen@hilluzination.de> wrote:>* Peter Wu: > >> When an integer argument is passed as value, node_set_value >> segfaults. Reproducer is at the end of this message > >Uh-oh. It looks like the handling of values is broken for non-string >cases. > > bytes = PyUnicode_AsUTF8String (obj); > >with obj derived from the numeric 1234 causes bytes to be set to null. >A line of error handling code tells us why: > > TypeError: bad argument type for built-in operation > >For Python2, ret->len is set to a value that is too large for size_t, >and thus malloc(), so Python crashes with... > > RuntimeError: Cannot allocate memory > >I am looking at fixing this. > >Cheers, >-Hilko
Hilko Bengen
2014-Aug-05 20:35 UTC
[Libguestfs] [hivex] python: Check type of variable passed into set_value.
The following code, reported by Peter Wu <peter@lekensteyn.nl>, broke on x86_64 with different symptoms on Python2 and Python3 (malloc() failure and segmentation fault, respectively): r = h.node_set_value(h.root(), { 'key': 'broken', 't': 4, 'value': 1234 }) --- generator/generator.ml | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/generator/generator.ml b/generator/generator.ml index bcf1966..0fa5c04 100755 --- a/generator/generator.ml +++ b/generator/generator.ml @@ -2799,6 +2799,7 @@ typedef int Py_ssize_t; #include <stdio.h> #include <stdlib.h> #include <assert.h> +#include <inttypes.h> #include \"hivex.h\" @@ -2868,14 +2869,28 @@ get_value (PyObject *v, hive_set_value *ret) PyErr_SetString (PyExc_RuntimeError, \"no 'value' element in dictionary\"); return -1; } + if (PyInt_Check (obj)) { + uint32_t* v = malloc (sizeof (uint32_t)); + *v = PyInt_AsLong (obj); + ret->value = (char*) v; + ret->len = sizeof (uint32_t); #ifdef HAVE_PYSTRING_ASSTRING - ret->value = PyString_AsString (obj); - ret->len = PyString_Size (obj); + } else if (PyString_Check (obj)) { + ret->value = PyString_AsString (obj); + ret->len = PyString_Size (obj); #else - bytes = PyUnicode_AsUTF8String (obj); - ret->value = PyBytes_AS_STRING (bytes); - ret->len = PyBytes_GET_SIZE (bytes); + } else if (PyUnicode_Check (obj)) { + bytes = PyUnicode_AsUTF8String (obj); + if (!bytes) { + return -1; + } + ret->value = PyBytes_AS_STRING (bytes); + ret->len = PyBytes_GET_SIZE (bytes); #endif + } else { + PyErr_SetString (PyExc_RuntimeError, \"Cannot use 'value' element in dictionary\"); + return -1; + } return 0; } -- 2.0.1
Peter Wu
2014-Aug-08 18:39 UTC
[Libguestfs] [PATCH 0/2] Fix node_set_values[s] for Python 2/3
Hi, Here is a fix for the Python issue I encountered the other day. It adds more validation to the node_set_value wrapper and supports the following types on Python 2 and 3: Unicode strings, bytes and integers (for DWORD/QWORDs). The second patch is a trivial whitespace-only change. Peter Wu (2): Add type checking, support integers as value generator: Fix mixed tabs/spaces configure.ac | 4 - generator/generator.ml | 612 ++++++++++++++++++++++------------------- python/t/300-setvalue-types.py | 76 +++++ 3 files changed, 410 insertions(+), 282 deletions(-) create mode 100644 python/t/300-setvalue-types.py -- 2.0.2
Peter Wu
2014-Aug-08 18:39 UTC
[Libguestfs] [PATCH 1/2] Add type checking, support integers as value
Before this patch, Python would segfault once you pass a non-string key or value to node_set_value. It was also not possible to set bytes on Python 3 as Unicode was assumed (Python 2 was not affected by this). This patch fixes recognition of bytes for Python 3, but in addition it recognizes ints (includes 'long' in Python 2) for DWORD (LE + BE) and QWORDs. For this purpose, a new field was added to the py_set_values struct (words) to simplify memory allocation (otherwise, malloc must be tracked somehow). In addition, more specific exception types have been chosen (TypeError instead of RuntimeError). A test is added to avoid future regressions. Note that this test will crash older versions of hivex. All tests pass with Python 2.7.5 + 3.3.2 (Fedora 20 x86_64), 2.7.8 + 3.4.1 (Arch Linux x86_64) and 2.6.5 (Ubuntu 10.04 i686). --- configure.ac | 4 -- generator/generator.ml | 112 ++++++++++++++++++++++++++++++----------- python/t/300-setvalue-types.py | 76 ++++++++++++++++++++++++++++ 3 files changed, 160 insertions(+), 32 deletions(-) create mode 100644 python/t/300-setvalue-types.py diff --git a/configure.ac b/configure.ac index f50daff..4566a32 100644 --- a/configure.ac +++ b/configure.ac @@ -345,10 +345,6 @@ AS_IF([test "x$enable_python" != "xno"], [AC_DEFINE([HAVE_PYCAPSULE_NEW],1, [Found PyCapsule_New in libpython])], [],[$PYTHON_BLDLIBRARY]) - AC_CHECK_LIB([c],[PyString_AsString], - [AC_DEFINE([HAVE_PYSTRING_ASSTRING],1, - [Found PyString_AsString in libpython])], - [],[$PYTHON_BLDLIBRARY]) LIBS="$old_LIBS" fi diff --git a/generator/generator.ml b/generator/generator.ml index bcf1966..0aeb24e 100755 --- a/generator/generator.ml +++ b/generator/generator.ml @@ -2837,45 +2837,90 @@ put_handle (hive_h *h) * not be freed. */ static int -get_value (PyObject *v, hive_set_value *ret) +get_value (PyObject *v, hive_set_value *ret, uint64_t *word) { PyObject *obj; -#ifndef HAVE_PYSTRING_ASSTRING PyObject *bytes; -#endif + + if (!PyDict_Check (v)) { + PyErr_SetString (PyExc_TypeError, \"expected dictionary type for value\"); + return -1; + } obj = PyDict_GetItemString (v, \"key\"); if (!obj) { - PyErr_SetString (PyExc_RuntimeError, \"no 'key' element in dictionary\"); + PyErr_SetString (PyExc_KeyError, \"no 'key' element in dictionary\"); + return -1; + } + if (PyUnicode_Check (obj)) { + bytes = PyUnicode_AsUTF8String (obj); + if (bytes == NULL) { + return -1; + } + } else if (PyBytes_Check (obj)) { + bytes = obj; + } else { + PyErr_SetString (PyExc_TypeError, \"expected bytes or str type for 'key'\"); return -1; } -#ifdef HAVE_PYSTRING_ASSTRING - ret->key = PyString_AsString (obj); -#else - bytes = PyUnicode_AsUTF8String (obj); ret->key = PyBytes_AS_STRING (bytes); -#endif obj = PyDict_GetItemString (v, \"t\"); if (!obj) { - PyErr_SetString (PyExc_RuntimeError, \"no 't' element in dictionary\"); + PyErr_SetString (PyExc_KeyError, \"no 't' element in dictionary\"); return -1; } ret->t = PyLong_AsLong (obj); + if (PyErr_Occurred ()) { + PyErr_SetString (PyExc_TypeError, \"expected int type for 't'\"); + return -1; + } obj = PyDict_GetItemString (v, \"value\"); if (!obj) { - PyErr_SetString (PyExc_RuntimeError, \"no 'value' element in dictionary\"); + PyErr_SetString (PyExc_KeyError, \"no 'value' element in dictionary\"); + return -1; + } + /* Support bytes and unicode strings. For DWORD and QWORD types, long and + * integers are also supported. Caller must ensure sanity of byte buffer + * lengths */ + if (PyUnicode_Check (obj)) { + bytes = PyUnicode_AsUTF8String (obj); + if (bytes == NULL) + return -1; + ret->len = PyBytes_GET_SIZE (bytes); + ret->value = PyBytes_AS_STRING (bytes); + } else if (PyBytes_Check (obj)) { + ret->len = PyBytes_GET_SIZE (obj); + ret->value = PyBytes_AS_STRING (obj); + } else if (ret->t == hive_t_REG_DWORD || + ret->t == hive_t_REG_DWORD_BIG_ENDIAN) { + uint32_t d = PyLong_AsLong (obj); + if (PyErr_Occurred ()) { + PyErr_SetString (PyExc_TypeError, \"expected int type for DWORD value\"); + return -1; + } + + ret->len = sizeof (d); + ret->value = (char *) word; + if (ret->t == hive_t_REG_DWORD) + *(uint32_t *) ret->value = htole32 (d); + else + *(uint32_t *) ret->value = htobe32 (d); + } else if (ret->t == hive_t_REG_QWORD) { + uint64_t l = PyLong_AsLongLong (obj); + if (PyErr_Occurred ()) { + PyErr_SetString (PyExc_TypeError, \"expected int type for QWORD value\"); + return -1; + } + + ret->len = sizeof (l); + ret->value = (char *) word; + *(uint64_t *) ret->value = htole64 (l); + } else { + PyErr_SetString (PyExc_TypeError, \"expected bytes or str type for 'value'\"); return -1; } -#ifdef HAVE_PYSTRING_ASSTRING - ret->value = PyString_AsString (obj); - ret->len = PyString_Size (obj); -#else - bytes = PyUnicode_AsUTF8String (obj); - ret->value = PyBytes_AS_STRING (bytes); - ret->len = PyBytes_GET_SIZE (bytes); -#endif return 0; } @@ -2883,6 +2928,7 @@ get_value (PyObject *v, hive_set_value *ret) typedef struct py_set_values { size_t nr_values; hive_set_value *values; + uint64_t *words; } py_set_values; static int @@ -2905,13 +2951,21 @@ get_values (PyObject *v, py_set_values *ret) ret->nr_values = len; ret->values = malloc (len * sizeof (hive_set_value)); if (!ret->values) { - PyErr_SetString (PyExc_RuntimeError, strerror (errno)); + PyErr_NoMemory (); + return -1; + } + /* if the value is a dword/qword, it will be stored here */ + ret->words = malloc (len * sizeof (uint64_t)); + if (!ret->words) { + free (ret->values); + PyErr_NoMemory (); return -1; } for (i = 0; i < len; ++i) { - if (get_value (PyList_GetItem (v, i), &(ret->values[i])) == -1) { + if (get_value (PyList_GetItem (v, i), &(ret->values[i]), &(ret->words[i])) == -1) { free (ret->values); + free (ret->words); return -1; } } @@ -3070,9 +3124,10 @@ put_val_type (char *val, size_t len, hive_type t) | ASetValues -> pr " py_set_values values;\n"; pr " PyObject *py_values;\n" - | ASetValue -> - pr " hive_set_value val;\n"; - pr " PyObject *py_val;\n" + | ASetValue -> + pr " hive_set_value val;\n"; + pr " PyObject *py_val;\n"; + pr " uint64_t word;" ) (snd style); pr "\n"; @@ -3136,8 +3191,8 @@ put_val_type (char *val, size_t len, hive_type t) | ASetValues -> pr " if (get_values (py_values, &values) == -1)\n"; pr " return NULL;\n" - | ASetValue -> - pr " if (get_value (py_val, &val) == -1)\n"; + | ASetValue -> + pr " if (get_value (py_val, &val, &word) == -1)\n"; pr " return NULL;\n" ) (snd style); @@ -3151,8 +3206,9 @@ put_val_type (char *val, size_t len, hive_type t) | AString _ | AStringNullable _ | AOpenFlags | AUnusedFlags -> () | ASetValues -> - pr " free (values.values);\n" - | ASetValue -> () + pr " free (values.values);\n"; + pr " free (values.words);\n" + | ASetValue -> () ) (snd style); (* Check for errors from C library. *) diff --git a/python/t/300-setvalue-types.py b/python/t/300-setvalue-types.py new file mode 100644 index 0000000..6d72a59 --- /dev/null +++ b/python/t/300-setvalue-types.py @@ -0,0 +1,76 @@ +# Test various possible types for assignment to setvalue +# Copyright (C) 2014 Peter Wu <peter@lekensteyn.nl> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +import hivex +import os +from sys import getrefcount + +srcdir = "." +if "srcdir" in os.environ and os.environ["srcdir"]: + srcdir = os.environ["srcdir"] + +h = hivex.Hivex ("%s/../images/minimal" % srcdir, + write = True) + +REG_SZ = 1 +REG_BINARY = 3 +REG_DWORD = 4 +REG_DWORD_BIG_ENDIAN = 5 +REG_QWORD = 11 + +def set_value (key="test key", t=REG_BINARY, value=b'Val'): + global h + h.node_set_value (h.root (), { + "key": key, + "t": t, + "value": value + }) + +def test_pass (t, value, exp_bytes): + global h + key = "test_key" + set_value (key, t, value) + val = h.node_get_value (h.root (), key) + ret_type, ret_value = h.value_value (val) + assert t == ret_type, \ + "expected type {0}, got {1}".format(t, ret_type) + assert exp_bytes == ret_value, \ + "expected value {0}, got {1}".format(exp_bytes, ret_value) + +def test_exception (exception_type, **kwargs): + try: + set_value (**kwargs) + raise AssertionError("expected {0}".format(exception_type)) + except exception_type: + pass + +# Good weather tests +test_pass (REG_BINARY, b"\x01\x02", b"\x01\x02") +test_pass (REG_SZ, u"Val", b"\x56\x61\x6c") +test_pass (REG_DWORD, 0xabcdef, b'\xef\xcd\xab\x00') +test_pass (REG_DWORD_BIG_ENDIAN, 0xabcdef, b'\x00\xab\xcd\xef') +test_pass (REG_QWORD, 0x0123456789abcdef, + b'\xef\xcd\xab\x89\x67\x45\x23\x01') + +# *WORDs must still accept bytes (the length is not checked) +test_pass (REG_DWORD, b'\xaa\xbb\xcc', b'\xaa\xbb\xcc') + +# Bad weather tests +test_exception (TypeError, key = 1) +test_exception (TypeError, t = "meh") +test_exception (TypeError, t = REG_SZ, value = 1) +test_exception (TypeError, t = REG_DWORD, value = None) -- 2.0.2
vim :set ts=8 :retab --- generator/generator.ml | 500 ++++++++++++++++++++++++------------------------- 1 file changed, 250 insertions(+), 250 deletions(-) diff --git a/generator/generator.ml b/generator/generator.ml index 0aeb24e..40c1981 100755 --- a/generator/generator.ml +++ b/generator/generator.ml @@ -1069,10 +1069,10 @@ here. Often it's not documented at all. pr "\n"; if List.mem AUnusedFlags (snd style) then - pr "The flags parameter is unused. Always pass 0.\n\n"; + pr "The flags parameter is unused. Always pass 0.\n\n"; if List.mem ASetValues (snd style) then - pr "C<values> is an array of (key, value) pairs. There + pr "C<values> is an array of (key, value) pairs. There should be C<nr_values> elements in this array. Any existing values stored at the node are discarded, and their @@ -1080,7 +1080,7 @@ C<hive_value_h> handles become invalid. Thus you can remove all values stored at C<node> by passing C<nr_values = 0>.\n\n"; if List.mem ASetValue (snd style) then - pr "C<value> is a single (key, value) pair. + pr "C<value> is a single (key, value) pair. Existing C<hive_value_h> handles become invalid.\n\n"; @@ -1791,8 +1791,8 @@ static void raise_closed (const char *) Noreturn; | ASetValues -> pr " int nrvalues = Wosize_val (valuesv);\n"; pr " hive_set_value *values = HiveSetValues_val (valuesv);\n" - | ASetValue -> - pr " hive_set_value *val = HiveSetValue_val (valv);\n" + | ASetValue -> + pr " hive_set_value *val = HiveSetValue_val (valv);\n" ) (snd style); pr "\n"; @@ -1864,9 +1864,9 @@ static void raise_closed (const char *) Noreturn; | ASetValues -> pr " free (values);\n"; pr "\n"; - | ASetValue -> - pr " free (val);\n"; - pr "\n"; + | ASetValue -> + pr " free (val);\n"; + pr "\n"; ) (snd style); (* Check for errors. *) @@ -1903,7 +1903,7 @@ static void raise_closed (const char *) Noreturn; pr " free (r);\n" | RStringList -> pr " rv = caml_copy_string_array ((const char **) r);\n"; - pr " int i;\n"; + pr " int i;\n"; pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n"; pr " free (r);\n" | RLenType -> pr " rv = copy_type_len (len, t);\n" @@ -2220,45 +2220,45 @@ sub open { * Therefore we don't generate prototypes for these two calls: *) if fst style <> RErrDispose && List.hd (snd style) = AHive then ( - let longdesc = replace_str longdesc "C<hivex_" "C<" in - pr "=item %s\n\n " name; - generate_perl_prototype name style; - pr "\n\n"; - pr "%s\n\n" longdesc; - - (match fst style with - | RErr - | RErrDispose - | RHive - | RString - | RStringList - | RLenType - | RLenValue - | RLenTypeVal - | RInt32 - | RInt64 -> () - | RSize -> + let longdesc = replace_str longdesc "C<hivex_" "C<" in + pr "=item %s\n\n " name; + generate_perl_prototype name style; + pr "\n\n"; + pr "%s\n\n" longdesc; + + (match fst style with + | RErr + | RErrDispose + | RHive + | RString + | RStringList + | RLenType + | RLenValue + | RLenTypeVal + | RInt32 + | RInt64 -> () + | RSize -> pr "\ This returns a size.\n\n" - | RNode -> - pr "\ + | RNode -> + pr "\ This returns a node handle.\n\n" - | RNodeNotFound -> - pr "\ + | RNodeNotFound -> + pr "\ This returns a node handle, or C<undef> if the node was not found.\n\n" - | RNodeList -> - pr "\ + | RNodeList -> + pr "\ This returns a list of node handles.\n\n" - | RValue -> - pr "\ + | RValue -> + pr "\ This returns a value handle.\n\n" - | RValueList -> - pr "\ + | RValueList -> + pr "\ This returns a list of value handles.\n\n" - ); + ); - if List.mem ASetValues (snd style) then - pr "C<@values> is an array of (keys, value) pairs. + if List.mem ASetValues (snd style) then + pr "C<@values> is an array of (keys, value) pairs. Each element should be a hashref containing C<key>, C<t> (type) and C<data>. @@ -2524,172 +2524,172 @@ DESTROY (h) fun (name, style, _, longdesc) -> (* The close and open calls are handled specially above. *) if fst style <> RErrDispose && List.hd (snd style) = AHive then ( - (match fst style with - | RErr -> pr "void\n" - | RErrDispose -> failwith "perl bindings cannot handle a call which disposes of the handle" - | RHive -> failwith "perl bindings cannot handle a call which returns a handle" - | RSize - | RNode - | RNodeNotFound - | RValue - | RString -> pr "SV *\n" - | RNodeList - | RValueList - | RStringList - | RLenType - | RLenValue - | RLenTypeVal -> pr "void\n" - | RInt32 -> pr "SV *\n" - | RInt64 -> pr "SV *\n" - ); - - (* Call and arguments. *) - let perl_params - filter_map (function - | AUnusedFlags -> None - | arg -> Some (name_of_argt arg)) (snd style) in - - let c_params - List.map (function - | AUnusedFlags -> "0" - | ASetValues -> "values.nr_values, values.values" - | arg -> name_of_argt arg) (snd style) in - - pr "%s (%s)\n" name (String.concat ", " perl_params); - iteri ( + (match fst style with + | RErr -> pr "void\n" + | RErrDispose -> failwith "perl bindings cannot handle a call which disposes of the handle" + | RHive -> failwith "perl bindings cannot handle a call which returns a handle" + | RSize + | RNode + | RNodeNotFound + | RValue + | RString -> pr "SV *\n" + | RNodeList + | RValueList + | RStringList + | RLenType + | RLenValue + | RLenTypeVal -> pr "void\n" + | RInt32 -> pr "SV *\n" + | RInt64 -> pr "SV *\n" + ); + + (* Call and arguments. *) + let perl_params + filter_map (function + | AUnusedFlags -> None + | arg -> Some (name_of_argt arg)) (snd style) in + + let c_params + List.map (function + | AUnusedFlags -> "0" + | ASetValues -> "values.nr_values, values.values" + | arg -> name_of_argt arg) (snd style) in + + pr "%s (%s)\n" name (String.concat ", " perl_params); + iteri ( fun i -> function | AHive -> - pr " hive_h *h;\n" - | ANode n - | AValue n -> - pr " int %s;\n" n - | AString n -> - pr " char *%s;\n" n + pr " hive_h *h;\n" + | ANode n + | AValue n -> + pr " int %s;\n" n + | AString n -> + pr " char *%s;\n" n | AStringNullable n -> - (* http://www.perlmonks.org/?node_id=554277 *) - pr " char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n i i - | AOpenFlags -> - pr " int flags;\n" - | AUnusedFlags -> () - | ASetValues -> - pr " pl_set_values values = unpack_pl_set_values (ST(%d));\n" i - | ASetValue -> - pr " hive_set_value *val = unpack_set_value (ST(%d));\n" i - ) (snd style); - - let free_args () - List.iter ( - function - | ASetValues -> - pr " free (values.values);\n" - | ASetValue -> - pr " free (val);\n" - | AHive | ANode _ | AValue _ | AString _ | AStringNullable _ - | AOpenFlags | AUnusedFlags -> () - ) (snd style) - in - - (* Code. *) - (match fst style with - | RErr -> + (* http://www.perlmonks.org/?node_id=554277 *) + pr " char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n i i + | AOpenFlags -> + pr " int flags;\n" + | AUnusedFlags -> () + | ASetValues -> + pr " pl_set_values values = unpack_pl_set_values (ST(%d));\n" i + | ASetValue -> + pr " hive_set_value *val = unpack_set_value (ST(%d));\n" i + ) (snd style); + + let free_args () + List.iter ( + function + | ASetValues -> + pr " free (values.values);\n" + | ASetValue -> + pr " free (val);\n" + | AHive | ANode _ | AValue _ | AString _ | AStringNullable _ + | AOpenFlags | AUnusedFlags -> () + ) (snd style) + in + + (* Code. *) + (match fst style with + | RErr -> pr "PREINIT:\n"; pr " int r;\n"; pr " PPCODE:\n"; pr " r = hivex_%s (%s);\n" - name (String.concat ", " c_params); - free_args (); + name (String.concat ", " c_params); + free_args (); pr " if (r == -1)\n"; pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n" - name; + name; - | RErrDispose -> assert false - | RHive -> assert false + | RErrDispose -> assert false + | RHive -> assert false - | RSize - | RNode - | RValue -> + | RSize + | RNode + | RValue -> pr "PREINIT:\n"; - pr " /* hive_node_h = hive_value_h = size_t so we cheat\n"; - pr " here to simplify the generator */\n"; + pr " /* hive_node_h = hive_value_h = size_t so we cheat\n"; + pr " here to simplify the generator */\n"; pr " size_t r;\n"; pr " CODE:\n"; pr " r = hivex_%s (%s);\n" - name (String.concat ", " c_params); - free_args (); + name (String.concat ", " c_params); + free_args (); pr " if (r == 0)\n"; pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n" - name; + name; pr " RETVAL = newSViv (r);\n"; pr " OUTPUT:\n"; pr " RETVAL\n" - | RNodeNotFound -> + | RNodeNotFound -> pr "PREINIT:\n"; pr " hive_node_h r;\n"; pr " CODE:\n"; - pr " errno = 0;\n"; + pr " errno = 0;\n"; pr " r = hivex_%s (%s);\n" - name (String.concat ", " c_params); - free_args (); + name (String.concat ", " c_params); + free_args (); pr " if (r == 0 && errno != 0)\n"; pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n" - name; - pr " if (r == 0)\n"; + name; + pr " if (r == 0)\n"; pr " RETVAL = &PL_sv_undef;\n"; - pr " else\n"; + pr " else\n"; pr " RETVAL = newSViv (r);\n"; pr " OUTPUT:\n"; pr " RETVAL\n" - | RString -> + | RString -> pr "PREINIT:\n"; pr " char *r;\n"; pr " CODE:\n"; pr " r = hivex_%s (%s);\n" - name (String.concat ", " c_params); - free_args (); + name (String.concat ", " c_params); + free_args (); pr " if (r == NULL)\n"; pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n" - name; + name; if f_len_exists name then pr " RETVAL = newSVpvn_utf8 (r, hivex_%s_len (%s), 1);\n" name (String.concat ", " c_params) else pr " RETVAL = newSVpv (r, 0);\n"; - pr " free (r);\n"; + pr " free (r);\n"; pr " OUTPUT:\n"; pr " RETVAL\n" - | RNodeList - | RValueList -> + | RNodeList + | RValueList -> pr "PREINIT:\n"; pr " size_t *r;\n"; pr " int i, n;\n"; pr " PPCODE:\n"; pr " r = hivex_%s (%s);\n" - name (String.concat ", " c_params); - free_args (); + name (String.concat ", " c_params); + free_args (); pr " if (r == NULL)\n"; pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n" - name; + name; pr " for (n = 0; r[n] != 0; ++n) /**/;\n"; pr " EXTEND (SP, n);\n"; pr " for (i = 0; i < n; ++i)\n"; pr " PUSHs (sv_2mortal (newSViv (r[i])));\n"; pr " free (r);\n"; - | RStringList -> + | RStringList -> pr "PREINIT:\n"; pr " char **r;\n"; pr " int i, n;\n"; pr " PPCODE:\n"; pr " r = hivex_%s (%s);\n" - name (String.concat ", " c_params); - free_args (); + name (String.concat ", " c_params); + free_args (); pr " if (r == NULL)\n"; pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n" - name; + name; pr " for (n = 0; r[n] != NULL; ++n) /**/;\n"; pr " EXTEND (SP, n);\n"; pr " for (i = 0; i < n; ++i) {\n"; @@ -2698,86 +2698,86 @@ DESTROY (h) pr " }\n"; pr " free (r);\n"; - | RLenType -> - pr "PREINIT:\n"; - pr " int r;\n"; - pr " size_t len;\n"; - pr " hive_type type;\n"; - pr " PPCODE:\n"; + | RLenType -> + pr "PREINIT:\n"; + pr " int r;\n"; + pr " size_t len;\n"; + pr " hive_type type;\n"; + pr " PPCODE:\n"; pr " r = hivex_%s (%s, &type, &len);\n" - name (String.concat ", " c_params); - free_args (); + name (String.concat ", " c_params); + free_args (); pr " if (r == -1)\n"; pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n" - name; - pr " EXTEND (SP, 2);\n"; - pr " PUSHs (sv_2mortal (newSViv (type)));\n"; - pr " PUSHs (sv_2mortal (newSViv (len)));\n"; - - | RLenValue -> - pr "PREINIT:\n"; - pr " hive_value_h r;\n"; - pr " size_t len;\n"; - pr " PPCODE:\n"; + name; + pr " EXTEND (SP, 2);\n"; + pr " PUSHs (sv_2mortal (newSViv (type)));\n"; + pr " PUSHs (sv_2mortal (newSViv (len)));\n"; + + | RLenValue -> + pr "PREINIT:\n"; + pr " hive_value_h r;\n"; + pr " size_t len;\n"; + pr " PPCODE:\n"; pr " errno = 0;\n"; pr " r = hivex_%s (%s, &len);\n" - name (String.concat ", " c_params); - free_args (); + name (String.concat ", " c_params); + free_args (); pr " if (r == 0 && errno)\n"; pr " croak (\"%%s: \", \"%s\", strerror (errno));\n" - name; - pr " EXTEND (SP, 2);\n"; - pr " PUSHs (sv_2mortal (newSViv (len)));\n"; - pr " PUSHs (sv_2mortal (newSViv (r)));\n"; - - | RLenTypeVal -> - pr "PREINIT:\n"; - pr " char *r;\n"; - pr " size_t len;\n"; - pr " hive_type type;\n"; - pr " PPCODE:\n"; + name; + pr " EXTEND (SP, 2);\n"; + pr " PUSHs (sv_2mortal (newSViv (len)));\n"; + pr " PUSHs (sv_2mortal (newSViv (r)));\n"; + + | RLenTypeVal -> + pr "PREINIT:\n"; + pr " char *r;\n"; + pr " size_t len;\n"; + pr " hive_type type;\n"; + pr " PPCODE:\n"; pr " r = hivex_%s (%s, &type, &len);\n" - name (String.concat ", " c_params); - free_args (); + name (String.concat ", " c_params); + free_args (); pr " if (r == NULL)\n"; pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n" - name; - pr " EXTEND (SP, 2);\n"; - pr " PUSHs (sv_2mortal (newSViv (type)));\n"; - pr " PUSHs (sv_2mortal (newSVpvn (r, len)));\n"; - pr " free (r);\n"; + name; + pr " EXTEND (SP, 2);\n"; + pr " PUSHs (sv_2mortal (newSViv (type)));\n"; + pr " PUSHs (sv_2mortal (newSVpvn (r, len)));\n"; + pr " free (r);\n"; - | RInt32 -> + | RInt32 -> pr "PREINIT:\n"; pr " int32_t r;\n"; pr " CODE:\n"; - pr " errno = 0;\n"; + pr " errno = 0;\n"; pr " r = hivex_%s (%s);\n" - name (String.concat ", " c_params); - free_args (); + name (String.concat ", " c_params); + free_args (); pr " if (r == -1 && errno != 0)\n"; pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n" - name; + name; pr " RETVAL = newSViv (r);\n"; pr " OUTPUT:\n"; pr " RETVAL\n" - | RInt64 -> + | RInt64 -> pr "PREINIT:\n"; pr " int64_t r;\n"; pr " CODE:\n"; - pr " errno = 0;\n"; + pr " errno = 0;\n"; pr " r = hivex_%s (%s);\n" - name (String.concat ", " c_params); - free_args (); + name (String.concat ", " c_params); + free_args (); pr " if (r == -1 && errno != 0)\n"; pr " croak (\"%%s: %%s\", \"%s\", strerror (errno));\n" - name; + name; pr " RETVAL = my_newSVll (r);\n"; pr " OUTPUT:\n"; pr " RETVAL\n" - ); - pr "\n" + ); + pr "\n" ) ) functions @@ -3055,10 +3055,10 @@ put_val_type (char *val, size_t len, hive_type t) pr " PyObject *py_r;\n"; let error_code - match fst style with + match fst style with | RErr -> pr " int r;\n"; "-1" - | RErrDispose -> pr " int r;\n"; "-1" - | RHive -> pr " hive_h *r;\n"; "NULL" + | RErrDispose -> pr " int r;\n"; "-1" + | RHive -> pr " hive_h *r;\n"; "NULL" | RSize -> pr " size_t r;\n"; "0" | RNode -> pr " hive_node_h r;\n"; "0" | RNodeNotFound -> @@ -3096,11 +3096,11 @@ put_val_type (char *val, size_t len, hive_type t) (* Call and arguments. *) let c_params - List.map (function - | AUnusedFlags -> "0" - | ASetValues -> "values.nr_values, values.values" + List.map (function + | AUnusedFlags -> "0" + | ASetValues -> "values.nr_values, values.values" | ASetValue -> "&val" - | arg -> name_of_argt arg) (snd style) in + | arg -> name_of_argt arg) (snd style) in let c_params match fst style with | RLenType | RLenTypeVal -> c_params @ ["&t"; "&len"] @@ -3110,20 +3110,20 @@ put_val_type (char *val, size_t len, hive_type t) List.iter ( function | AHive -> - pr " hive_h *h;\n"; + pr " hive_h *h;\n"; pr " PyObject *py_h;\n" - | ANode n - | AValue n -> - pr " long %s;\n" n - | AString n + | ANode n + | AValue n -> + pr " long %s;\n" n + | AString n | AStringNullable n -> - pr " char *%s;\n" n - | AOpenFlags -> - pr " int flags;\n" - | AUnusedFlags -> () - | ASetValues -> - pr " py_set_values values;\n"; - pr " PyObject *py_values;\n" + pr " char *%s;\n" n + | AOpenFlags -> + pr " int flags;\n" + | AUnusedFlags -> () + | ASetValues -> + pr " py_set_values values;\n"; + pr " PyObject *py_values;\n" | ASetValue -> pr " hive_set_value val;\n"; pr " PyObject *py_val;\n"; @@ -3137,19 +3137,19 @@ put_val_type (char *val, size_t len, hive_type t) List.iter ( function | AHive -> - pr "O" - | ANode n - | AValue n -> - pr "l" - | AString n -> - pr "s" + pr "O" + | ANode n + | AValue n -> + pr "l" + | AString n -> + pr "s" | AStringNullable n -> - pr "z" - | AOpenFlags -> - pr "i" - | AUnusedFlags -> () - | ASetValues - | ASetValue -> + pr "z" + | AOpenFlags -> + pr "i" + | AUnusedFlags -> () + | ASetValues + | ASetValue -> pr "O" ) (snd style); @@ -3158,19 +3158,19 @@ put_val_type (char *val, size_t len, hive_type t) List.iter ( function | AHive -> - pr ", &py_h" - | ANode n - | AValue n -> - pr ", &%s" n - | AString n + pr ", &py_h" + | ANode n + | AValue n -> + pr ", &%s" n + | AString n | AStringNullable n -> - pr ", &%s" n - | AOpenFlags -> - pr ", &flags" - | AUnusedFlags -> () - | ASetValues -> + pr ", &%s" n + | AOpenFlags -> + pr ", &flags" + | AUnusedFlags -> () + | ASetValues -> pr ", &py_values" - | ASetValue -> + | ASetValue -> pr ", &py_val" ) (snd style); @@ -3182,13 +3182,13 @@ put_val_type (char *val, size_t len, hive_type t) function | AHive -> pr " h = get_handle (py_h);\n" - | ANode _ - | AValue _ - | AString _ + | ANode _ + | AValue _ + | AString _ | AStringNullable _ - | AOpenFlags - | AUnusedFlags -> () - | ASetValues -> + | AOpenFlags + | AUnusedFlags -> () + | ASetValues -> pr " if (get_values (py_values, &values) == -1)\n"; pr " return NULL;\n" | ASetValue -> @@ -3202,10 +3202,10 @@ put_val_type (char *val, size_t len, hive_type t) (* Free up arguments. *) List.iter ( function - | AHive | ANode _ | AValue _ + | AHive | ANode _ | AValue _ | AString _ | AStringNullable _ - | AOpenFlags | AUnusedFlags -> () - | ASetValues -> + | AOpenFlags | AUnusedFlags -> () + | ASetValues -> pr " free (values.values);\n"; pr " free (values.words);\n" | ASetValue -> () @@ -3391,13 +3391,13 @@ class Hivex(object): fun arg -> pr ", "; match arg with - | AHive -> assert false + | AHive -> assert false | ANode n | AValue n | AString n | AStringNullable n -> pr "%s" n - | AOpenFlags + | AOpenFlags | AUnusedFlags -> assert false - | ASetValues -> pr "values" - | ASetValue -> pr "val" + | ASetValues -> pr "values" + | ASetValue -> pr "val" ) args; pr ")\n"; pr "\n" @@ -3434,9 +3434,9 @@ and generate_ruby_c () #define RSTRING_PTR(r) (RSTRING((r))->ptr) #endif -static VALUE m_hivex; /* hivex module */ -static VALUE c_hivex; /* hive_h handle */ -static VALUE e_Error; /* used for all errors */ +static VALUE m_hivex; /* hivex module */ +static VALUE c_hivex; /* hive_h handle */ +static VALUE e_Error; /* used for all errors */ static void ruby_hivex_free (void *hvp) @@ -3591,10 +3591,10 @@ get_values (VALUE valuesv, size_t *nr_values) pr "\n"; let error_code - match ret with + match ret with | RErr -> pr " int r;\n"; "-1" - | RErrDispose -> pr " int r;\n"; "-1" - | RHive -> pr " hive_h *r;\n"; "NULL" + | RErrDispose -> pr " int r;\n"; "-1" + | RHive -> pr " hive_h *r;\n"; "NULL" | RSize -> pr " size_t r;\n"; "0" | RNode -> pr " hive_node_h r;\n"; "0" | RNodeNotFound -> -- 2.0.2