Make RSX MLB parser more resistant to bad files.

This commit is contained in:
Olaf Seibert
2022-06-13 21:41:20 +02:00
parent ff183c0e36
commit 779c775107
6 changed files with 165 additions and 58 deletions

4
README
View File

@@ -110,6 +110,10 @@ Options:
-m macname Gives a macro library name. -m macname Gives a macro library name.
Up to 32 macro libraries may be specified, one per Up to 32 macro libraries may be specified, one per
-m option. -m option.
The current object file format (default, or from
-rt11 or -rsx before this option) is used first to
read the file; if this fails, the other format is
tried.
Note: unlike MACRO.SAV, SYSMAC.SML is not Note: unlike MACRO.SAV, SYSMAC.SML is not
automatically included; you must name it. automatically included; you must name it.

View File

@@ -1,6 +1,3 @@
#define MACRO11__C
/* /*
Assembler compatible with MACRO-11. Assembler compatible with MACRO-11.
@@ -132,7 +129,7 @@ static void print_help(
printf(" -l - enables listing to stdout.\n"); printf(" -l - enables listing to stdout.\n");
printf("-m load RSX-11 or RT-11 compatible macro library from which\n"); printf("-m load RSX-11 or RT-11 compatible macro library from which\n");
printf(" .MCALLed macros can be found.\n"); printf(" .MCALLed macros can be found.\n");
printf(" Multiple allowed.\n"); printf(" Multiple allowed. Affected by any -rsx or -rt11 which come before.\n");
printf("-o gives the object file name (.OBJ)\n"); printf("-o gives the object file name (.OBJ)\n");
printf("-p gives the name of a directory in which .MCALLed macros may be found.\n"); printf("-p gives the name of a directory in which .MCALLed macros may be found.\n");
printf(" Sets environment variable \"MCALL\".\n"); printf(" Sets environment variable \"MCALL\".\n");

163
mlb-rsx.c
View File

@@ -156,6 +156,9 @@ DAMAGE.
#include "mlb.h" #include "mlb.h"
#include "util.h" #include "util.h"
#define MLBDEBUG_OPEN 0
#define MLBDEBUG_ENTRY 0
static MLB *mlb_rsx_open( static MLB *mlb_rsx_open(
char *name, char *name,
int allow_object_library); int allow_object_library);
@@ -168,10 +171,11 @@ static void mlb_rsx_extract(
MLB *mlb); MLB *mlb);
struct mlb_vtbl mlb_rsx_vtbl = { struct mlb_vtbl mlb_rsx_vtbl = {
mlb_rsx_open, .mlb_open = mlb_rsx_open,
mlb_rsx_entry, .mlb_entry = mlb_rsx_entry,
mlb_rsx_extract, .mlb_extract = mlb_rsx_extract,
mlb_rsx_close, .mlb_close = mlb_rsx_close,
.mlb_is_rt11 = 0,
}; };
#define BLOCKSIZE 512 #define BLOCKSIZE 512
@@ -201,7 +205,7 @@ MLB *mlb_rsx_open(
int allow_objlib) int allow_objlib)
{ {
MLB *mlb = memcheck(malloc(sizeof(MLB))); MLB *mlb = memcheck(malloc(sizeof(MLB)));
char *buff; char *buff = NULL;
unsigned entsize; unsigned entsize;
unsigned nr_entries; unsigned nr_entries;
unsigned start_block; unsigned start_block;
@@ -210,6 +214,9 @@ MLB *mlb_rsx_open(
mlb->vtbl = &mlb_rsx_vtbl; mlb->vtbl = &mlb_rsx_vtbl;
mlb->directory = NULL; mlb->directory = NULL;
#if MLBDEBUG_OPEN
fprintf(stderr, "mlb_rsx_open('%s', %d)\n", name, allow_objlib);
#endif
mlb->fp = fopen(name, "rb"); mlb->fp = fopen(name, "rb");
if (mlb->fp == NULL) { if (mlb->fp == NULL) {
mlb_rsx_close(mlb); mlb_rsx_close(mlb);
@@ -219,20 +226,16 @@ MLB *mlb_rsx_open(
buff = memcheck(malloc(060)); /* Size of MLB library header */ buff = memcheck(malloc(060)); /* Size of MLB library header */
if (fread(buff, 1, 060, mlb->fp) < 060) { if (fread(buff, 1, 060, mlb->fp) < 060) {
fprintf(stderr, "error: can't read full header\n"); fprintf(stderr, "mlb_rsx_open error: can't read full header\n");
mlb_rsx_close(mlb); goto error;
free(buff);
return NULL;
} }
mlb->is_objlib = 0; mlb->is_objlib = 0;
if (allow_objlib && WORD(buff) == 01000) { /* Is it an object library? */ if (allow_objlib && WORD(buff) == 01000) { /* Is it an object library? */
mlb->is_objlib = 1; mlb->is_objlib = 1;
} else if (WORD(buff) != 01001) { /* Is this really a macro library? */ } else if (WORD(buff) != 01001) { /* Is this really a macro library? */
/* fprintf(stderr, "error: first word not correct value\n"); */ /* fprintf(stderr, "mlb_rsx_open error: first word not correct value\n"); */
mlb_rsx_close(mlb); /* Nope. */ goto error;
free(buff);
return NULL;
} }
entsize = buff[032]; /* The size of each macro directory entsize = buff[032]; /* The size of each macro directory
@@ -242,24 +245,33 @@ MLB *mlb_rsx_open(
directory */ directory */
if (entsize < 8) { /* Is this really a macro library? */ if (entsize < 8) { /* Is this really a macro library? */
mlb_rsx_close(mlb); /* Nope. */ fprintf(stderr, "mlb_rsx_open error: entsize too small: %d\n", entsize);
fprintf(stderr, "error: entsize too small: %d\n", entsize); goto error;
return NULL;
} }
// fprintf(stderr, "entsize=%d, nr_entries=%d, start_block=%d\n", if (start_block < 1) { /* Is this really a macro library? */
// entsize, nr_entries, start_block); fprintf(stderr, "mlb_rsx_open error: start_block too small: %d\n", start_block);
goto error;
}
#if MLBDEBUG_OPEN
fprintf(stderr, "entsize=%d, nr_entries=%d, start_block=%d\n",
entsize, nr_entries, start_block);
#endif
free(buff); /* Done with that header. */ free(buff); /* Done with that header. */
/* Allocate a buffer for the disk directory */ /* Allocate a buffer for the disk directory */
buff = memcheck(malloc(nr_entries * entsize)); buff = memcheck(malloc(nr_entries * entsize));
fseek(mlb->fp, start_block * BLOCKSIZE, SEEK_SET); /* Go to the directory */ /* Go to the directory */
if (fseek(mlb->fp, start_block * BLOCKSIZE, SEEK_SET) == -1) {
fprintf(stderr, "mlb_rsx_open error: seek error: %d\n", start_block * BLOCKSIZE);
goto error;
}
/* Read the disk directory */ /* Read the disk directory */
if (fread(buff, entsize, nr_entries, mlb->fp) < nr_entries) { if (fread(buff, entsize, nr_entries, mlb->fp) < nr_entries) {
mlb_rsx_close(mlb); /* Sorry, read error. */ fprintf(stderr, "mlb_rsx_open error: fread: not enough entries\n");
free(buff); goto error;
return NULL;
} }
/* Shift occupied directory entries to the front of the array */ /* Shift occupied directory entries to the front of the array */
@@ -269,11 +281,15 @@ MLB *mlb_rsx_open(
for (i = 0, j = nr_entries; i < j; i++) { for (i = 0, j = nr_entries; i < j; i++) {
char *ent1, char *ent1,
*ent2; *ent2;
int w1, w2;
ent1 = buff + (i * entsize); ent1 = buff + (i * entsize);
/* Unused entries have 0177777 0177777 for the RAD50 name, /* Unused entries have 0177777 0177777 for the RAD50 name,
which is not legal RAD50. */ which is not legal RAD50. */
if (WORD(ent1) == 0177777 && WORD(ent1 + 2) == 0177777) { w1 = WORD(ent1);
w2 = WORD(ent1 + 2);
if (w1 == 0177777 && w2 == 0177777) {
while (--j > i while (--j > i
&& (ent2 = buff + (j * entsize), WORD(ent2) == 0177777 && WORD(ent2 + 2) == 0177777)) ; && (ent2 = buff + (j * entsize), WORD(ent2) == 0177777 && WORD(ent2 + 2) == 0177777)) ;
if (j <= i) if (j <= i)
@@ -283,15 +299,31 @@ MLB *mlb_rsx_open(
space */ space */
memset(ent2, 0377, entsize); /* Mark entry unused */ memset(ent2, 0377, entsize); /* Mark entry unused */
} else { } else {
// fprintf(stderr, "entry %d: %02x%02x.%02x%02x\n", #if MLBDEBUG_OPEN
// i, ent1[5] & 0xFF, ent1[4] & 0xFF, ent1[7] & 0xFF, ent1[6] & 0xFF); fprintf(stderr, "entry %d: %02x%02x.%02x%02x\n",
i, ent1[5] & 0xFF, ent1[4] & 0xFF, ent1[7] & 0xFF, ent1[6] & 0xFF);
#endif
/*
* 00 00 rad50-decodes to spaces, which are not a
* valid name for a macro or object file.
*/
if (w1 == 0000000 && w2 == 0000000) {
fprintf(stderr, "mlb_rsx_open error: bad file, null name\n");
goto error;
}
} }
} }
/* Now i contains the actual number of entries. */ /* Now i contains the actual number of entries. */
mlb->nentries = i; mlb->nentries = i;
// fprintf(stderr, " mlb->nentries=%d\n", mlb->nentries); #if MLBDEBUG_OPEN
fprintf(stderr, "mlb->nentries=%d\n", mlb->nentries);
#endif
if (mlb->nentries == 0) {
fprintf(stderr, "mlb_rsx_open error: no entries\n");
goto error;
}
/* Now, allocate my in-memory directory */ /* Now, allocate my in-memory directory */
mlb->directory = memcheck(malloc(sizeof(MLBENT) * mlb->nentries)); mlb->directory = memcheck(malloc(sizeof(MLBENT) * mlb->nentries));
@@ -308,15 +340,28 @@ MLB *mlb_rsx_open(
unrad50(WORD(ent + 2), radname + 3); unrad50(WORD(ent + 2), radname + 3);
radname[6] = 0; radname[6] = 0;
// fprintf(stderr, "entry %d: \"%s\" %02x%02x.%02x%02x\n", #if MLBDEBUG_OPEN
// j, radname, fprintf(stderr, "entry %d: \"%s\" %02x%02x.%02x%02x\n",
// ent[5] & 0xFF, ent[4] & 0xFF, ent[7] & 0xFF, ent[6] & 0xFF); j, radname,
ent[5] & 0xFF, ent[4] & 0xFF, ent[7] & 0xFF, ent[6] & 0xFF);
#endif
trim(radname); trim(radname);
if (radname[0] == '\0' || strchr(radname, ' ')) {
fprintf(stderr, "mlb_rsx_open error: entry with space in name\n");
goto error;
}
mlb->directory[j].label = memcheck(strdup(radname)); mlb->directory[j].label = memcheck(strdup(radname));
mlb->directory[j].position = BYTEPOS(ent); mlb->directory[j].position = BYTEPOS(ent);
// fprintf(stderr, "entry %d: \"%s\" bytepos=%d\n", j, mlb->directory[j].label, mlb->directory[j].position); #if MLBDEBUG_OPEN
fprintf(stderr, "entry %d: \"%s\" bytepos=%ld\n", j, mlb->directory[j].label, mlb->directory[j].position);
#endif
mlb->directory[j].length = -1; mlb->directory[j].length = -1;
if (mlb->directory[j].position < BLOCKSIZE) {
fprintf(stderr, "mlb_rsx_open error: bad entry: position\n");
goto error;
}
} }
free(buff); free(buff);
@@ -324,6 +369,14 @@ MLB *mlb_rsx_open(
/* Done. Return the struct that represents the opened MLB. */ /* Done. Return the struct that represents the opened MLB. */
return mlb; return mlb;
error:
#if MLBDEBUG_OPEN
fprintf(stderr, "(mlb_rsx_open closing '%s' due to errors)\n", name);
#endif
mlb_rsx_close(mlb); /* Sorry, bad file. */
free(buff);
return NULL;
} }
/* mlb_rsx_close discards MLB and closes the file. */ /* mlb_rsx_close discards MLB and closes the file. */
@@ -367,28 +420,38 @@ BUFFER *mlb_rsx_entry(
} }
if (i >= mlb->nentries) { if (i >= mlb->nentries) {
// fprintf(stderr, "mlb_rsx_entry: %s not found\n", name); #if MLBDEBUG_ENTRY
fprintf(stderr, "mlb_rsx_entry: %s not found\n", name);
#endif
return NULL; return NULL;
} }
fseek(mlb->fp, ent->position, SEEK_SET); fseek(mlb->fp, ent->position, SEEK_SET);
// fprintf(stderr, "mlb_rsx_entry: %s at position %ld\n", name, (long)ent->position); #if MLBDEBUG_ENTRY
fprintf(stderr, "mlb_rsx_entry: %s at position %ld\n", name, (long)ent->position);
#endif
#define MODULE_HEADER_SIZE 022 #define MODULE_HEADER_SIZE 022
if (fread(module_header, MODULE_HEADER_SIZE, 1, mlb->fp) < 1) { if (fread(module_header, MODULE_HEADER_SIZE, 1, mlb->fp) < 1) {
// fprintf(stderr, "mlb_rsx_entry: %s at position %lx can't read 022 bytes\n", name, (long)ent->position); #if MLBDEBUG_ENTRY
fprintf(stderr, "mlb_rsx_entry: %s at position %lx can't read 022 bytes\n", name, (long)ent->position);
#endif
return NULL; return NULL;
} }
// for (i = 0; i < MODULE_HEADER_SIZE; i++) { #if MLBDEBUG_ENTRY
// fprintf(stderr, "%02x ", module_header[i]); for (i = 0; i < MODULE_HEADER_SIZE; i++) {
// } fprintf(stderr, "%02x ", module_header[i]);
// fprintf(stderr, "\n"); }
fprintf(stderr, "\n");
#endif
ent->length = (WORD(module_header + 04) << 16) + ent->length = (WORD(module_header + 04) << 16) +
WORD(module_header + 06); WORD(module_header + 06);
ent->length -= MODULE_HEADER_SIZE; /* length is including this header */ ent->length -= MODULE_HEADER_SIZE; /* length is including this header */
// fprintf(stderr, "mlb_rsx_entry: %s at position %lx length = %d\n", name, (long)ent->position, ent->length); #if MLBDEBUG_ENTRY
fprintf(stderr, "mlb_rsx_entry: %s at position %lx length = %d\n", name, (long)ent->position, ent->length);
#endif
if (module_header[02] == 1) { if (module_header[02] == 1) {
fprintf(stderr, "mlb_rsx_entry: %s at position %lx deleted entry\n", name, (long)ent->position); fprintf(stderr, "mlb_rsx_entry: %s at position %lx deleted entry\n", name, (long)ent->position);
@@ -418,19 +481,25 @@ BUFFER *mlb_rsx_entry(
i = fread(bp, 1, ent->length, mlb->fp); i = fread(bp, 1, ent->length, mlb->fp);
bp += i; bp += i;
} else if (module_header[0] & 0x10) { } else if (module_header[0] & 0x10) {
// fprintf(stderr, "mlb_rsx_entry: %s at position %lx variable length records\n", name, (long)ent->position); #if MLBDEBUG_ENTRY
fprintf(stderr, "mlb_rsx_entry: %s at position %lx variable length records\n", name, (long)ent->position);
#endif
/* Variable length records with size before them */ /* Variable length records with size before them */
i = ent->length; i = ent->length;
while (i > 0) { while (i > 0) {
int length; int length;
// fprintf(stderr, "file offset:$%lx\n", (long)ftell(mlb->fp)); #if MLBDEBUG_ENTRY
fprintf(stderr, "file offset:$%lx\n", (long)ftell(mlb->fp));
#endif
c = fgetc(mlb->fp); /* Get low byte of length */ c = fgetc(mlb->fp); /* Get low byte of length */
length = c & 0xFF; length = c & 0xFF;
c = fgetc(mlb->fp); /* Get high byte */ c = fgetc(mlb->fp); /* Get high byte */
length += (c & 0xFF) << 8; length += (c & 0xFF) << 8;
i -= 2; i -= 2;
// fprintf(stderr, "line length: %d $%x\n", length, length); #if MLBDEBUG_ENTRY
fprintf(stderr, "line length: %d $%x\n", length, length);
#endif
/* Odd lengths are padded with an extra 0 byte */ /* Odd lengths are padded with an extra 0 byte */
int padded = length & 1; int padded = length & 1;
@@ -441,7 +510,9 @@ BUFFER *mlb_rsx_entry(
while (length > 0) { while (length > 0) {
c = fgetc(mlb->fp); /* Get macro byte */ c = fgetc(mlb->fp); /* Get macro byte */
//fprintf(stderr, "%02x %c length=%d\n", c, c, length); #if MLBDEBUG_ENTRY
fprintf(stderr, "%02x %c length=%d\n", c, c, length);
#endif
i--; i--;
length--; length--;
if (c == '\r' || c == 0) /* If it's a carriage return or 0, if (c == '\r' || c == 0) /* If it's a carriage return or 0,
@@ -452,12 +523,16 @@ BUFFER *mlb_rsx_entry(
*bp++ = '\n'; *bp++ = '\n';
if (padded) { if (padded) {
c = fgetc(mlb->fp); /* Get pad byte; need not be 0. */ c = fgetc(mlb->fp); /* Get pad byte; need not be 0. */
//fprintf(stderr, "pad byte %02x %c length=%d\n", c, c, length); #if MLBDEBUG_ENTRY
fprintf(stderr, "pad byte %02x %c length=%d\n", c, c, length);
#endif
i--; i--;
} }
} }
} else { } else {
// fprintf(stderr, "mlb_rsx_entry: %s at position %lx byte stream records\n", name, (long)ent->position); #if MLBDEBUG_ENTRY
fprintf(stderr, "mlb_rsx_entry: %s at position %lx byte stream records\n", name, (long)ent->position);
#endif
for (i = 0; i < ent->length; i++) { for (i = 0; i < ent->length; i++) {
c = fgetc(mlb->fp); /* Get macro byte */ c = fgetc(mlb->fp); /* Get macro byte */
if (c == '\r' || c == 0) /* If it's a carriage return or 0, if (c == '\r' || c == 0) /* If it's a carriage return or 0,

View File

@@ -59,12 +59,20 @@ static void mlb_rt11_extract(
MLB *mlb); MLB *mlb);
struct mlb_vtbl mlb_rt11_vtbl = { struct mlb_vtbl mlb_rt11_vtbl = {
mlb_rt11_open, .mlb_open = mlb_rt11_open,
mlb_rt11_entry, .mlb_entry = mlb_rt11_entry,
mlb_rt11_extract, .mlb_extract = mlb_rt11_extract,
mlb_rt11_close, .mlb_close = mlb_rt11_close,
.mlb_is_rt11 = 1,
}; };
/*
* Format description:
* http://www.bitsavers.org/pdf/dec/pdp11/rt11/v5.6_Aug91/AA-PD6PA-TC_RT-11_Volume_and_File_Formats_Manual_Aug91.pdf
* pages 2-27 ff.
*
* A MLB Macro Library Header differs a lot from an Object Library Header.
*/
#define WORD(cp) ((*(cp) & 0xff) + ((*((cp)+1) & 0xff) << 8)) #define WORD(cp) ((*(cp) & 0xff) + ((*((cp)+1) & 0xff) << 8))
/* BYTEPOS calculates the byte position within the macro libray file. /* BYTEPOS calculates the byte position within the macro libray file.

1
mlb.h
View File

@@ -62,6 +62,7 @@ typedef struct mlb_vtbl {
BUFFER *(*mlb_entry)(MLB *mlb, char *name); BUFFER *(*mlb_entry)(MLB *mlb, char *name);
void (*mlb_extract)(MLB *mlb); void (*mlb_extract)(MLB *mlb);
void (*mlb_close)(MLB *mlb); void (*mlb_close)(MLB *mlb);
int mlb_is_rt11;
} MLB_VTBL; } MLB_VTBL;
extern MLB *mlb_open( extern MLB *mlb_open(

34
mlb2.c
View File

@@ -35,6 +35,7 @@ DAMAGE.
#include <string.h> #include <string.h>
#include "util.h" #include "util.h"
#include "mlb.h" #include "mlb.h"
#include "object.h"
MLB_VTBL *mlb_vtbls[] = { MLB_VTBL *mlb_vtbls[] = {
&mlb_rsx_vtbl, &mlb_rsx_vtbl,
@@ -42,25 +43,46 @@ MLB_VTBL *mlb_vtbls[] = {
NULL NULL
}; };
MLB *mlb_open( static MLB *mlb_open_fmt(
char *name, char *name,
int allow_object_library) int allow_object_library,
int object_format)
{ {
MLB_VTBL *vtbl; MLB_VTBL *vtbl;
MLB *mlb = NULL; MLB *mlb = NULL;
int i; int i;
for (i = 0; (vtbl = mlb_vtbls[i]); i++) { for (i = 0; (vtbl = mlb_vtbls[i]); i++) {
mlb = vtbl->mlb_open(name, allow_object_library); if (vtbl->mlb_is_rt11 == object_format) {
if (mlb != NULL) { mlb = vtbl->mlb_open(name, allow_object_library);
mlb->name = memcheck(strdup(name)); if (mlb != NULL) {
break; mlb->name = memcheck(strdup(name));
break;
}
} }
} }
return mlb; return mlb;
} }
MLB *mlb_open(
char *name,
int allow_object_library)
{
MLB *mlb = NULL;
/*
* First try the open function for the currently set object format.
* If that fails, try the other one.
*/
mlb = mlb_open_fmt(name, allow_object_library, rt11);
if (mlb == NULL) {
mlb = mlb_open_fmt(name, allow_object_library, !rt11);
}
return mlb;
}
BUFFER *mlb_entry( BUFFER *mlb_entry(
MLB *mlb, MLB *mlb,
char *name) char *name)