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
Possibly Parallel Threads
- [hivex] [PATCH 0/6] Python fixes for node_set_value
- [PATCH] hivex: add hivex_set_value api call and ocaml/perl bindings, tests
- [PATCH] hivex: add hivex_set_value api call and perl bindings, tests
- [PATCH 1/2] Add type checking, support integers as value
- [PATCH] hivex: add hivex_set_value api call