Print this page
new smatch

@@ -48,18 +48,58 @@
                 return NULL;
 
         return alloc_string(arg->string->data);
 }
 
+static int xxx_is_array(struct expression *expr)
+{
+        struct symbol *type;
+
+        expr = strip_expr(expr);
+        if (!expr)
+                return 0;
+
+        if (expr->type == EXPR_PREOP && expr->op == '*') {
+                expr = strip_expr(expr->unop);
+                if (!expr)
+                        return 0;
+                if (expr->type == EXPR_BINOP && expr->op == '+')
+                        return 1;
+        }
+
+        if (expr->type != EXPR_BINOP || expr->op != '+')
+                return 0;
+
+        type = get_type(expr->left);
+        if (!type)
+                return 0;
+        if (type->type != SYM_ARRAY && type->type != SYM_PTR)
+                return 0;
+
+        return 1;
+}
+
+static struct expression *xxx_get_array_base(struct expression *expr)
+{
+        if (!xxx_is_array(expr))
+                return NULL;
+        expr = strip_expr(expr);
+        if (expr->type == EXPR_PREOP && expr->op == '*')
+                expr = strip_expr(expr->unop);
+        if (expr->type != EXPR_BINOP || expr->op != '+')
+                return NULL;
+        return strip_parens(expr->left);
+}
+
 static char *get_array_ptr(struct expression *expr)
 {
         struct expression *array;
         struct symbol *type;
         char *name;
         char buf[256];
 
-        array = get_array_base(expr);
+        array = xxx_get_array_base(expr);
 
         if (array) {
                 name = get_member_name(array);
                 if (name)
                         return name;

@@ -76,11 +116,11 @@
                 snprintf(buf, sizeof(buf), "%s[]", name);
                 return alloc_string(buf);
         }
 
         expr = get_assigned_expr(expr);
-        array = get_array_base(expr);
+        array = xxx_get_array_base(expr);
         if (!array)
                 return NULL;
         name = expr_to_var(array);
         if (!name)
                 return NULL;

@@ -139,11 +179,11 @@
 
 char *get_fnptr_name(struct expression *expr)
 {
         char *name;
 
-        if (is_zero(expr))
+        if (expr_is_zero(expr))
                 return NULL;
 
         expr = strip_expr(expr);
 
         /* (*ptrs[0])(a, b, c) is the same as ptrs[0](a, b, c); */

@@ -253,10 +293,16 @@
         if (type->type == SYM_PTR || type->type == SYM_ARRAY) {
                 type = get_real_base_type(type);
                 if (!type)
                         return 0;
         }
+        /* pointer to a pointer */
+        if (type->type == SYM_PTR || type->type == SYM_ARRAY) {
+                type = get_real_base_type(type);
+                if (!type)
+                        return 0;
+        }
         if (type->type == SYM_FN)
                 return 1;
         if (type == &ulong_ctype && expr->type == EXPR_DEREF)
                 return 1;
         if (type == &void_ctype)

@@ -277,11 +323,12 @@
         right = strip_expr(expr->right);
         if (right->type == EXPR_PREOP && right->op == '&')
                 right = strip_expr(right->unop);
 
         if (right->type != EXPR_SYMBOL &&
-            right->type != EXPR_DEREF)
+            right->type != EXPR_DEREF &&
+            right->type != EXPR_CALL)
                 return;
 
         if (!can_hold_function_ptr(right) ||
             !can_hold_function_ptr(expr->left))
                 return;