From b5533c1dc650d180954968b13ccff4c3b182c768 Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Tue, 2 Jan 2001 20:46:28 +0000 Subject: [PATCH] - Fixed a byteorder conversion problem with message tables. - Carefully read and write (possibly) misaligned data elements to avoid crashes on architectures where this is not allowed. --- tools/wrc/CHANGES | 8 +++ tools/wrc/genres.c | 136 +++++++++++++++++++++++++-------------- tools/wrc/newstruc.c | 150 +++++++++++++++++++++++++++++-------------- tools/wrc/parser.y | 72 +++++++++++++-------- tools/wrc/wrc.h | 4 +- 5 files changed, 247 insertions(+), 123 deletions(-) diff --git a/tools/wrc/CHANGES b/tools/wrc/CHANGES index df976da2f88..9281233213d 100644 --- a/tools/wrc/CHANGES +++ b/tools/wrc/CHANGES @@ -1,3 +1,11 @@ +--------------------------------------------------------------------------- +Version 1.1.9 (31-Dec-2000) + +Ulrich Weigand +- Fixed a byteorder conversion problem with message tables. +- Carefully read and write (possibly) misaligned data elements + to avoid crashes on architectures where this is not allowed. + --------------------------------------------------------------------------- Version 1.1.8 (24-Aug-2000) diff --git a/tools/wrc/genres.c b/tools/wrc/genres.c index 541f305c6a4..6ecf4aec5fe 100644 --- a/tools/wrc/genres.c +++ b/tools/wrc/genres.c @@ -66,7 +66,7 @@ void put_byte(res_t *res, unsigned c) { if(res->allocsize - res->size < sizeof(char)) grow_res(res, RES_BLOCKSIZE); - *(char *)&(res->data[res->size]) = (char)c; + res->data[res->size] = (char)c; res->size += sizeof(char); } @@ -76,15 +76,20 @@ void put_word(res_t *res, unsigned w) grow_res(res, RES_BLOCKSIZE); switch(byteorder) { -#ifndef WORDS_BIGENDIAN - case WRC_BO_BIG: -#else - case WRC_BO_LITTLE: -#endif - *(WORD *)&(res->data[res->size]) = BYTESWAP_WORD((WORD)w); - break; +#ifdef WORDS_BIGENDIAN default: - *(WORD *)&(res->data[res->size]) = (WORD)w; +#endif + case WRC_BO_BIG: + res->data[res->size+0] = HIBYTE(w); + res->data[res->size+1] = LOBYTE(w); + break; + +#ifndef WORDS_BIGENDIAN + default: +#endif + case WRC_BO_LITTLE: + res->data[res->size+1] = HIBYTE(w); + res->data[res->size+0] = LOBYTE(w); break; } res->size += sizeof(WORD); @@ -96,15 +101,24 @@ void put_dword(res_t *res, unsigned d) grow_res(res, RES_BLOCKSIZE); switch(byteorder) { -#ifndef WORDS_BIGENDIAN - case WRC_BO_BIG: -#else - case WRC_BO_LITTLE: -#endif - *(DWORD *)&(res->data[res->size]) = BYTESWAP_DWORD((DWORD)d); - break; +#ifdef WORDS_BIGENDIAN default: - *(DWORD *)&(res->data[res->size]) = (DWORD)d; +#endif + case WRC_BO_BIG: + res->data[res->size+0] = HIBYTE(HIWORD(d)); + res->data[res->size+1] = LOBYTE(HIWORD(d)); + res->data[res->size+2] = HIBYTE(LOWORD(d)); + res->data[res->size+3] = LOBYTE(LOWORD(d)); + break; + +#ifndef WORDS_BIGENDIAN + default: +#endif + case WRC_BO_LITTLE: + res->data[res->size+3] = HIBYTE(HIWORD(d)); + res->data[res->size+2] = LOBYTE(HIWORD(d)); + res->data[res->size+1] = HIBYTE(LOWORD(d)); + res->data[res->size+0] = LOBYTE(LOWORD(d)); break; } res->size += sizeof(DWORD); @@ -136,15 +150,20 @@ void set_word(res_t *res, int ofs, unsigned w) { switch(byteorder) { -#ifndef WORDS_BIGENDIAN - case WRC_BO_BIG: -#else - case WRC_BO_LITTLE: -#endif - *(WORD *)&(res->data[ofs]) = BYTESWAP_WORD((WORD)w); - break; +#ifdef WORDS_BIGENDIAN default: - *(WORD *)&(res->data[ofs]) = (WORD)w; +#endif + case WRC_BO_BIG: + res->data[ofs+0] = HIBYTE(w); + res->data[ofs+1] = LOBYTE(w); + break; + +#ifndef WORDS_BIGENDIAN + default: +#endif + case WRC_BO_LITTLE: + res->data[ofs+1] = HIBYTE(w); + res->data[ofs+0] = LOBYTE(w); break; } } @@ -153,15 +172,24 @@ void set_dword(res_t *res, int ofs, unsigned d) { switch(byteorder) { -#ifndef WORDS_BIGENDIAN - case WRC_BO_BIG: -#else - case WRC_BO_LITTLE: -#endif - *(DWORD *)&(res->data[ofs]) = BYTESWAP_DWORD((DWORD)d); - break; +#ifdef WORDS_BIGENDIAN default: - *(DWORD *)&(res->data[ofs]) = (DWORD)d; +#endif + case WRC_BO_BIG: + res->data[ofs+0] = HIBYTE(HIWORD(d)); + res->data[ofs+1] = LOBYTE(HIWORD(d)); + res->data[ofs+2] = HIBYTE(LOWORD(d)); + res->data[ofs+3] = LOBYTE(LOWORD(d)); + break; + +#ifndef WORDS_BIGENDIAN + default: +#endif + case WRC_BO_LITTLE: + res->data[ofs+3] = HIBYTE(HIWORD(d)); + res->data[ofs+2] = LOBYTE(HIWORD(d)); + res->data[ofs+1] = HIBYTE(LOWORD(d)); + res->data[ofs+0] = LOBYTE(LOWORD(d)); break; } } @@ -185,14 +213,19 @@ WORD get_word(res_t *res, int ofs) { switch(byteorder) { -#ifndef WORDS_BIGENDIAN - case WRC_BO_BIG: -#else - case WRC_BO_LITTLE: -#endif - return BYTESWAP_WORD(*(WORD *)&(res->data[ofs])); +#ifdef WORDS_BIGENDIAN default: - return *(WORD *)&(res->data[ofs]); +#endif + case WRC_BO_BIG: + return (res->data[ofs+0] << 8) + | res->data[ofs+1]; + +#ifndef WORDS_BIGENDIAN + default: +#endif + case WRC_BO_LITTLE: + return (res->data[ofs+1] << 8) + | res->data[ofs+0]; } } @@ -200,14 +233,23 @@ DWORD get_dword(res_t *res, int ofs) { switch(byteorder) { -#ifndef WORDS_BIGENDIAN - case WRC_BO_BIG: -#else - case WRC_BO_LITTLE: -#endif - return BYTESWAP_DWORD(*(DWORD *)&(res->data[ofs])); +#ifdef WORDS_BIGENDIAN default: - return *(DWORD *)&(res->data[ofs]); +#endif + case WRC_BO_BIG: + return (res->data[ofs+0] << 24) + | (res->data[ofs+1] << 16) + | (res->data[ofs+2] << 8) + | res->data[ofs+3]; + +#ifndef WORDS_BIGENDIAN + default: +#endif + case WRC_BO_LITTLE: + return (res->data[ofs+3] << 24) + | (res->data[ofs+2] << 16) + | (res->data[ofs+1] << 8) + | res->data[ofs+0]; } } diff --git a/tools/wrc/newstruc.c b/tools/wrc/newstruc.c index 7268ba6f861..913cecea0f6 100644 --- a/tools/wrc/newstruc.c +++ b/tools/wrc/newstruc.c @@ -374,7 +374,6 @@ static void split_icons(raw_data_t *rd, icon_group_t *icog, int *nico) { int cnt; int i; - icon_dir_entry_t *ide; icon_t *ico; icon_t *list = NULL; icon_header_t *ih = (icon_header_t *)rd->data; @@ -388,31 +387,34 @@ static void split_icons(raw_data_t *rd, icon_group_t *icog, int *nico) yyerror("Icon resource data has invalid type id %d", ih->type); cnt = swap ? BYTESWAP_WORD(ih->count) : ih->count; - ide = (icon_dir_entry_t *)((char *)rd->data + sizeof(icon_header_t)); for(i = 0; i < cnt; i++) { + icon_dir_entry_t ide; + BITMAPINFOHEADER info; + memcpy(&ide, rd->data + sizeof(icon_header_t) + + i*sizeof(icon_dir_entry_t), sizeof(ide)); + ico = new_icon(); ico->id = alloc_icon_id(icog->lvc.language); ico->lvc = icog->lvc; if(swap) { - ide[i].offset = BYTESWAP_DWORD(ide[i].offset); - ide[i].ressize= BYTESWAP_DWORD(ide[i].ressize); + ide.offset = BYTESWAP_DWORD(ide.offset); + ide.ressize= BYTESWAP_DWORD(ide.ressize); } - if(ide[i].offset > rd->size - || ide[i].offset + ide[i].ressize > rd->size) + if(ide.offset > rd->size + || ide.offset + ide.ressize > rd->size) yyerror("Icon resource data corrupt"); - ico->width = ide[i].width; - ico->height = ide[i].height; - ico->nclr = ide[i].nclr; - ico->planes = swap ? BYTESWAP_WORD(ide[i].planes) : ide[i].planes; - ico->bits = swap ? BYTESWAP_WORD(ide[i].bits) : ide[i].bits; - convert_bitmap((char *)rd->data + ide[i].offset, 0); + ico->width = ide.width; + ico->height = ide.height; + ico->nclr = ide.nclr; + ico->planes = swap ? BYTESWAP_WORD(ide.planes) : ide.planes; + ico->bits = swap ? BYTESWAP_WORD(ide.bits) : ide.bits; + convert_bitmap((char *)rd->data + ide.offset, 0); + memcpy(&info, rd->data + ide.offset, sizeof(info)); if(!ico->planes) { - WORD planes; /* Argh! They did not fill out the resdir structure */ - planes = ((BITMAPINFOHEADER *)((char *)rd->data + ide[i].offset))->biPlanes; /* The bitmap is in destination byteorder. We want native for our structures */ switch(byteorder) { @@ -421,17 +423,15 @@ static void split_icons(raw_data_t *rd, icon_group_t *icog, int *nico) #else case WRC_BO_BIG: #endif - ico->planes = BYTESWAP_WORD(planes); + ico->planes = BYTESWAP_WORD(info.biPlanes); break; default: - ico->planes = planes; + ico->planes = info.biPlanes; } } if(!ico->bits) { - WORD bits; /* Argh! They did not fill out the resdir structure */ - bits = ((BITMAPINFOHEADER *)((char *)rd->data + ide[i].offset))->biBitCount; /* The bitmap is in destination byteorder. We want native for our structures */ switch(byteorder) { @@ -440,14 +440,14 @@ static void split_icons(raw_data_t *rd, icon_group_t *icog, int *nico) #else case WRC_BO_BIG: #endif - ico->bits = BYTESWAP_WORD(bits); + ico->bits = BYTESWAP_WORD(info.biBitCount); break; default: - ico->bits = bits; + ico->bits = info.biBitCount; } } ico->data = new_raw_data(); - copy_raw_data(ico->data, rd, ide[i].offset, ide[i].ressize); + copy_raw_data(ico->data, rd, ide.offset, ide.ressize); if(!list) { list = ico; @@ -467,7 +467,6 @@ static void split_cursors(raw_data_t *rd, cursor_group_t *curg, int *ncur) { int cnt; int i; - cursor_dir_entry_t *cde; cursor_t *cur; cursor_t *list = NULL; cursor_header_t *ch = (cursor_header_t *)rd->data; @@ -480,29 +479,29 @@ static void split_cursors(raw_data_t *rd, cursor_group_t *curg, int *ncur) else yyerror("Cursor resource data has invalid type id %d", ch->type); cnt = swap ? BYTESWAP_WORD(ch->count) : ch->count; - cde = (cursor_dir_entry_t *)((char *)rd->data + sizeof(cursor_header_t)); for(i = 0; i < cnt; i++) { - WORD planes; - WORD bits; + cursor_dir_entry_t cde; + BITMAPINFOHEADER info; + memcpy(&cde, rd->data + sizeof(cursor_header_t) + + i*sizeof(cursor_dir_entry_t), sizeof(cde)); + cur = new_cursor(); cur->id = alloc_cursor_id(curg->lvc.language); cur->lvc = curg->lvc; if(swap) { - cde[i].offset = BYTESWAP_DWORD(cde[i].offset); - cde[i].ressize= BYTESWAP_DWORD(cde[i].ressize); + cde.offset = BYTESWAP_DWORD(cde.offset); + cde.ressize= BYTESWAP_DWORD(cde.ressize); } - if(cde[i].offset > rd->size - || cde[i].offset + cde[i].ressize > rd->size) + if(cde.offset > rd->size + || cde.offset + cde.ressize > rd->size) yyerror("Cursor resource data corrupt"); - cur->width = cde[i].width; - cur->height = cde[i].height; - cur->nclr = cde[i].nclr; - convert_bitmap((char *)rd->data + cde[i].offset, 0); - /* The next two are to support color cursors */ - planes = ((BITMAPINFOHEADER *)((char *)rd->data + cde[i].offset))->biPlanes; - bits = ((BITMAPINFOHEADER *)((char *)rd->data + cde[i].offset))->biBitCount; + cur->width = cde.width; + cur->height = cde.height; + cur->nclr = cde.nclr; + convert_bitmap((char *)rd->data + cde.offset, 0); + memcpy(&info, rd->data + cde.offset, sizeof(info)); /* The bitmap is in destination byteorder. We want native for our structures */ switch(byteorder) { @@ -511,19 +510,19 @@ static void split_cursors(raw_data_t *rd, cursor_group_t *curg, int *ncur) #else case WRC_BO_BIG: #endif - cur->planes = BYTESWAP_WORD(planes); - cur->bits = BYTESWAP_WORD(bits); + cur->planes = BYTESWAP_WORD(info.biPlanes); + cur->bits = BYTESWAP_WORD(info.biBitCount); break; default: - cur->planes = planes; - cur->bits = bits; + cur->planes = info.biPlanes; + cur->bits = info.biBitCount; } if(!win32 && (cur->planes != 1 || cur->bits != 1)) yywarning("Win16 cursor contains colors"); - cur->xhot = swap ? BYTESWAP_WORD(cde[i].xhot) : cde[i].xhot; - cur->yhot = swap ? BYTESWAP_WORD(cde[i].yhot) : cde[i].yhot; + cur->xhot = swap ? BYTESWAP_WORD(cde.xhot) : cde.xhot; + cur->yhot = swap ? BYTESWAP_WORD(cde.yhot) : cde.yhot; cur->data = new_raw_data(); - copy_raw_data(cur->data, rd, cde[i].offset, cde[i].ressize); + copy_raw_data(cur->data, rd, cde.offset, cde.ressize); if(!list) { list = cur; @@ -907,6 +906,7 @@ ver_words_t *add_ver_words(ver_words_t *w, int i) messagetable_t *new_messagetable(raw_data_t *rd, int *memopt) { messagetable_t *msg = (messagetable_t *)xmalloc(sizeof(messagetable_t)); + msgtab_block_t *mbp; DWORD nblk; DWORD i; WORD lo; @@ -941,13 +941,62 @@ messagetable_t *new_messagetable(raw_data_t *rd, int *memopt) if(!hi && !lo) yyerror("Invalid messagetable block count 0"); -#ifdef WORDS_BIGENDIAN - if(!hi && lo && byteorder != WRC_BO_LITTLE) -#else - if(hi && !lo && byteorder != WRC_BO_BIG) -#endif + if(!hi && lo) /* Messagetable byteorder == native byteorder */ { - msgtab_block_t *mbp = (msgtab_block_t *)&(((DWORD *)rd->data)[1]); +#ifdef WORDS_BIGENDIAN + if(byteorder != WRC_BO_LITTLE) goto out; +#else + if(byteorder != WRC_BO_BIG) goto out; +#endif + /* Resource byteorder != native byteorder */ + + mbp = (msgtab_block_t *)&(((DWORD *)rd->data)[1]); + if(MSGTAB_BAD_PTR(mbp, rd->data, rd->size, nblk * sizeof(*mbp))) + yyerror("Messagetable's blocks are outside of defined data"); + for(i = 0; i < nblk; i++) + { + msgtab_entry_t *mep, *next_mep; + DWORD id; + + mep = (msgtab_entry_t *)(((char *)rd->data) + mbp[i].offset); + + for(id = mbp[i].idlo; id <= mbp[i].idhi; id++) + { + if(MSGTAB_BAD_PTR(mep, rd->data, rd->size, mep->length)) + yyerror("Messagetable's data for block %d, ID 0x%08lx is outside of defined data", (int)i, id); + if(mep->flags == 1) /* Docu says 'flags == 0x0001' for unicode */ + { + WORD *wp = (WORD *)&mep[1]; + int l = mep->length/2 - 2; /* Length included header */ + int n; + + if(mep->length & 1) + yyerror("Message 0x%08lx is unicode (block %d), but has odd length (%d)", id, (int)i, mep->length); + for(n = 0; n < l; n++) + wp[n] = BYTESWAP_WORD(wp[n]); + + } + next_mep = (msgtab_entry_t *)(((char *)mep) + mep->length); + mep->length = BYTESWAP_WORD(mep->length); + mep->flags = BYTESWAP_WORD(mep->flags); + mep = next_mep; + } + + mbp[i].idlo = BYTESWAP_DWORD(mbp[i].idlo); + mbp[i].idhi = BYTESWAP_DWORD(mbp[i].idhi); + mbp[i].offset = BYTESWAP_DWORD(mbp[i].offset); + } + } + if(hi && !lo) /* Messagetable byteorder != native byteorder */ + { +#ifdef WORDS_BIGENDIAN + if(byteorder == WRC_BO_LITTLE) goto out; +#else + if(byteorder == WRC_BO_BIG) goto out; +#endif + /* Resource byteorder == native byteorder */ + + mbp = (msgtab_block_t *)&(((DWORD *)rd->data)[1]); nblk = BYTESWAP_DWORD(nblk); if(MSGTAB_BAD_PTR(mbp, rd->data, rd->size, nblk * sizeof(*mbp))) yyerror("Messagetable's blocks are outside of defined data"); @@ -960,10 +1009,12 @@ messagetable_t *new_messagetable(raw_data_t *rd, int *memopt) mbp[i].idhi = BYTESWAP_DWORD(mbp[i].idhi); mbp[i].offset = BYTESWAP_DWORD(mbp[i].offset); mep = (msgtab_entry_t *)(((char *)rd->data) + mbp[i].offset); + for(id = mbp[i].idlo; id <= mbp[i].idhi; id++) { mep->length = BYTESWAP_WORD(mep->length); mep->flags = BYTESWAP_WORD(mep->flags); + if(MSGTAB_BAD_PTR(mep, rd->data, rd->size, mep->length)) yyerror("Messagetable's data for block %d, ID 0x%08lx is outside of defined data", (int)i, id); if(mep->flags == 1) /* Docu says 'flags == 0x0001' for unicode */ @@ -983,6 +1034,7 @@ messagetable_t *new_messagetable(raw_data_t *rd, int *memopt) } } + out: return msg; } #undef MSGTAB_BAD_PTR diff --git a/tools/wrc/parser.y b/tools/wrc/parser.y index 61861f1ade3..7c17fa7d81c 100644 --- a/tools/wrc/parser.y +++ b/tools/wrc/parser.y @@ -2330,15 +2330,20 @@ static raw_data_t *int2raw_data(int i) rd->data = (char *)xmalloc(rd->size); switch(byteorder) { -#ifndef WORDS_BIGENDIAN - case WRC_BO_BIG: -#else - case WRC_BO_LITTLE: -#endif - *(WORD *)(rd->data) = BYTESWAP_WORD((WORD)i); - break; +#ifdef WORDS_BIGENDIAN default: - *(WORD *)(rd->data) = (WORD)i; +#endif + case WRC_BO_BIG: + rd->data[0] = HIBYTE(i); + rd->data[1] = LOBYTE(i); + break; + +#ifndef WORDS_BIGENDIAN + default: +#endif + case WRC_BO_LITTLE: + rd->data[1] = HIBYTE(i); + rd->data[0] = LOBYTE(i); break; } return rd; @@ -2352,15 +2357,24 @@ static raw_data_t *long2raw_data(int i) rd->data = (char *)xmalloc(rd->size); switch(byteorder) { -#ifndef WORDS_BIGENDIAN - case WRC_BO_BIG: -#else - case WRC_BO_LITTLE: -#endif - *(DWORD *)(rd->data) = BYTESWAP_DWORD((DWORD)i); - break; +#ifdef WORDS_BIGENDIAN default: - *(DWORD *)(rd->data) = (DWORD)i; +#endif + case WRC_BO_BIG: + rd->data[0] = HIBYTE(HIWORD(i)); + rd->data[1] = LOBYTE(HIWORD(i)); + rd->data[2] = HIBYTE(LOWORD(i)); + rd->data[3] = LOBYTE(LOWORD(i)); + break; + +#ifndef WORDS_BIGENDIAN + default: +#endif + case WRC_BO_LITTLE: + rd->data[3] = HIBYTE(HIWORD(i)); + rd->data[2] = LOBYTE(HIWORD(i)); + rd->data[1] = HIBYTE(LOWORD(i)); + rd->data[0] = LOBYTE(LOWORD(i)); break; } return rd; @@ -2379,17 +2393,25 @@ static raw_data_t *str2raw_data(string_t *str) int i; switch(byteorder) { -#ifndef WORDS_BIGENDIAN - case WRC_BO_BIG: -#else - case WRC_BO_LITTLE: -#endif - for(i = 0; i < str->size; i++) - *(WORD *)&(rd->data[2*i]) = BYTESWAP_WORD((WORD)str->str.wstr[i]); - break; +#ifdef WORDS_BIGENDIAN default: +#endif + case WRC_BO_BIG: for(i = 0; i < str->size; i++) - *(WORD *)&(rd->data[2*i]) = (WORD)str->str.wstr[i]; + { + rd->data[2*i + 0] = HIBYTE((WORD)str->str.wstr[i]); + rd->data[2*i + 1] = LOBYTE((WORD)str->str.wstr[i]); + } + break; +#ifndef WORDS_BIGENDIAN + default: +#endif + case WRC_BO_LITTLE: + for(i = 0; i < str->size; i++) + { + rd->data[2*i + 1] = HIBYTE((WORD)str->str.wstr[i]); + rd->data[2*i + 0] = LOBYTE((WORD)str->str.wstr[i]); + } break; } } diff --git a/tools/wrc/wrc.h b/tools/wrc/wrc.h index 88529ea5f5e..0f539302fae 100644 --- a/tools/wrc/wrc.h +++ b/tools/wrc/wrc.h @@ -16,8 +16,8 @@ #define WRC_MAJOR_VERSION 1 #define WRC_MINOR_VERSION 1 -#define WRC_MICRO_VERSION 8 -#define WRC_RELEASEDATE "(24-Aug-2000)" +#define WRC_MICRO_VERSION 9 +#define WRC_RELEASEDATE "(31-Dec-2000)" #define WRC_STRINGIZE(a) #a #define WRC_EXP_STRINGIZE(a) WRC_STRINGIZE(a)