mirror of
https://github.com/rkd77/elinks.git
synced 2024-12-04 14:46:47 -05:00
Fix access to free()d memory in the DOM stack state data
There already was one work-around in the code related to clearing of the state data after popping. Instead of storing a pointer to the state data in the state we now store the depth of the state (in the stack) and use a macro to access the state data. The bug occurred when reallocating the stack state objects and the stack data pointers wasn't updated to point to the newly allocated data.
This commit is contained in:
parent
cc416b2234
commit
208515c82f
@ -94,7 +94,6 @@ push_dom_node(struct dom_stack *stack, struct dom_node *node)
|
||||
|
||||
if (stack->object_size) {
|
||||
unsigned char *state_objects;
|
||||
size_t offset = stack->depth * stack->object_size;
|
||||
|
||||
state_objects = realloc_dom_stack_state_objects(stack);
|
||||
if (!state_objects) {
|
||||
@ -102,7 +101,7 @@ push_dom_node(struct dom_stack *stack, struct dom_node *node)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
state->data = (void *) &state_objects[offset];
|
||||
state->depth = stack->depth;
|
||||
}
|
||||
|
||||
state->node = node;
|
||||
@ -113,7 +112,9 @@ push_dom_node(struct dom_stack *stack, struct dom_node *node)
|
||||
|
||||
callback = stack->callbacks[node->type];
|
||||
if (callback) {
|
||||
node = callback(stack, node, state->data);
|
||||
void *state_data = get_dom_stack_state_data(stack, state);
|
||||
|
||||
node = callback(stack, node, state_data);
|
||||
|
||||
/* If the callback returned NULL pop the state immediately */
|
||||
if (!node) {
|
||||
@ -136,20 +137,19 @@ do_pop_dom_node(struct dom_stack *stack, struct dom_stack_state *parent)
|
||||
|
||||
state = get_dom_stack_top(stack);
|
||||
if (state->callback) {
|
||||
void *state_data = get_dom_stack_state_data(stack, state);
|
||||
|
||||
/* Pass the node we are popping to and _not_ the state->node */
|
||||
state->callback(stack, parent->node, state->data);
|
||||
state->callback(stack, parent->node, state_data);
|
||||
}
|
||||
|
||||
stack->depth--;
|
||||
assert(stack->depth >= 0);
|
||||
|
||||
if (stack->object_size && state->data) {
|
||||
size_t offset = stack->depth * stack->object_size;
|
||||
if (stack->object_size) {
|
||||
void *state_data = get_dom_stack_state_data(stack, state);
|
||||
|
||||
/* I tried to use item->data here but it caused a memory
|
||||
* corruption bug on fm. This is also less trustworthy in that
|
||||
* the state->data pointer could have been mangled. --jonas */
|
||||
memset(&stack->state_objects[offset], 0, stack->object_size);
|
||||
memset(state_data, 0, stack->object_size);
|
||||
}
|
||||
|
||||
memset(state, 0, sizeof(*state));
|
||||
|
@ -28,10 +28,9 @@ struct dom_stack_state {
|
||||
* correctly highlighting ending elements (e.g. </a>). */
|
||||
dom_stack_callback_T callback;
|
||||
|
||||
/* Parser specific data. For the SGML parser this holds DTD-oriented
|
||||
* info about the node (recorded in struct sgml_node_info). E.g.
|
||||
* whether an element node is optional. */
|
||||
void *data;
|
||||
/* The depth of the state in the stack. This is amongst other things
|
||||
* used to get the state object data. */
|
||||
unsigned int depth;
|
||||
};
|
||||
|
||||
/* The DOM stack is a convenient way to traverse DOM trees. Also it
|
||||
@ -42,8 +41,10 @@ struct dom_stack {
|
||||
struct dom_stack_state *states;
|
||||
size_t depth;
|
||||
|
||||
/* This is one big array of parser specific objects which will be
|
||||
* assigned to the data member of the individual dom_stack_states. */
|
||||
/* This is one big array of parser specific objects. */
|
||||
/* The objects hold parser specific data. For the SGML parser this
|
||||
* holds DTD-oriented info about the node (recorded in struct
|
||||
* sgml_node_info). E.g. whether an element node is optional. */
|
||||
unsigned char *state_objects;
|
||||
size_t object_size;
|
||||
|
||||
@ -66,6 +67,9 @@ get_dom_stack_state(struct dom_stack *stack, int top_offset)
|
||||
#define get_dom_stack_parent(nav) get_dom_stack_state(nav, 1)
|
||||
#define get_dom_stack_top(nav) get_dom_stack_state(nav, 0)
|
||||
|
||||
#define get_dom_stack_state_data(stack, state) \
|
||||
((void *) &(stack)->state_objects[(state)->depth * (stack)->object_size])
|
||||
|
||||
/* The state iterators do not include the bottom state */
|
||||
|
||||
#define foreach_dom_state(nav, item, pos) \
|
||||
|
@ -58,9 +58,9 @@ add_sgml_element(struct dom_stack *stack, struct scanner_token *token)
|
||||
return NULL;
|
||||
|
||||
state = get_dom_stack_top(stack);
|
||||
assert(node == state->node && state->data);
|
||||
assert(node == state->node);
|
||||
|
||||
pstate = state->data;
|
||||
pstate = get_dom_stack_state_data(stack, state);
|
||||
pstate->info = node_info;
|
||||
|
||||
return node;
|
||||
|
Loading…
Reference in New Issue
Block a user