Fix multiple debugger issues. (#1640)

- Wait for free byte code pointers during garbage collection.
- Detect incorrect free requests in the debugger server.
- Ignore byte code blocks loaded from snapshot.
- Use memmove instead of memcpy to avoid receive buffer corruption.

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg
2017-03-06 11:13:25 +01:00
committed by GitHub
parent b996841a65
commit b5a91069fd
9 changed files with 110 additions and 62 deletions
+3 -3
View File
@@ -551,9 +551,9 @@ jerry_debugger_receive (void)
if (message_total_size < offset) if (message_total_size < offset)
{ {
memcpy (recv_buffer_p, memmove (recv_buffer_p,
recv_buffer_p + message_total_size, recv_buffer_p + message_total_size,
offset - message_total_size); offset - message_total_size);
} }
JERRY_CONTEXT (debugger_receive_buffer_offset) = (uint16_t) (offset - message_total_size); JERRY_CONTEXT (debugger_receive_buffer_offset) = (uint16_t) (offset - message_total_size);
+22 -22
View File
@@ -45,18 +45,18 @@ jerry_debugger_free_unreferenced_byte_code (void)
jerry_debugger_byte_code_free_t *byte_code_free_p; jerry_debugger_byte_code_free_t *byte_code_free_p;
byte_code_free_p = JMEM_CP_GET_POINTER (jerry_debugger_byte_code_free_t, byte_code_free_p = JMEM_CP_GET_POINTER (jerry_debugger_byte_code_free_t,
JERRY_CONTEXT (debugger_byte_code_free_head)); JERRY_CONTEXT (debugger_byte_code_free_tail));
while (byte_code_free_p != NULL) while (byte_code_free_p != NULL)
{ {
jerry_debugger_byte_code_free_t *next_byte_code_free_p; jerry_debugger_byte_code_free_t *prev_byte_code_free_p;
next_byte_code_free_p = JMEM_CP_GET_POINTER (jerry_debugger_byte_code_free_t, prev_byte_code_free_p = JMEM_CP_GET_POINTER (jerry_debugger_byte_code_free_t,
byte_code_free_p->next_cp); byte_code_free_p->prev_cp);
jmem_heap_free_block (byte_code_free_p, jmem_heap_free_block (byte_code_free_p,
((size_t) byte_code_free_p->size) << JMEM_ALIGNMENT_LOG); ((size_t) byte_code_free_p->size) << JMEM_ALIGNMENT_LOG);
byte_code_free_p = next_byte_code_free_p; byte_code_free_p = prev_byte_code_free_p;
} }
} /* jerry_debugger_free_unreferenced_byte_code */ } /* jerry_debugger_free_unreferenced_byte_code */
@@ -88,6 +88,12 @@ jerry_debugger_send_backtrace (uint8_t *recv_buffer_p) /**< pointer the the rece
while (frame_ctx_p != NULL && max_depth > 0) while (frame_ctx_p != NULL && max_depth > 0)
{ {
if (frame_ctx_p->bytecode_header_p->status_flags & CBC_CODE_FLAGS_DEBUGGER_IGNORE)
{
frame_ctx_p = frame_ctx_p->prev_context_p;
continue;
}
if (current_frame >= JERRY_DEBUGGER_SEND_MAX (jerry_debugger_frame_t)) if (current_frame >= JERRY_DEBUGGER_SEND_MAX (jerry_debugger_frame_t))
{ {
if (!jerry_debugger_send (sizeof (jerry_debugger_send_backtrace_t))) if (!jerry_debugger_send (sizeof (jerry_debugger_send_backtrace_t)))
@@ -283,31 +289,25 @@ jerry_debugger_process_message (uint8_t *recv_buffer_p, /**< pointer the the rec
jmem_cpointer_t byte_code_free_cp; jmem_cpointer_t byte_code_free_cp;
memcpy (&byte_code_free_cp, byte_code_p->byte_code_cp, sizeof (jmem_cpointer_t)); memcpy (&byte_code_free_cp, byte_code_p->byte_code_cp, sizeof (jmem_cpointer_t));
if (byte_code_free_cp != JERRY_CONTEXT (debugger_byte_code_free_tail))
{
jerry_port_log (JERRY_LOG_LEVEL_ERROR, "Invalid byte code free order\n");
jerry_debugger_close_connection ();
return false;
}
jerry_debugger_byte_code_free_t *byte_code_free_p; jerry_debugger_byte_code_free_t *byte_code_free_p;
byte_code_free_p = JMEM_CP_GET_NON_NULL_POINTER (jerry_debugger_byte_code_free_t, byte_code_free_p = JMEM_CP_GET_NON_NULL_POINTER (jerry_debugger_byte_code_free_t,
byte_code_free_cp); byte_code_free_cp);
if (JERRY_CONTEXT (debugger_byte_code_free_head) == byte_code_free_cp)
{
JERRY_CONTEXT (debugger_byte_code_free_head) = byte_code_free_p->next_cp;
}
if (byte_code_free_p->prev_cp != ECMA_NULL_POINTER) if (byte_code_free_p->prev_cp != ECMA_NULL_POINTER)
{ {
jerry_debugger_byte_code_free_t *prev_byte_code_free_p; JERRY_CONTEXT (debugger_byte_code_free_tail) = byte_code_free_p->prev_cp;
prev_byte_code_free_p = JMEM_CP_GET_NON_NULL_POINTER (jerry_debugger_byte_code_free_t,
byte_code_free_p->prev_cp);
prev_byte_code_free_p->next_cp = byte_code_free_p->next_cp;
} }
else
if (byte_code_free_p->next_cp != ECMA_NULL_POINTER)
{ {
jerry_debugger_byte_code_free_t *next_byte_code_free_p; JERRY_CONTEXT (debugger_byte_code_free_head) = ECMA_NULL_POINTER;
next_byte_code_free_p = JMEM_CP_GET_NON_NULL_POINTER (jerry_debugger_byte_code_free_t, JERRY_CONTEXT (debugger_byte_code_free_tail) = ECMA_NULL_POINTER;
byte_code_free_p->next_cp);
next_byte_code_free_p->prev_cp = byte_code_free_p->prev_cp;
} }
jmem_heap_free_block (byte_code_free_p, jmem_heap_free_block (byte_code_free_p,
+2 -3
View File
@@ -98,9 +98,8 @@ typedef enum
*/ */
typedef struct typedef struct
{ {
uint16_t size; uint16_t size; /**< size of the byte code header divided by JMEM_ALIGNMENT */
jmem_cpointer_t prev_cp; jmem_cpointer_t prev_cp; /**< previous byte code data to be freed */
jmem_cpointer_t next_cp;
} jerry_debugger_byte_code_free_t; } jerry_debugger_byte_code_free_t;
/** /**
+10 -2
View File
@@ -708,10 +708,18 @@ ecma_gc_run (jmem_free_unused_memory_severity_t severity) /**< gc severity */
void void
ecma_free_unused_memory (jmem_free_unused_memory_severity_t severity) /**< severity of the request */ ecma_free_unused_memory (jmem_free_unused_memory_severity_t severity) /**< severity of the request */
{ {
#ifdef JERRY_DEBUGGER
while ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
&& JERRY_CONTEXT (debugger_byte_code_free_tail) != ECMA_NULL_POINTER)
{
/* Wait until all byte code is freed or the connection is aborted. */
jerry_debugger_receive ();
}
#endif /* JERRY_DEBUGGER */
if (severity == JMEM_FREE_UNUSED_MEMORY_SEVERITY_LOW) if (severity == JMEM_FREE_UNUSED_MEMORY_SEVERITY_LOW)
{ {
#ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE
#ifndef CONFIG_ECMA_PROPERTY_HASHMAP_DISABLE
if (JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) > ECMA_PROP_HASHMAP_ALLOC_ON) if (JERRY_CONTEXT (ecma_prop_hashmap_alloc_state) > ECMA_PROP_HASHMAP_ALLOC_ON)
{ {
--JERRY_CONTEXT (ecma_prop_hashmap_alloc_state); --JERRY_CONTEXT (ecma_prop_hashmap_alloc_state);
+27 -24
View File
@@ -1377,33 +1377,36 @@ ecma_bytecode_deref (ecma_compiled_code_t *bytecode_p) /**< byte code pointer */
} }
#ifdef JERRY_DEBUGGER #ifdef JERRY_DEBUGGER
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED) if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
&& !(bytecode_p->status_flags & CBC_CODE_FLAGS_DEBUGGER_IGNORE)
&& jerry_debugger_send_function_cp (JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP, bytecode_p))
{ {
if (jerry_debugger_send_function_cp (JERRY_DEBUGGER_RELEASE_BYTE_CODE_CP, bytecode_p)) /* Delay the byte code free until the debugger client is notified.
* If the connection is aborted the pointer is still freed by
* jerry_debugger_close_connection(). */
jerry_debugger_byte_code_free_t *byte_code_free_p = (jerry_debugger_byte_code_free_t *) bytecode_p;
jmem_cpointer_t byte_code_free_head = JERRY_CONTEXT (debugger_byte_code_free_head);
byte_code_free_p->prev_cp = ECMA_NULL_POINTER;
jmem_cpointer_t byte_code_free_cp;
JMEM_CP_SET_NON_NULL_POINTER (byte_code_free_cp, byte_code_free_p);
if (byte_code_free_head == ECMA_NULL_POINTER)
{ {
/* Delay the byte code free until the debugger client is notified. JERRY_CONTEXT (debugger_byte_code_free_tail) = byte_code_free_cp;
* If the connection is aborted the pointer is still freed by
* jerry_debugger_close_connection(). */
jerry_debugger_byte_code_free_t *byte_code_free_p = (jerry_debugger_byte_code_free_t *) bytecode_p;
jmem_cpointer_t byte_code_free_head = JERRY_CONTEXT (debugger_byte_code_free_head);
byte_code_free_p->prev_cp = ECMA_NULL_POINTER;
byte_code_free_p->next_cp = byte_code_free_head;
JMEM_CP_SET_NON_NULL_POINTER (JERRY_CONTEXT (debugger_byte_code_free_head),
byte_code_free_p);
if (byte_code_free_head != ECMA_NULL_POINTER)
{
jerry_debugger_byte_code_free_t *next_byte_code_free_p;
next_byte_code_free_p = JMEM_CP_GET_NON_NULL_POINTER (jerry_debugger_byte_code_free_t,
byte_code_free_head);
next_byte_code_free_p->prev_cp = JERRY_CONTEXT (debugger_byte_code_free_head);
}
return;
} }
else
{
jerry_debugger_byte_code_free_t *first_byte_code_free_p;
first_byte_code_free_p = JMEM_CP_GET_NON_NULL_POINTER (jerry_debugger_byte_code_free_t,
byte_code_free_head);
first_byte_code_free_p->prev_cp = byte_code_free_cp;
}
JERRY_CONTEXT (debugger_byte_code_free_head) = byte_code_free_cp;
return;
} }
#endif /* JERRY_DEBUGGER */ #endif /* JERRY_DEBUGGER */
} }
+1
View File
@@ -88,6 +88,7 @@ typedef struct
uint8_t debugger_send_buffer[JERRY_DEBUGGER_MAX_BUFFER_SIZE]; /**< buffer for sending messages */ uint8_t debugger_send_buffer[JERRY_DEBUGGER_MAX_BUFFER_SIZE]; /**< buffer for sending messages */
uint8_t debugger_receive_buffer[JERRY_DEBUGGER_MAX_BUFFER_SIZE]; /**< buffer for receiving messages */ uint8_t debugger_receive_buffer[JERRY_DEBUGGER_MAX_BUFFER_SIZE]; /**< buffer for receiving messages */
jmem_cpointer_t debugger_byte_code_free_head; /**< head of byte code free linked list */ jmem_cpointer_t debugger_byte_code_free_head; /**< head of byte code free linked list */
jmem_cpointer_t debugger_byte_code_free_tail; /**< tail of byte code free linked list */
int debugger_connection; /**< hold the file descriptor for socket communication */ int debugger_connection; /**< hold the file descriptor for socket communication */
uint8_t debugger_flags; /**< debugger flags */ uint8_t debugger_flags; /**< debugger flags */
vm_frame_ctx_t *debugger_stop_context; /**< stop only if the current context is equal to this context */ vm_frame_ctx_t *debugger_stop_context; /**< stop only if the current context is equal to this context */
+4
View File
@@ -395,6 +395,10 @@ snapshot_load_compiled_code (const uint8_t *snapshot_data_p, /**< snapshot data
JERRY_ASSERT (bytecode_p->refs == 1); JERRY_ASSERT (bytecode_p->refs == 1);
#ifdef JERRY_DEBUGGER
bytecode_p->status_flags = (uint16_t) (bytecode_p->status_flags | CBC_CODE_FLAGS_DEBUGGER_IGNORE);
#endif /* JERRY_DEBUGGER */
jmem_cpointer_t *literal_start_p = (jmem_cpointer_t *) (((uint8_t *) bytecode_p) + header_size); jmem_cpointer_t *literal_start_p = (jmem_cpointer_t *) (((uint8_t *) bytecode_p) + header_size);
for (uint32_t i = 0; i < const_literal_end; i++) for (uint32_t i = 0; i < const_literal_end; i++)
+13 -8
View File
@@ -650,14 +650,19 @@ typedef struct
uint16_t literal_end; /**< end position of the literal group */ uint16_t literal_end; /**< end position of the literal group */
} cbc_uint16_arguments_t; } cbc_uint16_arguments_t;
/* When CBC_CODE_FLAGS_FULL_LITERAL_ENCODING /**
* is not set the small encoding is used. */ * Compact byte code status flags.
#define CBC_CODE_FLAGS_FUNCTION 0x01 */
#define CBC_CODE_FLAGS_FULL_LITERAL_ENCODING 0x02 typedef enum
#define CBC_CODE_FLAGS_UINT16_ARGUMENTS 0x04 {
#define CBC_CODE_FLAGS_STRICT_MODE 0x08 CBC_CODE_FLAGS_FUNCTION = (1u << 0), /**< compiled code is JavaScript function */
#define CBC_CODE_FLAGS_ARGUMENTS_NEEDED 0x10 CBC_CODE_FLAGS_FULL_LITERAL_ENCODING = (1u << 1), /**< full literal encoding mode is enabled */
#define CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED 0x20 CBC_CODE_FLAGS_UINT16_ARGUMENTS = (1u << 2), /**< compiled code data is cbc_uint16_arguments_t */
CBC_CODE_FLAGS_STRICT_MODE = (1u << 3), /**< strict mode is enabled */
CBC_CODE_FLAGS_ARGUMENTS_NEEDED = (1u << 4), /**< arguments object must be constructed */
CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED = (1u << 5), /**< no need to create a lexical environment */
CBC_CODE_FLAGS_DEBUGGER_IGNORE = (1u << 6), /**< this function should be ignored by debugger */
} cbc_code_flags;
#define CBC_OPCODE(arg1, arg2, arg3, arg4) arg1, #define CBC_OPCODE(arg1, arg2, arg3, arg4) arg1,
+28
View File
@@ -2321,6 +2321,20 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED); JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED);
if (frame_ctx_p->bytecode_header_p->status_flags & CBC_CODE_FLAGS_DEBUGGER_IGNORE)
{
/* Messages are still processed regardless of ignore. */
if (JERRY_CONTEXT (debugger_message_delay) > 0)
{
JERRY_CONTEXT (debugger_message_delay)--;
continue;
}
JERRY_CONTEXT (debugger_message_delay) = JERRY_DEBUGGER_MESSAGE_FREQUENCY;
jerry_debugger_receive ();
continue;
}
frame_ctx_p->byte_code_p = byte_code_start_p; frame_ctx_p->byte_code_p = byte_code_start_p;
jerry_debugger_breakpoint_hit (); jerry_debugger_breakpoint_hit ();
@@ -2337,6 +2351,20 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED); JERRY_ASSERT (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED);
if (frame_ctx_p->bytecode_header_p->status_flags & CBC_CODE_FLAGS_DEBUGGER_IGNORE)
{
/* Messages are still processed regardless of ignore. */
if (JERRY_CONTEXT (debugger_message_delay) > 0)
{
JERRY_CONTEXT (debugger_message_delay)--;
continue;
}
JERRY_CONTEXT (debugger_message_delay) = JERRY_DEBUGGER_MESSAGE_FREQUENCY;
jerry_debugger_receive ();
continue;
}
frame_ctx_p->byte_code_p = byte_code_start_p; frame_ctx_p->byte_code_p = byte_code_start_p;
if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_STOP) if ((JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_VM_STOP)