1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-09-28 03:06:20 -04: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:
Jonas Fonseca 2005-12-05 11:11:06 +01:00 committed by Jonas Fonseca
parent cc416b2234
commit 208515c82f
3 changed files with 22 additions and 18 deletions

View File

@ -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));

View File

@ -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) \

View File

@ -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;