1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-09-28 03:06:20 -04:00

bug 764: Initialize the right member of union option_value

Convert the initial value of each option to void * at compile time,
and make register_options() convert it back and set the appropriate
member of union option_value.  Previously, all initial values were
left in option.value.tree and then read directly from other members
of the union, failing badly on big-endian 64-bit systems.
This commit is contained in:
Kalle Olavi Niemitalo 2009-08-11 03:44:02 +03:00 committed by Kalle Olavi Niemitalo
parent 39d03147bb
commit 9e52956a02
3 changed files with 44 additions and 9 deletions

2
NEWS
View File

@ -12,6 +12,8 @@ To be released as 0.11.7.
* critical bug 1077: fix crash opening a ``javascript:'' link in a new
tab
* major bug 764: remove int/long/pointer type punning in union
option_value, especially harmful on sparc64
ELinks 0.11.6:
--------------

View File

@ -713,6 +713,11 @@ static struct change_hook_info change_hooks[];
void
init_options(void)
{
/* The following assignment is needed if void * and struct
* list_head * have different representations. Otherwise,
* the compiler should be able to optimize it out. */
options_root.value.tree = options_root.value.compile_time_init;
cmdline_options = add_opt_tree_tree(&options_root, "", "",
"cmdline", 0, "");
register_options(cmdline_options_info, cmdline_options);
@ -1144,26 +1149,42 @@ register_options(struct option_info info[], struct option *tree)
delete_option(option);
continue;
}
safe_strncpy(string, option->value.string, MAX_STR_LEN);
safe_strncpy(string,
option->value.compile_time_init,
MAX_STR_LEN);
option->value.string = string;
break;
case OPT_COLOR:
string = option->value.string;
string = option->value.compile_time_init;
assert(string);
decode_color(string, strlen(string),
&option->value.color);
break;
case OPT_CODEPAGE:
string = option->value.string;
string = option->value.compile_time_init;
assert(string);
option->value.number = get_cp_index(string);
break;
case OPT_BOOL:
case OPT_INT:
case OPT_LONG:
case OPT_LANGUAGE:
/* Some compilers warn if we cast a
* pointer directly to an integer with
* a different size. */
option->value.number = (int) (longptr_T)
option->value.compile_time_init;
break;
case OPT_LONG:
option->value.big_number = (long) (longptr_T)
option->value.compile_time_init;
break;
case OPT_COMMAND:
option->value.command =
option->value.compile_time_init;
break;
case OPT_ALIAS:
option->value.string =
option->value.compile_time_init;
break;
}

View File

@ -101,7 +101,19 @@ struct option;
struct session;
union option_value {
/* XXX: Keep first to make @options_root initialization possible. */
/* INIT_OPTION initializes this first member at compile time.
* In C89, only the first member of a union can be initialized.
* So INIT_OPTION casts the default value of each option to the
* type of this member at compile time, and register_options()
* then casts the value back to the original type and writes it
* to the appropriate member. The type must be a pointer type
* because we need to store strings and (int) "foo" is not a
* valid constant expression for an initializer in standard C.
* We choose void * because that type has the fewest alignment
* requirements and so is not likely to lose any bits of the
* integers we cast to it. */
void *compile_time_init;
/* The OPT_TREE list_head is allocated. */
struct list_head *tree;
@ -149,7 +161,7 @@ struct option {
};
#define INIT_OPTION(name, flags, type, min, max, value, desc, capt) \
{ NULL_LIST_HEAD, INIT_OBJECT("option"), name, flags, type, min, max, { (struct list_head *) (value) }, desc, capt }
{ NULL_LIST_HEAD, INIT_OBJECT("option"), name, flags, type, min, max, { (void *) (value) }, desc, capt }
extern struct option *config_options;
extern struct option *cmdline_options;
@ -314,13 +326,13 @@ extern void unregister_options(struct option_info info[], struct option *tree);
{ INIT_OPTION(NULL, 0, 0, 0, 0, NULL, NULL, NULL), NULL }
#define INIT_OPT_BOOL(path, capt, name, flags, def, desc) \
{ INIT_OPTION(name, flags, OPT_BOOL, 0, 1, def, DESC(desc), capt), path }
{ INIT_OPTION(name, flags, OPT_BOOL, 0, 1, (longptr_T) def, DESC(desc), capt), path }
#define INIT_OPT_INT(path, capt, name, flags, min, max, def, desc) \
{ INIT_OPTION(name, flags, OPT_INT, min, max, def, DESC(desc), capt), path }
{ INIT_OPTION(name, flags, OPT_INT, min, max, (longptr_T) def, DESC(desc), capt), path }
#define INIT_OPT_LONG(path, capt, name, flags, min, max, def, desc) \
{ INIT_OPTION(name, flags, OPT_LONG, min, max, def, DESC(desc), capt), path }
{ INIT_OPTION(name, flags, OPT_LONG, min, max, (longptr_T) def, DESC(desc), capt), path }
#define INIT_OPT_STRING(path, capt, name, flags, def, desc) \
{ INIT_OPTION(name, flags, OPT_STRING, 0, MAX_STR_LEN, def, DESC(desc), capt), path }