Fix tests for device dependent info, convert to strndup, fix out of bounds access
| | |
| | | #endif |
| | | |
| | | #ifndef USE_DEVICE_DEPENDENT_ERROR_INFORMATION |
| | | #define USE_DEVICE_DEPENDENT_ERROR_INFORMATION 0 |
| | | #define USE_DEVICE_DEPENDENT_ERROR_INFORMATION SYSTEM_TYPE |
| | | #endif |
| | | |
| | | #if USE_DEVICE_DEPENDENT_ERROR_INFORMATION |
| | | #ifndef USE_MEMORY_ALLOCATION_FREE |
| | | #define USE_MEMORY_ALLOCATION_FREE 1 |
| | | #endif |
| | | #endif |
| | | |
| | | |
| | | |
| | | #ifndef USE_COMMAND_TAGS |
| | | #define USE_COMMAND_TAGS 1 |
| | |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | #define SCPIDEFINE_DESCRIPTION_MAX_PARTS 2 |
| | | #define SCPIDEFINE_strdup(h, s) strdup((s)) |
| | | #define SCPIDEFINE_strndup(h, s, l) strndup((s), (l)) |
| | | #define SCPIDEFINE_free(h, s, r) free((s)) |
| | | #else |
| | | #define SCPIDEFINE_DESCRIPTION_MAX_PARTS 3 |
| | | #define SCPIDEFINE_strdup(h, s) OUR_strdup((h), (s)) |
| | | #define SCPIDEFINE_strndup(h, s, l) OUR_strndup((h), (s), (l)) |
| | | #define SCPIDEFINE_free(h, s, r) OUR_free((h), (s), (r)) |
| | | #define SCPIDEFINE_get_parts(h, s, l1, s2, l2) OUR_get_parts((h), (s), (l1), (s2), (l2)) |
| | | #endif |
| | | #else |
| | | #define SCPIDEFINE_DESCRIPTION_MAX_PARTS 1 |
| | | #define SCPIDEFINE_strdup(h, s) NULL |
| | | #define SCPIDEFINE_strdup(h, s, l) NULL |
| | | #define SCPIDEFINE_free(h, s, r) (void) |
| | | #endif |
| | | |
| | |
| | | void SCPI_ErrorInit(scpi_t * context, scpi_error_t * data, int16_t size); |
| | | void SCPI_ErrorClear(scpi_t * context); |
| | | scpi_bool_t SCPI_ErrorPop(scpi_t * context, scpi_error_t * error); |
| | | void SCPI_ErrorPushEx(scpi_t * context, int16_t err, char * info); |
| | | void SCPI_ErrorPushEx(scpi_t * context, int16_t err, char * info, size_t info_len); |
| | | void SCPI_ErrorPush(scpi_t * context, int16_t err); |
| | | int32_t SCPI_ErrorCount(scpi_t * context); |
| | | const char * SCPI_ErrorTranslate(int16_t err); |
| | |
| | | |
| | | struct _scpi_error_t { |
| | | int16_t error_code; |
| | | const char * device_dependent_info; |
| | | char * device_dependent_info; |
| | | }; |
| | | typedef struct _scpi_error_t scpi_error_t; |
| | | |
| | |
| | | error_value.device_dependent_info = info; |
| | | if (!fifo_add(&context->error_queue, &error_value)) { |
| | | fifo_remove_last(&context->error_queue, &error_value); |
| | | // TODO free device_dependent_info |
| | | SCPIDEFINE_free(&context->error_info_heap, error_value.device_dependent_info, false); |
| | | error_value.error_code = SCPI_ERROR_QUEUE_OVERFLOW; |
| | | error_value.device_dependent_info = NULL; |
| | | fifo_add(&context->error_queue, &error_value); |
| | |
| | | * @param context - scpi context |
| | | * @param err - error number |
| | | */ |
| | | void SCPI_ErrorPushEx(scpi_t * context, int16_t err, char * info) { |
| | | void SCPI_ErrorPushEx(scpi_t * context, int16_t err, char * info, size_t info_len) { |
| | | int i; |
| | | char * info_ptr = NULL; |
| | | |
| | | #if USE_DEVICE_DEPENDENT_ERROR_INFORMATION |
| | | if (info) { |
| | | info_ptr = SCPIDEFINE_strdup(&context->error_info_heap, info); |
| | | info_ptr = SCPIDEFINE_strndup(&context->error_info_heap, info, info_len); |
| | | } |
| | | #endif |
| | | |
| | |
| | | * @param err - error number |
| | | */ |
| | | void SCPI_ErrorPush(scpi_t * context, int16_t err) { |
| | | SCPI_ErrorPushEx(context, err, NULL); |
| | | SCPI_ErrorPushEx(context, err, NULL, 0); |
| | | return; |
| | | } |
| | | |
| | |
| | | result &= processCommand(context); |
| | | cmd_prev = state->programHeader; |
| | | } else { |
| | | /* test */ |
| | | /* place undefined header with error */ |
| | | data[r ? (r - 1) : r] = 0; |
| | | SCPI_ErrorPushEx(context, SCPI_ERROR_UNDEFINED_HEADER, data); |
| | | //SCPI_ErrorPush(context, SCPI_ERROR_UNDEFINED_HEADER); |
| | | /* calculate length of errornouse header and trim \r\n */ |
| | | size_t r2 = r; |
| | | while(r2 > 0 && (data[r2 - 1] == '\r' || data[r2 - 1] == '\n')) r2--; |
| | | SCPI_ErrorPushEx(context, SCPI_ERROR_UNDEFINED_HEADER, data, r2); |
| | | result = FALSE; |
| | | } |
| | | } |
| | |
| | | result += writeDelimiter(context); |
| | | result += writeData(context, "\"", 1); |
| | | |
| | | for (i = 0; data[i] && outputlimit && (i < SCPIDEFINE_DESCRIPTION_MAX_PARTS); i++) { |
| | | for (i = 0; (i < SCPIDEFINE_DESCRIPTION_MAX_PARTS) && data[i] && outputlimit; i++) { |
| | | if (i == 1) { |
| | | result += writeSemicolon(context); |
| | | outputlimit -= 1; |
| | |
| | | * @param s - current pointer of duplication string |
| | | * @return - pointer of duplicated string or NULL, if duplicate is not possible. |
| | | */ |
| | | char * OUR_strdup(scpi_error_info_heap_t * heap, const char *s) { |
| | | char * OUR_strndup(scpi_error_info_heap_t * heap, const char *s, size_t n) { |
| | | if (!s || !heap) { |
| | | return NULL; |
| | | } |
| | |
| | | return NULL; |
| | | } |
| | | |
| | | size_t len = strlen(s) + 1; // additional '\0' at end |
| | | size_t len = SCPIDEFINE_strnlen(s, n) + 1; // additional '\0' at end |
| | | if (len > heap->count) { |
| | | return NULL; |
| | | } |
| | | char * ptrs = s; |
| | | const char * ptrs = s; |
| | | char * head = &heap->data[heap->wr]; |
| | | size_t rem = heap->size - (&heap->data[heap->wr] - heap->data); |
| | | size_t sstp = 0; |
| | | |
| | | if (len >= rem) { |
| | | memcpy(&heap->data[heap->wr], s, rem); |
| | |
| | | * @param s - pointer of duplicate string |
| | | * @param rollback - backward write pointer in heap |
| | | */ |
| | | void OUR_free(scpi_error_info_heap_t * heap, const char * s, scpi_bool_t rollback) { |
| | | void OUR_free(scpi_error_info_heap_t * heap, char * s, scpi_bool_t rollback) { |
| | | |
| | | if (!s) return; |
| | | |
| | | char * data_add; |
| | | size_t len[2]; |
| | | |
| | | if (!OUR_get_parts(heap, s, &len[0], &data_add, &len[1])) return; |
| | | if (!OUR_get_parts(heap, s, &len[0], (const char **)&data_add, &len[1])) return; |
| | | |
| | | if (data_add) { |
| | | len[1]++; |
| | |
| | | #endif |
| | | |
| | | #if USE_DEVICE_DEPENDENT_ERROR_INFORMATION && !USE_MEMORY_ALLOCATION_FREE |
| | | char * OUR_strdup(scpi_error_info_heap_t * heap, const char *s) LOCAL; |
| | | void OUR_free(scpi_error_info_heap_t * heap, const char *s, scpi_bool_t rollback) LOCAL; |
| | | char * OUR_strndup(scpi_error_info_heap_t * heap, const char *s, size_t n) LOCAL; |
| | | void OUR_free(scpi_error_info_heap_t * heap, char *s, scpi_bool_t rollback) LOCAL; |
| | | scpi_bool_t OUR_get_parts(scpi_error_info_heap_t * heap, const char *s1, size_t * len1, const char ** s2, size_t * len2) LOCAL; |
| | | #endif |
| | | |
| | |
| | | TEST_IEEE4882("*ESR?\r\n", "0\r\n"); |
| | | |
| | | TEST_IEEE4882("SYST:ERR:COUNT?\r\n", "1\r\n"); |
| | | #if USE_DEVICE_DEPENDENT_ERROR_INFORMATION |
| | | TEST_IEEE4882("SYST:ERR:NEXT?\r\n", "-113,\"Undefined header;ABCD\"\r\n"); |
| | | #else /* USE_DEVICE_DEPENDENT_ERROR_INFORMATION */ |
| | | TEST_IEEE4882("SYST:ERR:NEXT?\r\n", "-113,\"Undefined header\"\r\n"); |
| | | #endif /* USE_DEVICE_DEPENDENT_ERROR_INFORMATION */ |
| | | TEST_IEEE4882("SYST:ERR:NEXT?\r\n", "0,\"No error\"\r\n"); |
| | | |
| | | TEST_IEEE4882("*STB?\r\n", "0\r\n"); /* Error queue is now empty */ |
| | |
| | | CU_ASSERT_EQUAL(srq_val, 0); /* no control callback */ |
| | | TEST_IEEE4882("*STB?\r\n", "100\r\n"); /* Event status register + Service request */ |
| | | TEST_IEEE4882("*ESR?\r\n", "32\r\n"); /* Command error */ |
| | | #if USE_DEVICE_DEPENDENT_ERROR_INFORMATION |
| | | TEST_IEEE4882("SYST:ERR:NEXT?\r\n", "-113,\"Undefined header;ABCD\"\r\n"); |
| | | #else /* USE_DEVICE_DEPENDENT_ERROR_INFORMATION */ |
| | | TEST_IEEE4882("SYST:ERR:NEXT?\r\n", "-113,\"Undefined header\"\r\n"); |
| | | #endif /* USE_DEVICE_DEPENDENT_ERROR_INFORMATION */ |
| | | scpi_context.interface->control = SCPI_Control; |
| | | |
| | | RST_executed = FALSE; |