classifier: Allow classifier_for_each_match() callback to free the rule.
authorBen Pfaff <blp@nicira.com>
Wed, 4 Mar 2009 21:26:19 +0000 (13:26 -0800)
committerBen Pfaff <blp@nicira.com>
Wed, 4 Mar 2009 21:29:05 +0000 (13:29 -0800)
classifier_for_each_match() would segfault if the callback passed in
deleted and freed the rule in question, because it accessed the rule after
calling the callback.  This commit should fix the problem.

Thanks to Natasha for reporting the problem.

lib/classifier.c

index 5081823dad93d221065a06fa3c8c0bd6633831b1..ddc5bf0eed8ce32dfca9d8a545c145785eef21a7 100644 (file)
@@ -347,6 +347,9 @@ classifier_for_each_match(const struct classifier *cls,
                           const struct cls_rule *target,
                           int include, cls_cb_func *cb, void *aux)
 {
+    struct cls_rule *prev_rule;
+
+    prev_rule = NULL;
     if (include & CLS_INC_WILD) {
         const struct hmap *table;
         for (table = &cls->tables[0]; table < &cls->tables[CLS_N_FIELDS];
@@ -361,7 +364,10 @@ classifier_for_each_match(const struct classifier *cls,
                 LIST_FOR_EACH (pos, struct cls_rule, node.list,
                                &bucket->rules) {
                     if (rules_match_1wild(pos, target, 0)) {
-                        cb(pos, aux);
+                        if (prev_rule) {
+                            cb(prev_rule, aux);
+                        }
+                        prev_rule = pos;
                     }
                 }
             }
@@ -374,7 +380,10 @@ classifier_for_each_match(const struct classifier *cls,
             HMAP_FOR_EACH (rule, struct cls_rule, node.hmap,
                            &cls->exact_table) {
                 if (rules_match_1wild(rule, target, 0)) {
-                    cb(rule, aux);
+                    if (prev_rule) {
+                        cb(prev_rule, aux);
+                    }
+                    prev_rule = rule;
                 }
             }
         } else {
@@ -384,10 +393,16 @@ classifier_for_each_match(const struct classifier *cls,
             struct cls_rule *rule = search_exact_table(cls, hash,
                                                        &target->flow);
             if (rule) {
-                cb(rule, aux);
+                if (prev_rule) {
+                    cb(prev_rule, aux);
+                }
+                prev_rule = rule;
             }
         }
     }
+    if (prev_rule) {
+        cb(prev_rule, aux);
+    }
 }
 
 void