summaryrefslogtreecommitdiffhomepage
path: root/libs/luci-lib-jsonc
diff options
context:
space:
mode:
Diffstat (limited to 'libs/luci-lib-jsonc')
-rw-r--r--libs/luci-lib-jsonc/src/jsonc.c77
1 files changed, 74 insertions, 3 deletions
diff --git a/libs/luci-lib-jsonc/src/jsonc.c b/libs/luci-lib-jsonc/src/jsonc.c
index ef11101660..9ff8520dbc 100644
--- a/libs/luci-lib-jsonc/src/jsonc.c
+++ b/libs/luci-lib-jsonc/src/jsonc.c
@@ -27,6 +27,12 @@ limitations under the License.
#define LUCI_JSONC "luci.jsonc"
#define LUCI_JSONC_PARSER "luci.jsonc.parser"
+struct seen {
+ size_t size;
+ size_t len;
+ const void *ptrs[];
+};
+
struct json_state {
struct json_object *obj;
struct json_tokener *tok;
@@ -35,6 +41,7 @@ struct json_state {
static void _json_to_lua(lua_State *L, struct json_object *obj);
static struct json_object * _lua_to_json(lua_State *L, int index);
+static struct json_object * _lua_to_json_rec(lua_State *L, int index, struct seen **seen);
static int json_new(lua_State *L)
{
@@ -199,6 +206,9 @@ static int _lua_test_array(lua_State *L, int index)
int max = 0;
lua_Number idx;
+ if (!lua_checkstack(L, 2))
+ return -1;
+
lua_pushnil(L);
/* check for non-integer keys */
@@ -243,16 +253,54 @@ out:
return max;
}
-static struct json_object * _lua_to_json(lua_State *L, int index)
+
+static bool visited(struct seen **sp, const void *ptr) {
+ struct seen *s = *sp;
+ size_t i;
+
+ if (s->len >= s->size)
+ {
+ i = s->size + 10;
+ s = realloc(*sp, sizeof(struct seen) + sizeof(void *) * i);
+
+ if (!s)
+ {
+ if (*sp)
+ free(*sp);
+
+ *sp = NULL;
+ return true;
+ }
+
+ s->size = i;
+ *sp = s;
+ }
+
+ for (i = 0; i < s->len; i++)
+ if (s->ptrs[i] == ptr)
+ return true;
+
+ s->ptrs[s->len++] = ptr;
+ return false;
+}
+
+static struct json_object * _lua_to_json_rec(lua_State *L, int index,
+ struct seen **seen)
{
lua_Number nd, ni;
struct json_object *obj;
const char *key;
int i, max;
+ if (index < 0)
+ index = lua_gettop(L) + index + 1;
+
switch (lua_type(L, index))
{
case LUA_TTABLE:
+ if (visited(seen, lua_topointer(L, index)))
+ return NULL;
+
max = _lua_test_array(L, index);
if (max >= 0)
@@ -262,12 +310,15 @@ static struct json_object * _lua_to_json(lua_State *L, int index)
if (!obj)
return NULL;
+ if (!lua_checkstack(L, 1))
+ return NULL;
+
for (i = 1; i <= max; i++)
{
lua_rawgeti(L, index, i);
json_object_array_put_idx(obj, i - 1,
- _lua_to_json(L, lua_gettop(L)));
+ _lua_to_json_rec(L, -1, seen));
lua_pop(L, 1);
}
@@ -280,6 +331,9 @@ static struct json_object * _lua_to_json(lua_State *L, int index)
if (!obj)
return NULL;
+ if (!lua_checkstack(L, 3))
+ return NULL;
+
lua_pushnil(L);
while (lua_next(L, index))
@@ -289,7 +343,7 @@ static struct json_object * _lua_to_json(lua_State *L, int index)
if (key)
json_object_object_add(obj, key,
- _lua_to_json(L, lua_gettop(L) - 1));
+ _lua_to_json_rec(L, -2, seen));
lua_pop(L, 2);
}
@@ -318,6 +372,23 @@ static struct json_object * _lua_to_json(lua_State *L, int index)
return NULL;
}
+static struct json_object * _lua_to_json(lua_State *L, int index)
+{
+ struct seen *s = calloc(sizeof(struct seen) + sizeof(void *) * 10, 1);
+ struct json_object *rv;
+
+ if (!s)
+ return NULL;
+
+ s->size = 10;
+
+ rv = _lua_to_json_rec(L, index, &s);
+
+ free(s);
+
+ return rv;
+}
+
static int json_parse_set(lua_State *L)
{
struct json_state *s = luaL_checkudata(L, 1, LUCI_JSONC_PARSER);