From e162d378c717e0cc1157aa06d99af69e51fdc20e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 13 Sep 2012 15:26:22 +0200 Subject: Add set/unset stmt to grammar & AST ... but not yet to executing engine --- grammar/grammar.y | 8 ++++++++ grammar/lexer.l | 6 +++++- grammar/rainerscript.c | 38 ++++++++++++++++++++++++++++++++++++++ grammar/rainerscript.h | 11 +++++++++++ 4 files changed, 62 insertions(+), 1 deletion(-) diff --git a/grammar/grammar.y b/grammar/grammar.y index f455a21f..6b967ca4 100644 --- a/grammar/grammar.y +++ b/grammar/grammar.y @@ -65,6 +65,8 @@ extern int yyerror(char*); %token BEGIN_CONSTANT %token BEGIN_TPL %token STOP +%token SET +%token UNSET %token LEGACY_ACTION %token LEGACY_RULESET %token PRIFILT @@ -153,6 +155,12 @@ stmt: actlst { $$ = $1; } $$->d.s_if.expr = $2; $$->d.s_if.t_then = $4; $$->d.s_if.t_else = $6; } + | SET VAR '=' expr ';' { dbgprintf("TTTT: have SET stmt, var:'%s'\n", $2); + $$ = cnfstmtNewSet($2, $4); + } + | UNSET VAR ';' { dbgprintf("TTTT: have UNSET stmt, var:'%s'\n", $2); + $$ = cnfstmtNewUnset($2); + } | PRIFILT block { $$ = cnfstmtNewPRIFILT($1, $2); } | PROPFILT block { $$ = cnfstmtNewPROPFILT($1, $2); } block: stmt { $$ = $1; } diff --git a/grammar/lexer.l b/grammar/lexer.l index 8b930713..7f42b04e 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -96,9 +96,11 @@ int fileno(FILE *stream); /* keywords */ "if" { BEGIN EXPR; return IF; } "then" { BEGIN INITIAL; return THEN; } +";" { BEGIN INITIAL; return ';'; } "or" { return OR; } "and" { return AND; } "not" { return NOT; } +"=" | "," | "*" | "/" | @@ -121,7 +123,7 @@ int fileno(FILE *stream); 0[0-7]+ | /* octal number */ 0x[0-7a-f] | /* hex number, following rule is dec; strtoll handles all! */ ([1-9][0-9]*|0) { yylval.n = strtoll(yytext, NULL, 0); return NUMBER; } -\$[$!]{0,1}[a-z][a-z0-9\-_\.]* { yylval.s = strdup(yytext); return VAR; } +\$[$!]{0,1}[a-z][!a-z0-9\-_\.]* { yylval.s = strdup(yytext); return VAR; } \'([^'\\]|\\['"\\$bntr]|\\x[0-9a-f][0-9a-f]|\\[0-7][0-7][0-7])*\' { yytext[yyleng-1] = '\0'; unescapeStr((uchar*)yytext+1, yyleng-2); @@ -145,6 +147,8 @@ int fileno(FILE *stream); */ "stop" { return STOP; } "else" { return ELSE; } +"set" { BEGIN EXPR; return SET; } +"unset" { BEGIN EXPR; return UNSET; } "preprocfilelinenumber(" { BEGIN LINENO; } [0-9]+ { yylineno = atoi(yytext) - 1; } ")" { BEGIN INITIAL; } diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index b0a79458..c7344628 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1466,6 +1466,16 @@ cnfstmtPrint(struct cnfstmt *root, int indent) } doIndent(indent); dbgprintf("END IF\n"); break; + case S_SET: + doIndent(indent); dbgprintf("SET %s =\n", + stmt->d.s_set.varname); + cnfexprPrint(stmt->d.s_set.expr, indent+1); + doIndent(indent); dbgprintf("END SET\n"); + break; + case S_UNSET: + doIndent(indent); dbgprintf("UNSET %s\n", + stmt->d.s_unset.varname); + break; case S_PRIFILT: doIndent(indent); dbgprintf("PRIFILT '%s'\n", stmt->printable); cnfstmtPrint(stmt->d.s_prifilt.t_then, indent+1); @@ -1569,6 +1579,13 @@ cnfstmtDestruct(struct cnfstmt *root) cnfstmtDestruct(stmt->d.s_if.t_else); } break; + case S_SET: + free(stmt->d.s_set.varname); + cnfexprDestruct(stmt->d.s_set.expr); + break; + case S_UNSET: + free(stmt->d.s_set.varname); + break; case S_PRIFILT: cnfstmtDestruct(stmt->d.s_prifilt.t_then); break; @@ -1593,6 +1610,27 @@ cnfstmtDestruct(struct cnfstmt *root) } } +struct cnfstmt * +cnfstmtNewSet(char *var, struct cnfexpr *expr) +{ + struct cnfstmt* cnfstmt; + if((cnfstmt = cnfstmtNew(S_SET)) != NULL) { + cnfstmt->d.s_set.varname = (uchar*) var; + cnfstmt->d.s_set.expr = expr; + } + return cnfstmt; +} + +struct cnfstmt * +cnfstmtNewUnset(char *var) +{ + struct cnfstmt* cnfstmt; + if((cnfstmt = cnfstmtNew(S_UNSET)) != NULL) { + cnfstmt->d.s_unset.varname = (uchar*) var; + } + return cnfstmt; +} + struct cnfstmt * cnfstmtNewPRIFILT(char *prifilt, struct cnfstmt *t_then) { diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index 7637ae48..51d96e51 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -116,6 +116,8 @@ struct nvlst { #define S_IF 4003 #define S_ACT 4004 #define S_NOP 4005 /* usually used to disable some statement */ +#define S_SET 4006 +#define S_UNSET 4007 enum cnfFiltType { CNFFILT_NONE, CNFFILT_PRI, CNFFILT_PROP, CNFFILT_SCRIPT }; static inline char* @@ -145,6 +147,13 @@ struct cnfstmt { struct cnfstmt *t_then; struct cnfstmt *t_else; } s_if; + struct { + uchar *varname; + struct cnfexpr *expr; + } s_set; + struct { + uchar *varname; + } s_unset; struct { uchar pmask[LOG_NFACILITIES+1]; /* priority mask */ struct cnfstmt *t_then; @@ -288,6 +297,8 @@ struct cnfstmt * cnfstmtNewPRIFILT(char *prifilt, struct cnfstmt *t_then); struct cnfstmt * cnfstmtNewPROPFILT(char *propfilt, struct cnfstmt *t_then); struct cnfstmt * cnfstmtNewAct(struct nvlst *lst); struct cnfstmt * cnfstmtNewLegaAct(char *actline); +struct cnfstmt * cnfstmtNewSet(char *var, struct cnfexpr *expr); +struct cnfstmt * cnfstmtNewUnset(char *var); void cnfstmtDestruct(struct cnfstmt *root); char* getFIOPName(unsigned iFIOP); rsRetVal initRainerscript(void); -- cgit v1.2.3 From 71a5122fae6e46c0547f09fb527e1f4355b33810 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 13 Sep 2012 18:53:41 +0200 Subject: Implement set config stmt (initial version) code passes basic tests, no extended testing done. Definitely room for improvement, but not bad ;) --- runtime/msg.c | 57 ++++++++++++++++++++++++++++++++++++++++++------------- runtime/rsyslog.h | 1 + runtime/ruleset.c | 22 +++++++++++++++++++++ 3 files changed, 67 insertions(+), 13 deletions(-) diff --git a/runtime/msg.c b/runtime/msg.c index f1f7997c..15eb7abb 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -2420,7 +2420,6 @@ getCEEPropVal(msg_t *pM, es_str_t *propName, uchar **pRes, int *buflen, unsigned if(*pbMustBeFreed) free(*pRes); *pRes = NULL; -dbgprintf("AAAA: enter getCEEPropVal\n"); // TODO: mutex? if(pM->json == NULL) goto finalize_it; @@ -2428,9 +2427,7 @@ dbgprintf("AAAA: enter getCEEPropVal\n"); field = pM->json; } else { name = (uchar*)es_str2cstr(propName, NULL); -dbgprintf("AAAA: name to search '%s'\n", name); leaf = jsonPathGetLeaf(name, ustrlen(name)); -dbgprintf("AAAA: leaf '%s'\n", leaf); CHKiRet(jsonPathFindParent(pM, name, leaf, &parent, 1)); field = json_object_object_get(parent, (char*)leaf); } @@ -2439,7 +2436,6 @@ dbgprintf("AAAA: leaf '%s'\n", leaf); *pbMustBeFreed = 0; } else { *pRes = (uchar*) strdup(json_object_get_string(field)); -dbgprintf("AAAA: json_object_get_string() returns '%s'\n", *pRes); *buflen = (int) ustrlen(*pRes); *pbMustBeFreed = 1; } @@ -2465,7 +2461,6 @@ msgGetCEEPropJSON(msg_t *pM, es_str_t *propName, struct json_object **pjson) struct json_object *parent; DEFiRet; -dbgprintf("AAAA: enter getCEEPropJSON\n"); // TODO: mutex? if(pM->json == NULL) { ABORT_FINALIZE(RS_RET_NOT_FOUND); @@ -2476,9 +2471,7 @@ dbgprintf("AAAA: enter getCEEPropJSON\n"); FINALIZE; } name = (uchar*)es_str2cstr(propName, NULL); -dbgprintf("AAAA: name to search '%s'\n", name); leaf = jsonPathGetLeaf(name, ustrlen(name)); -dbgprintf("AAAA: leaf '%s'\n", leaf); CHKiRet(jsonPathFindParent(pM, name, leaf, &parent, 1)); *pjson = json_object_object_get(parent, (char*)leaf); if(*pjson == NULL) { @@ -3685,9 +3678,9 @@ jsonPathFindNext(struct json_object *root, uchar **name, uchar *leaf, ++p; for(i = 0 ; *p && *p != '!' && p != leaf && i < sizeof(namebuf)-1 ; ++i, ++p) namebuf[i] = *p; - if(i == 0) { + if(i > 0) { namebuf[i] = '\0'; - dbgprintf("AAAA: next JSONP elt: '%s'\n", namebuf); + dbgprintf("AAAA: next JSONPath elt: '%s'\n", namebuf); json = json_object_object_get(root, (char*)namebuf); } else json = root; @@ -3713,7 +3706,6 @@ jsonPathFindParent(msg_t *pM, uchar *name, uchar *leaf, struct json_object **par *parent = pM->json; while(name < leaf-1) { jsonPathFindNext(*parent, &name, leaf, parent, bCreate); -dbgprintf("AAAA: name %p, leaf %p\n", name, leaf); } RETiRet; } @@ -3726,7 +3718,7 @@ jsonMerge(struct json_object *existing, struct json_object *json) struct json_object_iter it; json_object_object_foreachC(json, it) { -dbgprintf("AAAA jsonMerge adds '%s'\n", it.key); +DBGPRINTF("AAAA jsonMerge adds '%s'\n", it.key); json_object_object_add(existing, it.key, json_object_get(it.val)); } @@ -3762,8 +3754,23 @@ msgAddJSON(msg_t *pM, uchar *name, struct json_object *json) leafnode = json_object_object_get(parent, (char*)leaf); if(leafnode == NULL) json_object_object_add(parent, (char*)leaf, json); - else - CHKiRet(jsonMerge(pM->json, json)); + else { + if(json_object_get_type(json) == json_type_object) { + CHKiRet(jsonMerge(pM->json, json)); + } else { +//dbgprintf("AAAA: leafnode already exists, type is %d, update with %d\n", (int)json_object_get_type(leafnode), (int)json_object_get_type(json)); + /* TODO: improve the code below, however, the current + * state is not really bad */ + if(json_object_get_type(leafnode) == json_type_object) { + DBGPRINTF("msgAddJSON: trying to update a container " + "node with a leaf, name is '%s' - " + "forbidden\n", name); + ABORT_FINALIZE(RS_RET_INVLD_SETOP); + } + json_object_object_del(parent, (char*)leaf); + json_object_object_add(parent, (char*)leaf, json); + } + } } finalize_it: @@ -3771,6 +3778,30 @@ finalize_it: RETiRet; } +rsRetVal +msgSetJSONFromVar(msg_t *pMsg, uchar *varname, struct var *var) +{ + struct json_object *json = NULL; + char *cstr; + DEFiRet; + switch(var->datatype) { + case 'S':/* string */ + cstr = es_str2cstr(var->d.estr, NULL); + json = json_object_new_string(cstr); + free(cstr); + break; + case 'N':/* number (integer) */ + json = json_object_new_int((int) var->d.n); + break; + default:DBGPRINTF("msgSetJSONFromVar: unsupported datatype %c\n", + var->datatype); + ABORT_FINALIZE(RS_RET_ERR); + } + msgAddJSON(pMsg, varname+1, json); +finalize_it: + RETiRet; +} + /* dummy */ rsRetVal msgQueryInterface(void) { return RS_RET_NOT_IMPLEMENTED; } diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index fe9bb4cc..2977f6f3 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -387,6 +387,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_JNAME_INVALID = -2302, /**< JSON path is invalid */ RS_RET_JSON_PARSE_ERR = -2303, /**< we had a problem parsing JSON (or extra data) */ RS_RET_BSD_BLOCKS_UNSUPPORTED = -2304, /**< BSD-style config blocks are no longer supported */ + RS_RET_INVLD_SETOP = -2305, /**< invalid variable set operation, incompatible type */ /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ diff --git a/runtime/ruleset.c b/runtime/ruleset.c index faec122c..392473e9 100644 --- a/runtime/ruleset.c +++ b/runtime/ruleset.c @@ -206,6 +206,7 @@ static inline sbool *newActive(batch_t *pBatch) } static inline void freeActive(sbool *active) { free(active); } + /* for details, see scriptExec() header comment! */ /* call action for all messages with filter on */ static rsRetVal @@ -218,6 +219,24 @@ dbgprintf("RRRR: execAct: batch of %d elements, active %p\n", batchNumMsgs(pBatc RETiRet; } +/* for details, see scriptExec() header comment! */ +static rsRetVal +execSet(struct cnfstmt *stmt, batch_t *pBatch, sbool *active) +{ + int i; + struct var result; + DEFiRet; + for(i = 0 ; i < batchNumMsgs(pBatch) && !*(pBatch->pbShutdownImmediate) ; ++i) { + if( pBatch->pElem[i].state != BATCH_STATE_DISC + && (active == NULL || active[i])) { + cnfexprEval(stmt->d.s_set.expr, &result, pBatch->pElem[i].pUsrp); + msgSetJSONFromVar(pBatch->pElem[i].pUsrp, stmt->d.s_set.varname, + &result); + } + } + RETiRet; +} + /* for details, see scriptExec() header comment! */ /* "stop" simply discards the filtered items - it's just a (hopefully more intuitive * shortcut for users. @@ -452,6 +471,9 @@ dbgprintf("RRRR: scriptExec: batch of %d elements, active %p, stmt %p, nodetype case S_IF: execIf(stmt, pBatch, active); break; + case S_SET: + execSet(stmt, pBatch, active); + break; case S_PRIFILT: execPRIFILT(stmt, pBatch, active); break; -- cgit v1.2.3 From 8fe7507de1d9f800fedb82a2cf2e1f443db940f7 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 17 Sep 2012 08:00:12 +0200 Subject: cleanup --- grammar/grammar.y | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/grammar/grammar.y b/grammar/grammar.y index 6b967ca4..074d2abd 100644 --- a/grammar/grammar.y +++ b/grammar/grammar.y @@ -155,12 +155,8 @@ stmt: actlst { $$ = $1; } $$->d.s_if.expr = $2; $$->d.s_if.t_then = $4; $$->d.s_if.t_else = $6; } - | SET VAR '=' expr ';' { dbgprintf("TTTT: have SET stmt, var:'%s'\n", $2); - $$ = cnfstmtNewSet($2, $4); - } - | UNSET VAR ';' { dbgprintf("TTTT: have UNSET stmt, var:'%s'\n", $2); - $$ = cnfstmtNewUnset($2); - } + | SET VAR '=' expr ';' { $$ = cnfstmtNewSet($2, $4); } + | UNSET VAR ';' { $$ = cnfstmtNewUnset($2); } | PRIFILT block { $$ = cnfstmtNewPRIFILT($1, $2); } | PROPFILT block { $$ = cnfstmtNewPROPFILT($1, $2); } block: stmt { $$ = $1; } -- cgit v1.2.3 From 71f602c4e97a67097ede995642a5cb09c0ceca07 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 17 Sep 2012 08:00:34 +0200 Subject: new ruleengine: Implent "unset" statement --- runtime/msg.c | 42 ++++++++++++++++++++++++++++++++++++++++++ runtime/msg.h | 7 +++++++ runtime/rsyslog.h | 1 + runtime/ruleset.c | 29 ++++++++++++++++++++++------- 4 files changed, 72 insertions(+), 7 deletions(-) diff --git a/runtime/msg.c b/runtime/msg.c index 15eb7abb..0cb60436 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -3778,6 +3778,48 @@ finalize_it: RETiRet; } +rsRetVal +msgDelJSON(msg_t *pM, uchar *name) +{ + struct json_object *parent, *leafnode; + uchar *leaf; + DEFiRet; + +dbgprintf("AAAA: unset variable '%s'\n", name); + MsgLock(pM); + if(name[0] == '!' && name[1] == '\0') { + /* strange, but I think we should permit this. After all, + * we trust rsyslog.conf to be written by the admin. + */ + DBGPRINTF("unsetting JSON root object\n"); + json_object_put(pM->json); + pM->json = NULL; + } else { + if(pM->json == NULL) { + /* now we need a root obj */ + pM->json = json_object_new_object(); + } + leaf = jsonPathGetLeaf(name, ustrlen(name)); + CHKiRet(jsonPathFindParent(pM, name, leaf, &parent, 1)); + leafnode = json_object_object_get(parent, (char*)leaf); +DBGPRINTF("AAAA: unset found JSON value path '%s', " "leaf '%s', leafnode %p\n", name, leaf, leafnode); + if(leafnode == NULL) { + DBGPRINTF("unset JSON: could not find '%s'\n", name); + ABORT_FINALIZE(RS_RET_JNAME_NOTFOUND); + } else { + DBGPRINTF("deleting JSON value path '%s', " + "leaf '%s', type %d\n", + name, leaf, json_object_get_type(leafnode)); + json_object_put(leafnode); + json_object_object_del(parent, (char*)leaf); + } + } + +finalize_it: + MsgUnlock(pM); + RETiRet; +} + rsRetVal msgSetJSONFromVar(msg_t *pMsg, uchar *varname, struct var *var) { diff --git a/runtime/msg.h b/runtime/msg.h index 857eb673..477d1f1a 100644 --- a/runtime/msg.h +++ b/runtime/msg.h @@ -202,6 +202,13 @@ uchar *getRcvFrom(msg_t *pM); rsRetVal propNameToID(cstr_t *pCSPropName, propid_t *pPropID); uchar *propIDToName(propid_t propID); rsRetVal msgGetCEEPropJSON(msg_t *pM, es_str_t *propName, struct json_object **pjson); +rsRetVal msgSetJSONFromVar(msg_t *pMsg, uchar *varname, struct var *var); +rsRetVal msgDelJSON(msg_t *pMsg, uchar *varname); + +static inline rsRetVal +msgUnsetJSON(msg_t *pMsg, uchar *varname) { + return msgDelJSON(pMsg, varname+1); +} /* The MsgPrepareEnqueue() function is a macro for performance reasons. diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index 2977f6f3..ceb277d0 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -387,6 +387,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_JNAME_INVALID = -2302, /**< JSON path is invalid */ RS_RET_JSON_PARSE_ERR = -2303, /**< we had a problem parsing JSON (or extra data) */ RS_RET_BSD_BLOCKS_UNSUPPORTED = -2304, /**< BSD-style config blocks are no longer supported */ + RS_RET_JNAME_NOTFOUND = -2305, /**< JSON name not found (does not exist) */ RS_RET_INVLD_SETOP = -2305, /**< invalid variable set operation, incompatible type */ /* RainerScript error messages (range 1000.. 1999) */ diff --git a/runtime/ruleset.c b/runtime/ruleset.c index 392473e9..a40e2ed1 100644 --- a/runtime/ruleset.c +++ b/runtime/ruleset.c @@ -219,7 +219,6 @@ dbgprintf("RRRR: execAct: batch of %d elements, active %p\n", batchNumMsgs(pBatc RETiRet; } -/* for details, see scriptExec() header comment! */ static rsRetVal execSet(struct cnfstmt *stmt, batch_t *pBatch, sbool *active) { @@ -230,8 +229,23 @@ execSet(struct cnfstmt *stmt, batch_t *pBatch, sbool *active) if( pBatch->pElem[i].state != BATCH_STATE_DISC && (active == NULL || active[i])) { cnfexprEval(stmt->d.s_set.expr, &result, pBatch->pElem[i].pUsrp); - msgSetJSONFromVar(pBatch->pElem[i].pUsrp, stmt->d.s_set.varname, + msgSetJSONFromVar((msg_t*)pBatch->pElem[i].pUsrp, stmt->d.s_set.varname, &result); + varDelete(&result); + } + } + RETiRet; +} + +static rsRetVal +execUnset(struct cnfstmt *stmt, batch_t *pBatch, sbool *active) +{ + int i; + DEFiRet; + for(i = 0 ; i < batchNumMsgs(pBatch) && !*(pBatch->pbShutdownImmediate) ; ++i) { + if( pBatch->pElem[i].state != BATCH_STATE_DISC + && (active == NULL || active[i])) { + msgUnsetJSON((msg_t*)pBatch->pElem[i].pUsrp, stmt->d.s_unset.varname); } } RETiRet; @@ -321,7 +335,6 @@ execPRIFILT(struct cnfstmt *stmt, batch_t *pBatch, sbool *active) DBGPRINTF("batch: item %d PRIFILT %d\n", i, thenAct[i]); } -dbgprintf("RRRR: PRIFILT calling %p\n", stmt->d.s_prifilt.t_then); scriptExec(stmt->d.s_prifilt.t_then, pBatch, thenAct); freeActive(thenAct); } @@ -436,7 +449,6 @@ execPROPFILT(struct cnfstmt *stmt, batch_t *pBatch, sbool *active) DBGPRINTF("batch: item %d PROPFILT %d\n", i, thenAct[i]); } -dbgprintf("RRRR: PROPFILT calling %p\n", stmt->d.s_propfilt.t_then); scriptExec(stmt->d.s_propfilt.t_then, pBatch, thenAct); freeActive(thenAct); } @@ -468,12 +480,15 @@ dbgprintf("RRRR: scriptExec: batch of %d elements, active %p, stmt %p, nodetype case S_ACT: execAct(stmt, pBatch, active); break; - case S_IF: - execIf(stmt, pBatch, active); - break; case S_SET: execSet(stmt, pBatch, active); break; + case S_UNSET: + execUnset(stmt, pBatch, active); + break; + case S_IF: + execIf(stmt, pBatch, active); + break; case S_PRIFILT: execPRIFILT(stmt, pBatch, active); break; -- cgit v1.2.3 From 5ab936a92d636390026d466350464ec4182075ac Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 17 Sep 2012 08:32:44 +0200 Subject: new ruleengine: couple of fixes to new code - memory leak if container was tried to replace - too early free due to invalid reference counting - performance improvement for set statement --- runtime/msg.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/runtime/msg.c b/runtime/msg.c index 0cb60436..2f6606bb 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -3752,9 +3752,9 @@ msgAddJSON(msg_t *pM, uchar *name, struct json_object *json) leaf = jsonPathGetLeaf(name, ustrlen(name)); CHKiRet(jsonPathFindParent(pM, name, leaf, &parent, 1)); leafnode = json_object_object_get(parent, (char*)leaf); - if(leafnode == NULL) + if(leafnode == NULL) { json_object_object_add(parent, (char*)leaf, json); - else { + } else { if(json_object_get_type(json) == json_type_object) { CHKiRet(jsonMerge(pM->json, json)); } else { @@ -3765,9 +3765,17 @@ msgAddJSON(msg_t *pM, uchar *name, struct json_object *json) DBGPRINTF("msgAddJSON: trying to update a container " "node with a leaf, name is '%s' - " "forbidden\n", name); + json_object_put(json); ABORT_FINALIZE(RS_RET_INVLD_SETOP); } - json_object_object_del(parent, (char*)leaf); + /* json-c code indicates we can simply replace a + * json type. Unfortunaltely, this is not documented + * as part of the interface spec. We still use it, + * because it speeds up processing. If it does not work + * at some point, use + * json_object_object_del(parent, (char*)leaf); + * before adding. rgerhards, 2012-09-17 + */ json_object_object_add(parent, (char*)leaf, json); } } @@ -3810,7 +3818,6 @@ DBGPRINTF("AAAA: unset found JSON value path '%s', " "leaf '%s', leafnode %p\n", DBGPRINTF("deleting JSON value path '%s', " "leaf '%s', type %d\n", name, leaf, json_object_get_type(leafnode)); - json_object_put(leafnode); json_object_object_del(parent, (char*)leaf); } } -- cgit v1.2.3