ACPICA: Fixed a couple memory leaks associated with "implicit return"
[sfrench/cifs-2.6.git] / drivers / acpi / parser / psparse.c
index a02aa62fe1e5324f417e47d6c41bb8d67204311c..68e932f215ea5ef73c407a241a4d11d3367897fa 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -137,6 +137,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
        union acpi_parse_object *next;
        const struct acpi_opcode_info *parent_info;
        union acpi_parse_object *replacement_op = NULL;
+       acpi_status status = AE_OK;
 
        ACPI_FUNCTION_TRACE_PTR(ps_complete_this_op, op);
 
@@ -186,7 +187,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
                        replacement_op =
                            acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP);
                        if (!replacement_op) {
-                               goto allocate_error;
+                               status = AE_NO_MEMORY;
                        }
                        break;
 
@@ -204,12 +205,14 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
                                AML_BUFFER_OP)
                            || (op->common.parent->common.aml_opcode ==
                                AML_PACKAGE_OP)
+                           || (op->common.parent->common.aml_opcode ==
+                               AML_BANK_FIELD_OP)
                            || (op->common.parent->common.aml_opcode ==
                                AML_VAR_PACKAGE_OP)) {
                                replacement_op =
                                    acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP);
                                if (!replacement_op) {
-                                       goto allocate_error;
+                                       status = AE_NO_MEMORY;
                                }
                        } else
                            if ((op->common.parent->common.aml_opcode ==
@@ -224,13 +227,13 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
                                            acpi_ps_alloc_op(op->common.
                                                             aml_opcode);
                                        if (!replacement_op) {
-                                               goto allocate_error;
+                                               status = AE_NO_MEMORY;
+                                       } else {
+                                               replacement_op->named.data =
+                                                   op->named.data;
+                                               replacement_op->named.length =
+                                                   op->named.length;
                                        }
-
-                                       replacement_op->named.data =
-                                           op->named.data;
-                                       replacement_op->named.length =
-                                           op->named.length;
                                }
                        }
                        break;
@@ -240,7 +243,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
                        replacement_op =
                            acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP);
                        if (!replacement_op) {
-                               goto allocate_error;
+                               status = AE_NO_MEMORY;
                        }
                }
 
@@ -300,14 +303,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state,
        /* Now we can actually delete the subtree rooted at Op */
 
        acpi_ps_delete_parse_tree(op);
-       return_ACPI_STATUS(AE_OK);
-
-      allocate_error:
-
-       /* Always delete the subtree, even on error */
-
-       acpi_ps_delete_parse_tree(op);
-       return_ACPI_STATUS(AE_NO_MEMORY);
+       return_ACPI_STATUS(status);
 }
 
 /*******************************************************************************
@@ -349,19 +345,13 @@ acpi_ps_next_parse_state(struct acpi_walk_state *walk_state,
 
                parser_state->aml = walk_state->aml_last_while;
                walk_state->control_state->common.value = FALSE;
-               status = acpi_ds_result_stack_pop(walk_state);
-               if (ACPI_SUCCESS(status)) {
-                       status = AE_CTRL_BREAK;
-               }
+               status = AE_CTRL_BREAK;
                break;
 
        case AE_CTRL_CONTINUE:
 
                parser_state->aml = walk_state->aml_last_while;
-               status = acpi_ds_result_stack_pop(walk_state);
-               if (ACPI_SUCCESS(status)) {
-                       status = AE_CTRL_CONTINUE;
-               }
+               status = AE_CTRL_CONTINUE;
                break;
 
        case AE_CTRL_PENDING:
@@ -383,10 +373,7 @@ acpi_ps_next_parse_state(struct acpi_walk_state *walk_state,
                 * Just close out this package
                 */
                parser_state->aml = acpi_ps_get_next_package_end(parser_state);
-               status = acpi_ds_result_stack_pop(walk_state);
-               if (ACPI_SUCCESS(status)) {
-                       status = AE_CTRL_PENDING;
-               }
+               status = AE_CTRL_PENDING;
                break;
 
        case AE_CTRL_FALSE:
@@ -540,6 +527,11 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
 
                        if ((status == AE_ALREADY_EXISTS) &&
                            (!walk_state->method_desc->method.mutex)) {
+                               ACPI_INFO((AE_INFO,
+                                          "Marking method %4.4s as Serialized because of AE_ALREADY_EXISTS error",
+                                          walk_state->method_node->name.
+                                          ascii));
+
                                /*
                                 * Method tried to create an object twice. The probable cause is
                                 * that the method cannot handle reentrancy.
@@ -596,6 +588,30 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
                                 * The object is deleted
                                 */
                                if (!previous_walk_state->return_desc) {
+                                       /*
+                                        * In slack mode execution, if there is no return value
+                                        * we should implicitly return zero (0) as a default value.
+                                        */
+                                       if (acpi_gbl_enable_interpreter_slack &&
+                                           !previous_walk_state->
+                                           implicit_return_obj) {
+                                               previous_walk_state->
+                                                   implicit_return_obj =
+                                                   acpi_ut_create_internal_object
+                                                   (ACPI_TYPE_INTEGER);
+                                               if (!previous_walk_state->
+                                                   implicit_return_obj) {
+                                                       return_ACPI_STATUS
+                                                           (AE_NO_MEMORY);
+                                               }
+
+                                               previous_walk_state->
+                                                   implicit_return_obj->
+                                                   integer.value = 0;
+                                       }
+
+                                       /* Restart the calling control method */
+
                                        status =
                                            acpi_ds_restart_control_method
                                            (walk_state,
@@ -619,10 +635,12 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
                                            ACPI_WALK_METHOD_RESTART;
                                }
                        } else {
-                               /* On error, delete any return object */
+                               /* On error, delete any return object or implicit return */
 
                                acpi_ut_remove_reference(previous_walk_state->
                                                         return_desc);
+                               acpi_ds_clear_implicit_return
+                                   (previous_walk_state);
                        }
                }