expr_str() currently reports all failure cases as NULL, so callers cannot distinguish invalid recursion depth from allocation failure or later string construction errors.
Return ERR_PTR()-encoded errors from expr_str() and make parse_unary() and parse_expr() propagate them. Clear expr->name before destroying the hist field so the error pointer is not freed as a string. Signed-off-by: Pengpeng Hou <[email protected]> --- kernel/trace/trace_events_hist.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c index f778f060e922..082842e64ccd 100644 --- a/kernel/trace/trace_events_hist.c +++ b/kernel/trace/trace_events_hist.c @@ -1762,11 +1762,11 @@ static char *expr_str(struct hist_field *field, unsigned int level) char *expr __free(kfree) = NULL; if (level > 1) - return NULL; + return ERR_PTR(-EINVAL); expr = kzalloc(MAX_FILTER_STR_VAL, GFP_KERNEL); if (!expr) - return NULL; + return ERR_PTR(-ENOMEM); if (!field->operands[0]) { expr_field_str(field, expr); @@ -1778,8 +1778,8 @@ static char *expr_str(struct hist_field *field, unsigned int level) strcat(expr, "-("); subexpr = expr_str(field->operands[0], ++level); - if (!subexpr) - return NULL; + if (IS_ERR(subexpr)) + return subexpr; strcat(expr, subexpr); strcat(expr, ")"); @@ -1805,7 +1805,7 @@ static char *expr_str(struct hist_field *field, unsigned int level) strcat(expr, "*"); break; default: - return NULL; + return ERR_PTR(-EINVAL); } expr_field_str(field->operands[1], expr); @@ -2624,6 +2624,11 @@ static struct hist_field *parse_unary(struct hist_trigger_data *hist_data, expr->is_signed = operand1->is_signed; expr->operator = FIELD_OP_UNARY_MINUS; expr->name = expr_str(expr, 0); + if (IS_ERR(expr->name)) { + ret = PTR_ERR(expr->name); + expr->name = NULL; + goto free; + } expr->type = kstrdup_const(operand1->type, GFP_KERNEL); if (!expr->type) { ret = -ENOMEM; @@ -2836,6 +2841,11 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data, destroy_hist_field(operand1, 0); expr->name = expr_str(expr, 0); + if (IS_ERR(expr->name)) { + ret = PTR_ERR(expr->name); + expr->name = NULL; + goto free_expr; + } } else { /* The operand sizes should be the same, so just pick one */ expr->size = operand1->size; @@ -2849,6 +2859,11 @@ static struct hist_field *parse_expr(struct hist_trigger_data *hist_data, } expr->name = expr_str(expr, 0); + if (IS_ERR(expr->name)) { + ret = PTR_ERR(expr->name); + expr->name = NULL; + goto free_expr; + } } return expr; -- 2.50.1 (Apple Git-155)
