diff --git a/include/amduat/pel/core.h b/include/amduat/pel/core.h index 27577f5..95ee608 100644 --- a/include/amduat/pel/core.h +++ b/include/amduat/pel/core.h @@ -49,6 +49,8 @@ typedef struct { size_t diagnostics_len; } amduat_pel_execution_result_value_t; +void amduat_pel_execution_result_free(amduat_pel_execution_result_value_t *result); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/src/pel_stack/program_dag/program_dag.c b/src/pel_stack/program_dag/program_dag.c index f7bcb78..e45da67 100644 --- a/src/pel_stack/program_dag/program_dag.c +++ b/src/pel_stack/program_dag/program_dag.c @@ -4,9 +4,11 @@ #include "amduat/pel/opreg_kernel_params.h" #include "amduat/pel/program_dag_desc.h" +#include #include #include #include +#include #include #include @@ -42,13 +44,153 @@ static void amduat_set_result(amduat_pel_execution_result_value_t *result, if (result == NULL) { return; } + amduat_pel_execution_result_free(result); result->pel1_version = 1; result->status = status; result->scheme_ref = amduat_pel_program_dag_scheme_ref(); result->summary.kind = kind; result->summary.status_code = status_code; - result->diagnostics = NULL; - result->diagnostics_len = 0; +} + +static bool amduat_diag_set( + amduat_pel_execution_result_value_t *result, + uint32_t code, + const uint8_t *message, + size_t message_len) { + amduat_pel_diagnostic_entry_t *entries; + uint8_t *message_copy = NULL; + + if (result == NULL) { + return false; + } + + amduat_pel_execution_result_free(result); + + if (message_len != 0) { + message_copy = (uint8_t *)malloc(message_len); + if (message_copy == NULL) { + return false; + } + if (message != NULL) { + memcpy(message_copy, message, message_len); + } + } + + entries = (amduat_pel_diagnostic_entry_t *)calloc(1, sizeof(*entries)); + if (entries == NULL) { + free(message_copy); + return false; + } + + entries[0].code = code; + entries[0].message = amduat_octets(message_copy, message_len); + + result->diagnostics = entries; + result->diagnostics_len = 1; + return true; +} + +static bool amduat_diag_setf( + amduat_pel_execution_result_value_t *result, + uint32_t code, + const char *fmt, + ...) { + va_list ap; + va_list ap_copy; + int needed; + size_t message_len; + uint8_t *buffer; + + if (result == NULL || fmt == NULL) { + return false; + } + + va_start(ap, fmt); + va_copy(ap_copy, ap); + needed = vsnprintf(NULL, 0, fmt, ap_copy); + va_end(ap_copy); + if (needed < 0) { + va_end(ap); + return false; + } + + message_len = (size_t)needed; + buffer = NULL; + if (message_len != 0) { + buffer = (uint8_t *)malloc(message_len + 1); + if (buffer == NULL) { + va_end(ap); + return false; + } + if (vsnprintf((char *)buffer, message_len + 1, fmt, ap) < 0) { + free(buffer); + va_end(ap); + return false; + } + } + va_end(ap); + + if (!amduat_diag_set(result, code, buffer, message_len)) { + free(buffer); + return false; + } + free(buffer); + return true; +} + +enum { + AMDUAT_PEL_DAG_DIAG_STRUCTURAL_INVALID = 0x00010001u, + AMDUAT_PEL_DAG_DIAG_UNKNOWN_OP = 0x00010002u, + AMDUAT_PEL_DAG_DIAG_PARAM_DECODE_FAILED = 0x00010003u, + AMDUAT_PEL_DAG_DIAG_INPUT_ARITY = 0x00010004u, + AMDUAT_PEL_DAG_DIAG_INVALID_INPUT_KIND = 0x00010005u, + AMDUAT_PEL_DAG_DIAG_MISSING_NODE = 0x00010006u, + AMDUAT_PEL_DAG_DIAG_DUPLICATE_NODE = 0x00010007u, + AMDUAT_PEL_DAG_DIAG_CYCLE = 0x00010008u, + AMDUAT_PEL_DAG_DIAG_ROOT_OUTPUT_INDEX = 0x00010009u, + AMDUAT_PEL_DAG_DIAG_INVALID_INPUT_INDEX = 0x00020001u, + AMDUAT_PEL_DAG_DIAG_OUTPUT_INDEX = 0x0001000au, + AMDUAT_PEL_DAG_DIAG_RUNTIME_FAILED = 0x00030001u +}; + +typedef enum { + AMDUAT_PEL_PREP_ERROR_NONE = 0, + AMDUAT_PEL_PREP_ERROR_NULL_NODES, + AMDUAT_PEL_PREP_ERROR_NULL_ROOTS, + AMDUAT_PEL_PREP_ERROR_ROOTS_WITHOUT_NODES, + AMDUAT_PEL_PREP_ERROR_DUPLICATE_NODE, + AMDUAT_PEL_PREP_ERROR_MISSING_NODE, + AMDUAT_PEL_PREP_ERROR_INVALID_INPUT_KIND, + AMDUAT_PEL_PREP_ERROR_INVALID_OP_NAME, + AMDUAT_PEL_PREP_ERROR_INVALID_OP_UTF8, + AMDUAT_PEL_PREP_ERROR_NULL_INPUTS, + AMDUAT_PEL_PREP_ERROR_NULL_PARAMS, + AMDUAT_PEL_PREP_ERROR_UNKNOWN_OP, + AMDUAT_PEL_PREP_ERROR_INPUT_ARITY, + AMDUAT_PEL_PREP_ERROR_PARAM_DECODE, + AMDUAT_PEL_PREP_ERROR_CYCLE, + AMDUAT_PEL_PREP_ERROR_ROOT_MISSING, + AMDUAT_PEL_PREP_ERROR_ROOT_OUTPUT_INDEX +} amduat_pel_program_prep_error_t; + +typedef struct { + amduat_pel_program_prep_error_t kind; + amduat_pel_node_id_t node_id; + uint32_t index; + uint32_t min; + uint32_t max; +} amduat_pel_program_prep_error_info_t; + +static void amduat_pel_prep_error_reset( + amduat_pel_program_prep_error_info_t *error) { + if (error == NULL) { + return; + } + error->kind = AMDUAT_PEL_PREP_ERROR_NONE; + error->node_id = 0; + error->index = 0; + error->min = 0; + error->max = 0; } static bool amduat_utf8_is_valid(amduat_octets_t value) { @@ -130,9 +272,11 @@ static int amduat_find_node_index(const amduat_pel_program_t *program, return -1; } -static bool amduat_build_node_order(const amduat_pel_program_t *program, - size_t *out_order, - bool *out_oom) { +static bool amduat_build_node_order( + const amduat_pel_program_t *program, + size_t *out_order, + bool *out_oom, + amduat_pel_program_prep_error_info_t *out_error) { size_t n; size_t *deps; bool *placed; @@ -141,6 +285,7 @@ static bool amduat_build_node_order(const amduat_pel_program_t *program, if (out_oom != NULL) { *out_oom = false; } + amduat_pel_prep_error_reset(out_error); n = program->nodes_len; deps = NULL; placed = NULL; @@ -164,6 +309,10 @@ static bool amduat_build_node_order(const amduat_pel_program_t *program, size_t j; for (j = i + 1; j < n; ++j) { if (program->nodes[i].id == program->nodes[j].id) { + if (out_error != NULL) { + out_error->kind = AMDUAT_PEL_PREP_ERROR_DUPLICATE_NODE; + out_error->node_id = program->nodes[i].id; + } free(deps); free(placed); return false; @@ -180,12 +329,20 @@ static bool amduat_build_node_order(const amduat_pel_program_t *program, const amduat_pel_dag_input_t *input = &node->inputs[j]; if (input->kind == AMDUAT_PEL_DAG_INPUT_NODE) { if (amduat_find_node_index(program, input->value.node.node_id) < 0) { + if (out_error != NULL) { + out_error->kind = AMDUAT_PEL_PREP_ERROR_MISSING_NODE; + out_error->node_id = input->value.node.node_id; + } free(deps); free(placed); return false; } deps[i] += 1; } else if (input->kind != AMDUAT_PEL_DAG_INPUT_EXTERNAL) { + if (out_error != NULL) { + out_error->kind = AMDUAT_PEL_PREP_ERROR_INVALID_INPUT_KIND; + out_error->node_id = node->id; + } free(deps); free(placed); return false; @@ -209,6 +366,9 @@ static bool amduat_build_node_order(const amduat_pel_program_t *program, } if (best == SIZE_MAX) { + if (out_error != NULL) { + out_error->kind = AMDUAT_PEL_PREP_ERROR_CYCLE; + } free(deps); free(placed); return false; @@ -232,6 +392,9 @@ static bool amduat_build_node_order(const amduat_pel_program_t *program, if (input->kind == AMDUAT_PEL_DAG_INPUT_NODE && input->value.node.node_id == program->nodes[best].id) { if (deps[j] == 0) { + if (out_error != NULL) { + out_error->kind = AMDUAT_PEL_PREP_ERROR_CYCLE; + } free(deps); free(placed); return false; @@ -322,25 +485,37 @@ typedef enum { static amduat_pel_program_prepare_result_t amduat_program_prepare( const amduat_pel_program_t *program, - amduat_pel_program_dag_prepared_t *prepared) { + amduat_pel_program_dag_prepared_t *prepared, + amduat_pel_program_prep_error_info_t *out_error) { size_t i; bool oom; if (program == NULL || prepared == NULL) { + amduat_pel_prep_error_reset(out_error); return AMDUAT_PEL_PROGRAM_PREP_INVALID; } amduat_prepared_reset(prepared); + amduat_pel_prep_error_reset(out_error); if (program->nodes_len > 0 && program->nodes == NULL) { + if (out_error != NULL) { + out_error->kind = AMDUAT_PEL_PREP_ERROR_NULL_NODES; + } return AMDUAT_PEL_PROGRAM_PREP_INVALID; } if (program->roots_len > 0 && program->roots == NULL) { + if (out_error != NULL) { + out_error->kind = AMDUAT_PEL_PREP_ERROR_NULL_ROOTS; + } return AMDUAT_PEL_PROGRAM_PREP_INVALID; } if (program->nodes_len == 0) { if (program->roots_len != 0) { + if (out_error != NULL) { + out_error->kind = AMDUAT_PEL_PREP_ERROR_ROOTS_WITHOUT_NODES; + } return AMDUAT_PEL_PROGRAM_PREP_INVALID; } return AMDUAT_PEL_PROGRAM_PREP_OK; @@ -364,34 +539,65 @@ static amduat_pel_program_prepare_result_t amduat_program_prepare( const amduat_pel_kernel_op_desc_t *desc; if (node->op.name.len > 0 && node->op.name.data == NULL) { + if (out_error != NULL) { + out_error->kind = AMDUAT_PEL_PREP_ERROR_INVALID_OP_NAME; + out_error->node_id = node->id; + } amduat_prepared_free(prepared); return AMDUAT_PEL_PROGRAM_PREP_INVALID; } if (!amduat_utf8_is_valid(node->op.name)) { + if (out_error != NULL) { + out_error->kind = AMDUAT_PEL_PREP_ERROR_INVALID_OP_UTF8; + out_error->node_id = node->id; + } amduat_prepared_free(prepared); return AMDUAT_PEL_PROGRAM_PREP_INVALID; } if (node->inputs_len > 0 && node->inputs == NULL) { + if (out_error != NULL) { + out_error->kind = AMDUAT_PEL_PREP_ERROR_NULL_INPUTS; + out_error->node_id = node->id; + } amduat_prepared_free(prepared); return AMDUAT_PEL_PROGRAM_PREP_INVALID; } if (node->params.len > 0 && node->params.data == NULL) { + if (out_error != NULL) { + out_error->kind = AMDUAT_PEL_PREP_ERROR_NULL_PARAMS; + out_error->node_id = node->id; + } amduat_prepared_free(prepared); return AMDUAT_PEL_PROGRAM_PREP_INVALID; } desc = amduat_pel_kernel_op_lookup(node->op.name, node->op.version); if (desc == NULL) { + if (out_error != NULL) { + out_error->kind = AMDUAT_PEL_PREP_ERROR_UNKNOWN_OP; + out_error->node_id = node->id; + } amduat_prepared_free(prepared); return AMDUAT_PEL_PROGRAM_PREP_INVALID; } if (node->inputs_len < desc->min_inputs || node->inputs_len > desc->max_inputs) { + if (out_error != NULL) { + out_error->kind = AMDUAT_PEL_PREP_ERROR_INPUT_ARITY; + out_error->node_id = node->id; + out_error->index = (uint32_t)node->inputs_len; + out_error->min = (uint32_t)desc->min_inputs; + out_error->max = (uint32_t)desc->max_inputs; + } amduat_prepared_free(prepared); return AMDUAT_PEL_PROGRAM_PREP_INVALID; } if (!amduat_pel_kernel_params_decode(desc, node->params, &prepared->params[i])) { + if (out_error != NULL) { + out_error->kind = AMDUAT_PEL_PREP_ERROR_PARAM_DECODE; + out_error->node_id = node->id; + } amduat_prepared_free(prepared); return AMDUAT_PEL_PROGRAM_PREP_INVALID; } @@ -400,7 +606,7 @@ static amduat_pel_program_prepare_result_t amduat_program_prepare( } oom = false; - if (!amduat_build_node_order(program, prepared->order, &oom)) { + if (!amduat_build_node_order(program, prepared->order, &oom, out_error)) { amduat_prepared_free(prepared); return oom ? AMDUAT_PEL_PROGRAM_PREP_OOM : AMDUAT_PEL_PROGRAM_PREP_INVALID; @@ -415,6 +621,10 @@ static amduat_pel_program_prepare_result_t amduat_program_prepare( int dep_index = amduat_find_node_index(program, input->value.node.node_id); if (dep_index < 0) { + if (out_error != NULL) { + out_error->kind = AMDUAT_PEL_PREP_ERROR_MISSING_NODE; + out_error->node_id = input->value.node.node_id; + } amduat_prepared_free(prepared); return AMDUAT_PEL_PROGRAM_PREP_INVALID; } @@ -433,11 +643,20 @@ static amduat_pel_program_prepare_result_t amduat_program_prepare( for (i = 0; i < program->roots_len; ++i) { int root_index = amduat_find_node_index(program, program->roots[i].node_id); if (root_index < 0) { + if (out_error != NULL) { + out_error->kind = AMDUAT_PEL_PREP_ERROR_ROOT_MISSING; + out_error->node_id = program->roots[i].node_id; + } amduat_prepared_free(prepared); return AMDUAT_PEL_PROGRAM_PREP_INVALID; } if (program->roots[i].output_index >= prepared->ops[root_index]->outputs_len) { + if (out_error != NULL) { + out_error->kind = AMDUAT_PEL_PREP_ERROR_ROOT_OUTPUT_INDEX; + out_error->node_id = program->roots[i].node_id; + out_error->index = program->roots[i].output_index; + } amduat_prepared_free(prepared); return AMDUAT_PEL_PROGRAM_PREP_INVALID; } @@ -451,7 +670,7 @@ bool amduat_pel_program_dag_validate(const amduat_pel_program_t *program) { amduat_pel_program_prepare_result_t prep_result; amduat_prepared_reset(&prepared); - prep_result = amduat_program_prepare(program, &prepared); + prep_result = amduat_program_prepare(program, &prepared, NULL); amduat_prepared_free(&prepared); return prep_result == AMDUAT_PEL_PROGRAM_PREP_OK; } @@ -467,6 +686,7 @@ static bool amduat_pel_program_dag_exec_internal( amduat_pel_program_dag_trace_t *out_trace) { amduat_pel_program_dag_prepared_t prepared; amduat_pel_program_prepare_result_t prep_result; + amduat_pel_program_prep_error_info_t prep_error; amduat_pel_program_dag_node_result_t *node_results; amduat_artifact_t *resolved_inputs; size_t max_inputs; @@ -477,6 +697,7 @@ static bool amduat_pel_program_dag_exec_internal( if (out_outputs == NULL || out_outputs_len == NULL || out_result == NULL) { return false; } + memset(out_result, 0, sizeof(*out_result)); (void)params; *out_outputs = NULL; @@ -487,13 +708,125 @@ static bool amduat_pel_program_dag_exec_internal( } amduat_prepared_reset(&prepared); - prep_result = amduat_program_prepare(program, &prepared); + prep_result = amduat_program_prepare(program, &prepared, &prep_error); if (prep_result == AMDUAT_PEL_PROGRAM_PREP_OOM) { - return false; + amduat_set_result(out_result, AMDUAT_PEL_EXEC_STATUS_RUNTIME_FAILED, + AMDUAT_PEL_EXEC_ERROR_RUNTIME, + AMDUAT_PEL_KERNEL_STATUS_OOM); + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_RUNTIME_FAILED, + "runtime failed: out of memory"); + return true; } if (prep_result != AMDUAT_PEL_PROGRAM_PREP_OK) { amduat_set_result(out_result, AMDUAT_PEL_EXEC_STATUS_INVALID_PROGRAM, AMDUAT_PEL_EXEC_ERROR_PROGRAM, 2); + switch (prep_error.kind) { + case AMDUAT_PEL_PREP_ERROR_NULL_NODES: + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_STRUCTURAL_INVALID, + "invalid program: nodes missing"); + break; + case AMDUAT_PEL_PREP_ERROR_NULL_ROOTS: + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_STRUCTURAL_INVALID, + "invalid program: roots missing"); + break; + case AMDUAT_PEL_PREP_ERROR_ROOTS_WITHOUT_NODES: + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_STRUCTURAL_INVALID, + "invalid program: roots without nodes"); + break; + case AMDUAT_PEL_PREP_ERROR_DUPLICATE_NODE: + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_DUPLICATE_NODE, + "invalid program: duplicate node id %u", + (unsigned int)prep_error.node_id); + break; + case AMDUAT_PEL_PREP_ERROR_MISSING_NODE: + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_MISSING_NODE, + "invalid program: missing node id %u", + (unsigned int)prep_error.node_id); + break; + case AMDUAT_PEL_PREP_ERROR_INVALID_INPUT_KIND: + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_INVALID_INPUT_KIND, + "invalid program: invalid input kind in node %u", + (unsigned int)prep_error.node_id); + break; + case AMDUAT_PEL_PREP_ERROR_INVALID_OP_NAME: + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_STRUCTURAL_INVALID, + "invalid program: op name missing in node %u", + (unsigned int)prep_error.node_id); + break; + case AMDUAT_PEL_PREP_ERROR_INVALID_OP_UTF8: + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_STRUCTURAL_INVALID, + "invalid program: op name utf8 invalid in node %u", + (unsigned int)prep_error.node_id); + break; + case AMDUAT_PEL_PREP_ERROR_NULL_INPUTS: + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_STRUCTURAL_INVALID, + "invalid program: inputs missing in node %u", + (unsigned int)prep_error.node_id); + break; + case AMDUAT_PEL_PREP_ERROR_NULL_PARAMS: + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_STRUCTURAL_INVALID, + "invalid program: params missing in node %u", + (unsigned int)prep_error.node_id); + break; + case AMDUAT_PEL_PREP_ERROR_UNKNOWN_OP: + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_UNKNOWN_OP, + "invalid program: unknown op in node %u", + (unsigned int)prep_error.node_id); + break; + case AMDUAT_PEL_PREP_ERROR_INPUT_ARITY: + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_INPUT_ARITY, + "invalid program: input arity in node %u " + "(inputs=%u min=%u max=%u)", + (unsigned int)prep_error.node_id, + (unsigned int)prep_error.index, + (unsigned int)prep_error.min, + (unsigned int)prep_error.max); + break; + case AMDUAT_PEL_PREP_ERROR_PARAM_DECODE: + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_PARAM_DECODE_FAILED, + "invalid program: param decode failed in node %u", + (unsigned int)prep_error.node_id); + break; + case AMDUAT_PEL_PREP_ERROR_CYCLE: + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_CYCLE, + "invalid program: dependency cycle"); + break; + case AMDUAT_PEL_PREP_ERROR_ROOT_MISSING: + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_MISSING_NODE, + "invalid program: root node missing id %u", + (unsigned int)prep_error.node_id); + break; + case AMDUAT_PEL_PREP_ERROR_ROOT_OUTPUT_INDEX: + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_ROOT_OUTPUT_INDEX, + "invalid program: root output index out of range " + "for node %u (index=%u)", + (unsigned int)prep_error.node_id, + (unsigned int)prep_error.index); + break; + case AMDUAT_PEL_PREP_ERROR_NONE: + default: + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_STRUCTURAL_INVALID, + "invalid program: structural validation failed"); + break; + } amduat_prepared_free(&prepared); return true; } @@ -516,6 +849,9 @@ static bool amduat_pel_program_dag_exec_internal( if (needs_inputs) { amduat_set_result(out_result, AMDUAT_PEL_EXEC_STATUS_INVALID_INPUTS, AMDUAT_PEL_EXEC_ERROR_INPUTS, 3); + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_INVALID_INPUT_INDEX, + "invalid inputs: missing external inputs"); amduat_prepared_free(&prepared); return true; } @@ -532,7 +868,13 @@ static bool amduat_pel_program_dag_exec_internal( program->nodes_len, sizeof(*node_results)); if (node_results == NULL) { amduat_prepared_free(&prepared); - return false; + amduat_set_result(out_result, AMDUAT_PEL_EXEC_STATUS_RUNTIME_FAILED, + AMDUAT_PEL_EXEC_ERROR_RUNTIME, + AMDUAT_PEL_KERNEL_STATUS_OOM); + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_RUNTIME_FAILED, + "runtime failed: out of memory"); + return true; } for (i = 0; i < program->nodes_len; ++i) { node_results[i].status = AMDUAT_PEL_NODE_TRACE_SKIPPED; @@ -553,7 +895,13 @@ static bool amduat_pel_program_dag_exec_internal( if (resolved_inputs == NULL) { amduat_node_results_free(node_results, program->nodes_len); amduat_prepared_free(&prepared); - return false; + amduat_set_result(out_result, AMDUAT_PEL_EXEC_STATUS_RUNTIME_FAILED, + AMDUAT_PEL_EXEC_ERROR_RUNTIME, + AMDUAT_PEL_KERNEL_STATUS_OOM); + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_RUNTIME_FAILED, + "runtime failed: out of memory"); + return true; } } @@ -569,6 +917,10 @@ static bool amduat_pel_program_dag_exec_internal( if (input->value.external.input_index >= inputs_len) { amduat_set_result(out_result, AMDUAT_PEL_EXEC_STATUS_INVALID_INPUTS, AMDUAT_PEL_EXEC_ERROR_INPUTS, 3); + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_INVALID_INPUT_INDEX, + "invalid inputs: missing input index %u", + (unsigned int)input->value.external.input_index); free(resolved_inputs); goto finish; } @@ -581,6 +933,11 @@ static bool amduat_pel_program_dag_exec_internal( node_results[dep_index].outputs_len) { amduat_set_result(out_result, AMDUAT_PEL_EXEC_STATUS_INVALID_PROGRAM, AMDUAT_PEL_EXEC_ERROR_PROGRAM, 2); + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_OUTPUT_INDEX, + "invalid program: node %u output index %u out of range", + (unsigned int)input->value.node.node_id, + (unsigned int)input->value.node.output_index); free(resolved_inputs); goto finish; } @@ -589,6 +946,10 @@ static bool amduat_pel_program_dag_exec_internal( } else { amduat_set_result(out_result, AMDUAT_PEL_EXEC_STATUS_INVALID_PROGRAM, AMDUAT_PEL_EXEC_ERROR_PROGRAM, 2); + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_INVALID_INPUT_KIND, + "invalid program: invalid input kind in node %u", + (unsigned int)node->id); free(resolved_inputs); goto finish; } @@ -601,6 +962,7 @@ static bool amduat_pel_program_dag_exec_internal( &node_results[node_index].outputs_len, &status_code)) { if (status_code == AMDUAT_PEL_KERNEL_STATUS_OOM) { free(resolved_inputs); + resolved_inputs = NULL; goto oom_finish; } if (status_code == 2 || status_code == 3 || status_code == 0) { @@ -611,6 +973,11 @@ static bool amduat_pel_program_dag_exec_internal( any_node_executed = true; amduat_set_result(out_result, AMDUAT_PEL_EXEC_STATUS_RUNTIME_FAILED, AMDUAT_PEL_EXEC_ERROR_RUNTIME, status_code); + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_RUNTIME_FAILED, + "runtime failed: node %u status_code %u", + (unsigned int)node->id, + (unsigned int)status_code); free(resolved_inputs); goto finish; } @@ -624,6 +991,7 @@ static bool amduat_pel_program_dag_exec_internal( program->roots_len, sizeof(**out_outputs)); if (*out_outputs == NULL) { free(resolved_inputs); + resolved_inputs = NULL; goto oom_finish; } } @@ -635,6 +1003,12 @@ static bool amduat_pel_program_dag_exec_internal( node_results[root_index].outputs_len) { amduat_set_result(out_result, AMDUAT_PEL_EXEC_STATUS_INVALID_PROGRAM, AMDUAT_PEL_EXEC_ERROR_PROGRAM, 2); + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_ROOT_OUTPUT_INDEX, + "invalid program: root output index out of range " + "for node %u (index=%u)", + (unsigned int)program->roots[i].node_id, + (unsigned int)program->roots[i].output_index); amduat_pel_program_dag_free_outputs(*out_outputs, program->roots_len); *out_outputs = NULL; @@ -651,6 +1025,7 @@ static bool amduat_pel_program_dag_exec_internal( *out_outputs = NULL; *out_outputs_len = 0; free(resolved_inputs); + resolved_inputs = NULL; goto oom_finish; } } @@ -681,6 +1056,19 @@ finish: return true; oom_finish: + amduat_set_result(out_result, AMDUAT_PEL_EXEC_STATUS_RUNTIME_FAILED, + AMDUAT_PEL_EXEC_ERROR_RUNTIME, + AMDUAT_PEL_KERNEL_STATUS_OOM); + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_RUNTIME_FAILED, + "runtime failed: out of memory"); + if (out_outputs != NULL && *out_outputs != NULL) { + amduat_pel_program_dag_free_outputs(*out_outputs, *out_outputs_len); + *out_outputs = NULL; + *out_outputs_len = 0; + } + free(resolved_inputs); + resolved_inputs = NULL; if (wants_trace) { out_trace->any_node_executed = any_node_executed; if (any_node_executed) { @@ -695,7 +1083,7 @@ oom_finish: node_results = NULL; } amduat_prepared_free(&prepared); - return false; + return true; } bool amduat_pel_program_dag_exec( diff --git a/src/pel_stack/run.c b/src/pel_stack/run.c index 88851dc..8209fa9 100644 --- a/src/pel_stack/run.c +++ b/src/pel_stack/run.c @@ -6,8 +6,126 @@ #include "amduat/pel/program_dag.h" #include "amduat/pel/program_dag_desc.h" +#include +#include +#include +#include +#include +#include #include +void amduat_pel_execution_result_free( + amduat_pel_execution_result_value_t *result) { + size_t i; + + if (result == NULL) { + return; + } + + if (result->diagnostics != NULL) { + for (i = 0; i < result->diagnostics_len; ++i) { + free((void *)result->diagnostics[i].message.data); + result->diagnostics[i].message.data = NULL; + result->diagnostics[i].message.len = 0; + } + } + free(result->diagnostics); + result->diagnostics = NULL; + result->diagnostics_len = 0; +} + +static bool amduat_diag_set( + amduat_pel_execution_result_value_t *result, + uint32_t code, + const uint8_t *message, + size_t message_len) { + amduat_pel_diagnostic_entry_t *entries; + uint8_t *message_copy = NULL; + + if (result == NULL) { + return false; + } + + amduat_pel_execution_result_free(result); + + if (message_len != 0) { + message_copy = (uint8_t *)malloc(message_len); + if (message_copy == NULL) { + return false; + } + if (message != NULL) { + memcpy(message_copy, message, message_len); + } + } + + entries = (amduat_pel_diagnostic_entry_t *)calloc(1, sizeof(*entries)); + if (entries == NULL) { + free(message_copy); + return false; + } + + entries[0].code = code; + entries[0].message = amduat_octets(message_copy, message_len); + + result->diagnostics = entries; + result->diagnostics_len = 1; + return true; +} + +static bool amduat_diag_setf( + amduat_pel_execution_result_value_t *result, + uint32_t code, + const char *fmt, + ...) { + va_list ap; + va_list ap_copy; + int needed; + size_t message_len; + uint8_t *buffer; + + if (result == NULL || fmt == NULL) { + return false; + } + + va_start(ap, fmt); + va_copy(ap_copy, ap); + needed = vsnprintf(NULL, 0, fmt, ap_copy); + va_end(ap_copy); + if (needed < 0) { + va_end(ap); + return false; + } + + message_len = (size_t)needed; + buffer = NULL; + if (message_len != 0) { + buffer = (uint8_t *)malloc(message_len + 1); + if (buffer == NULL) { + va_end(ap); + return false; + } + if (vsnprintf((char *)buffer, message_len + 1, fmt, ap) < 0) { + free(buffer); + va_end(ap); + return false; + } + } + va_end(ap); + + if (!amduat_diag_set(result, code, buffer, message_len)) { + free(buffer); + return false; + } + free(buffer); + return true; +} + +enum { + AMDUAT_PEL_DAG_DIAG_DECODE_FAILED = 0x00010001u, + AMDUAT_PEL_DAG_DIAG_WRONG_TYPE_TAG = 0x00010002u, + AMDUAT_PEL_DAG_DIAG_INPUTS_MISSING = 0x00020001u +}; + bool amduat_pel_surf_run_with_result(amduat_asl_store_t *store, amduat_reference_t scheme_ref, amduat_reference_t program_ref, @@ -63,20 +181,21 @@ static bool amduat_pel_exec_program_bytes_unchecked( if (out_outputs == NULL || out_outputs_len == NULL || out_result == NULL) { return false; } + memset(out_result, 0, sizeof(*out_result)); if (inputs_len != 0 && inputs == NULL) { out_result->pel1_version = 1; out_result->status = AMDUAT_PEL_EXEC_STATUS_INVALID_INPUTS; out_result->scheme_ref = amduat_pel_program_dag_scheme_ref(); out_result->summary.kind = AMDUAT_PEL_EXEC_ERROR_INPUTS; out_result->summary.status_code = 3; - out_result->diagnostics = NULL; - out_result->diagnostics_len = 0; + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_INPUTS_MISSING, + "invalid inputs: missing external inputs"); return true; } *out_outputs = NULL; *out_outputs_len = 0; - memset(out_result, 0, sizeof(*out_result)); memset(&program, 0, sizeof(program)); decode_status = amduat_enc_pel_program_dag_decode_v1_ex(program_bytes, @@ -90,8 +209,9 @@ static bool amduat_pel_exec_program_bytes_unchecked( out_result->scheme_ref = amduat_pel_program_dag_scheme_ref(); out_result->summary.kind = AMDUAT_PEL_EXEC_ERROR_PROGRAM; out_result->summary.status_code = 2; - out_result->diagnostics = NULL; - out_result->diagnostics_len = 0; + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_DECODE_FAILED, + "invalid program: decode failed"); return true; } @@ -116,6 +236,7 @@ bool amduat_pel_exec_program_artifact(amduat_artifact_t program_artifact, if (out_outputs == NULL || out_outputs_len == NULL || out_result == NULL) { return false; } + memset(out_result, 0, sizeof(*out_result)); if (!program_artifact.has_type_tag || program_artifact.type_tag.tag_id != AMDUAT_PEL_TYPE_TAG_PROGRAM_DAG_1) { @@ -124,8 +245,9 @@ bool amduat_pel_exec_program_artifact(amduat_artifact_t program_artifact, out_result->scheme_ref = amduat_pel_program_dag_scheme_ref(); out_result->summary.kind = AMDUAT_PEL_EXEC_ERROR_PROGRAM; out_result->summary.status_code = 2; - out_result->diagnostics = NULL; - out_result->diagnostics_len = 0; + amduat_diag_setf(out_result, + AMDUAT_PEL_DAG_DIAG_WRONG_TYPE_TAG, + "invalid program: wrong type tag"); *out_outputs = NULL; *out_outputs_len = 0; return true; diff --git a/src/pel_stack/surf/surf.c b/src/pel_stack/surf/surf.c index 63fd716..c983b4d 100644 --- a/src/pel_stack/surf/surf.c +++ b/src/pel_stack/surf/surf.c @@ -6,9 +6,11 @@ #include "amduat/pel/program_dag.h" #include "amduat/pel/program_dag_desc.h" +#include #include #include #include +#include #include #include @@ -45,6 +47,66 @@ static void amduat_init_core_result(amduat_pel_execution_result_value_t *result, result->diagnostics_len = 0; } +static bool amduat_surf_diag_setf( + amduat_pel_execution_result_value_t *result, + uint32_t code, + const char *fmt, + ...) { + va_list ap; + va_list ap_copy; + int needed; + size_t message_len; + uint8_t *buffer; + amduat_pel_diagnostic_entry_t *entries; + + if (result == NULL || fmt == NULL) { + return false; + } + + amduat_pel_execution_result_free(result); + + va_start(ap, fmt); + va_copy(ap_copy, ap); + needed = vsnprintf(NULL, 0, fmt, ap_copy); + va_end(ap_copy); + if (needed < 0) { + va_end(ap); + return false; + } + + message_len = (size_t)needed; + buffer = NULL; + if (message_len != 0) { + buffer = (uint8_t *)malloc(message_len + 1); + if (buffer == NULL) { + va_end(ap); + return false; + } + if (vsnprintf((char *)buffer, message_len + 1, fmt, ap) < 0) { + free(buffer); + va_end(ap); + return false; + } + } + va_end(ap); + + entries = (amduat_pel_diagnostic_entry_t *)calloc(1, sizeof(*entries)); + if (entries == NULL) { + free(buffer); + return false; + } + entries[0].code = code; + entries[0].message = amduat_octets(buffer, message_len); + result->diagnostics = entries; + result->diagnostics_len = 1; + return true; +} + +enum { + AMDUAT_PEL_DAG_DIAG_DECODE_FAILED = 0x00010001u, + AMDUAT_PEL_DAG_DIAG_WRONG_TYPE_TAG = 0x00010002u +}; + static bool amduat_store_error_map(amduat_asl_store_error_t err, amduat_pel_store_error_code_t *out_code) { if (out_code == NULL) { @@ -401,6 +463,9 @@ bool amduat_pel_surf_run(amduat_asl_store_t *store, amduat_init_core_result(&core_result, scheme_ref, AMDUAT_PEL_EXEC_STATUS_INVALID_PROGRAM, AMDUAT_PEL_EXEC_ERROR_PROGRAM, 2); + amduat_surf_diag_setf(&core_result, + AMDUAT_PEL_DAG_DIAG_WRONG_TYPE_TAG, + "invalid program: wrong type tag"); } else { amduat_pel_program_dag_decode_status_t decode_status = amduat_enc_pel_program_dag_decode_v1_ex(program_artifact.bytes, @@ -420,6 +485,9 @@ bool amduat_pel_surf_run(amduat_asl_store_t *store, amduat_init_core_result(&core_result, scheme_ref, AMDUAT_PEL_EXEC_STATUS_INVALID_PROGRAM, AMDUAT_PEL_EXEC_ERROR_PROGRAM, 2); + amduat_surf_diag_setf(&core_result, + AMDUAT_PEL_DAG_DIAG_DECODE_FAILED, + "invalid program: decode failed"); } else { program_decoded = true; const amduat_artifact_t *params_arg = @@ -495,6 +563,7 @@ bool amduat_pel_surf_run(amduat_asl_store_t *store, amduat_artifact_free(¶ms_artifact); } amduat_pel_program_dag_free_outputs(outputs, outputs_len); + amduat_pel_execution_result_free(&core_result); return true; cleanup: @@ -511,5 +580,6 @@ cleanup: amduat_artifact_free(¶ms_artifact); } amduat_pel_program_dag_free_outputs(outputs, outputs_len); + amduat_pel_execution_result_free(&core_result); return false; } diff --git a/src/tools/amduat_pel_cli.c b/src/tools/amduat_pel_cli.c index a039993..58ea478 100644 --- a/src/tools/amduat_pel_cli.c +++ b/src/tools/amduat_pel_cli.c @@ -672,6 +672,8 @@ static int amduat_pel_cli_cmd_exec(int argc, FILE *out_stream = NULL; int i; + memset(&result, 0, sizeof(result)); + if (global == NULL) { return AMDUAT_PEL_CLI_EXIT_USAGE; } @@ -924,6 +926,7 @@ exec_cleanup: if (outputs != NULL) { amduat_pel_program_dag_free_outputs(outputs, outputs_len); } + amduat_pel_execution_result_free(&result); if (inputs != NULL) { for (i = 0; i < (int)input_paths_len; ++i) { amduat_asl_artifact_free(&inputs[i]); diff --git a/tests/pel/test_pel_program_dag_exec.c b/tests/pel/test_pel_program_dag_exec.c index c2bb77f..31332fb 100644 --- a/tests/pel/test_pel_program_dag_exec.c +++ b/tests/pel/test_pel_program_dag_exec.c @@ -58,6 +58,8 @@ static int test_valid_program(void) { amduat_octets_t const_params; int exit_code = 1; + memset(&result, 0, sizeof(result)); + const_params = make_const_params(const_bytes, sizeof(const_bytes)); if (const_params.data == NULL) { fprintf(stderr, "const params alloc failed\n"); @@ -117,6 +119,7 @@ static int test_valid_program(void) { cleanup: amduat_pel_program_dag_free_outputs(outputs, outputs_len); + amduat_pel_execution_result_free(&result); free((void *)const_params.data); return exit_code; } @@ -132,6 +135,10 @@ static int test_invalid_program_cycle(void) { amduat_pel_execution_result_value_t result; const char op_concat[] = "pel.bytes.concat"; + memset(&result, 0, sizeof(result)); + + memset(&result, 0, sizeof(result)); + node1_inputs[0].kind = AMDUAT_PEL_DAG_INPUT_NODE; node1_inputs[0].value.node.node_id = 2; node1_inputs[0].value.node.output_index = 0; @@ -165,6 +172,7 @@ static int test_invalid_program_cycle(void) { if (!amduat_pel_program_dag_exec(&program, NULL, 0, NULL, &outputs, &outputs_len, &result)) { fprintf(stderr, "exec failed\n"); + amduat_pel_execution_result_free(&result); return 1; } @@ -173,10 +181,12 @@ static int test_invalid_program_cycle(void) { result.summary.status_code != 2) { fprintf(stderr, "unexpected invalid program status\n"); amduat_pel_program_dag_free_outputs(outputs, outputs_len); + amduat_pel_execution_result_free(&result); return 1; } amduat_pel_program_dag_free_outputs(outputs, outputs_len); + amduat_pel_execution_result_free(&result); return 0; } @@ -192,6 +202,8 @@ static int test_invalid_params(void) { const char op_concat[] = "pel.bytes.concat"; uint8_t bad_params[] = {0x01u}; + memset(&result, 0, sizeof(result)); + node_inputs[0].kind = AMDUAT_PEL_DAG_INPUT_EXTERNAL; node_inputs[0].value.external.input_index = 0; @@ -215,6 +227,7 @@ static int test_invalid_params(void) { if (!amduat_pel_program_dag_exec(&program, inputs, 1, NULL, &outputs, &outputs_len, &result)) { fprintf(stderr, "exec failed\n"); + amduat_pel_execution_result_free(&result); return 1; } @@ -223,10 +236,12 @@ static int test_invalid_params(void) { result.summary.status_code != 2) { fprintf(stderr, "unexpected invalid params status\n"); amduat_pel_program_dag_free_outputs(outputs, outputs_len); + amduat_pel_execution_result_free(&result); return 1; } amduat_pel_program_dag_free_outputs(outputs, outputs_len); + amduat_pel_execution_result_free(&result); return 0; } @@ -264,6 +279,7 @@ static int test_invalid_input_index(void) { if (!amduat_pel_program_dag_exec(&program, inputs, 1, NULL, &outputs, &outputs_len, &result)) { fprintf(stderr, "exec failed\n"); + amduat_pel_execution_result_free(&result); return 1; } @@ -272,10 +288,12 @@ static int test_invalid_input_index(void) { result.summary.status_code != 3) { fprintf(stderr, "unexpected invalid inputs status\n"); amduat_pel_program_dag_free_outputs(outputs, outputs_len); + amduat_pel_execution_result_free(&result); return 1; } amduat_pel_program_dag_free_outputs(outputs, outputs_len); + amduat_pel_execution_result_free(&result); return 0; }