UNIX version 7 bugs

This document describes the UNIX version 7 errors fixed at the Vrije Universiteit, Amsterdam. Several of these are discovered at the VU. Others are quoted from a list of bugs distributed by BellLabs.

For each error the differences between the original and modified source files are given, as well as a test program.

ERROR 1: C optimizer bug for unsigned comparison

The following C program caused an IOT trap, while it should not (compile with ’cc -O prog.c’):

unsigned

i = 0;

main() {

register j;

j = -1;
if (i > 40000)

abort();

}

BellLabs suggests to make the following patch in c21.c:

     /* modified /usr/src/cmd/c/c21.c */

189

if (r==0) {
190

/* next 2 lines replaced as indicated by
191

* Bell Labs bug distribution ( v7optbug )
192

p->back->back->forw = p->forw;
193

p->forw->back = p->back->back;
194

End of lines changed */
195

if (p->forw->op==CBR
196

|| p->forw->op==SXT
197

|| p->forw->op==CFCC) {
198

p->back->forw = p->forw;
199

p->forw->back = p->back;
200

} else {
201

p->back->back->forw = p->forw;
202

p->forw->back = p->back->back;
203

}
204

/* End of new lines */
205

decref(p->ref);
206

p = p->back->back;
207

nchange++;
208

} else if (r>0) {

Use the previous program to test before and after the modification.

ERROR 2: The loader fails for large data or text portions

The loader ’ld’ produces a "local symbol botch" error for the following C program.

int

big1[10000] = {

1

};

int

big2[10000] = {

2

};

main() {

printf("loader is fine\n");

}

We have made the following fix:

     /* original /usr/src/cmd/ld.c */

113

struct {
114

int

fmagic;
115

int

tsize;
116

int

dsize;
117

int

bsize;
118

int

ssize;
119

int

entry;
120

int

pad;
121

int

relflg;
122

} filhdr;

/* modified /usr/src/cmd/ld.c */

113

/*
114

* The original Version 7 loader had problems loading large
115

* text or data portions.
116

* Why not include <a.out.h> ???
117

* then they would be declared unsigned
118

*/
119

struct {
120

int

fmagic;
121

unsigned

tsize;

/* not int !!! */
122

unsigned

dsize;

/* not int !!! */
123

unsigned

bsize;

/* not int !!! */
124

unsigned

ssize;

/* not int !!! */
125

unsigned

entry;

/* not int !!! */
126

unsigned

pad;

/* not int !!! */
127

unsigned

relflg;

/* not int !!! */
128

} filhdr;

ERROR 3: Floating point registers

When a program is swapped to disk if it needs more memory, then the floating point registers were not saved, so that it may have different registers when it is restarted. A small assembly program demonstrates this for the status register. If the error is not fixed, then the program generates an IOT error. A "memory fault" is generated if all is fine.

start:

ldfps

$7400
1:

stfps

r0

mov

r0,-(sp)

cmp

r0,$7400

beq

1b

4

Some digging into the kernel is required to fix it. The following patch will do:

     /* original /usr/sys/sys/slp.c */

563

a2 = malloc(coremap, newsize);
564

if(a2 == NULL) {
565

xswap(p, 1, n);
566

p->p_flag |= SSWAP;
567

qswtch();
568

/* no return */
569

}

/* modified /usr/sys/sys/slp.c */

590

a2 = malloc(coremap, newsize);
591

if(a2 == NULL) {
592

#ifdef FPBUG
593

/*
594

* copy floating point register and status,
595

* but only if you must switch processes
596

*/
597

if(u.u_fpsaved == 0) {
598

savfp(&u.u_fps);
599

u.u_fpsaved = 1;
600

}
601

#endif
602

xswap(p, 1, n);
603

p->p_flag |= SSWAP;
604

qswtch();
605

/* no return */
606

}

ERROR 4: Floating point registers.

A similar problem arises when a process forks. The child will have random floating point registers as is demonstrated by the following assembly language program. The child process will die by an IOT trap and the father prints the message "child failed".

exit

= 1.
fork

= 2.
write

= 4.
wait

= 7.

start:

ldfps

$7400

sys

fork

br

child

sys

wait

tst

r1

bne

bad

stfps

r2

cmp

r2,$7400

beq

start

4
child:

stfps

r2

cmp

r2,$7400

beq

ex

4
bad:

clr

r0

sys

write;mess;13.
ex:

clr

r0

sys

exit

.data
mess:

<child failed\n>

The same file slp.c should be patched as follows:

     /* original /usr/sys/sys/slp.c */

499

/*
500

* When the resume is executed for the new process,
501

* here’s where it will resume.
502

*/
503

if (save(u.u_ssav)) {
504

sureg();
505

return(1);
506

}
507

a2 = malloc(coremap, n);
508

/*
509

* If there is not enough core for the
510

* new process, swap out the current process to generate the
511

* copy.
512

*/

/* modified /usr/sys/sys/slp.c */

519

/*
520

* When the resume is executed for the new process,
521

* here’s where it will resume.
522

*/
523

if (save(u.u_ssav)) {
524

sureg();
525

return(1);
526

}
527 #ifdef FPBUG
528

/* copy the floating point registers and status to child */
529

if(u.u_fpsaved == 0) {
530

savfp(&u.u_fps);
531

u.u_fpsaved = 1;
532

}
533 #endif
534

a2 = malloc(coremap, n);
535

/*
536

* If there is not enough core for the
537

* new process, swap out the current process to generate the
538

* copy.
539

*/

ERROR 5: /usr/src/libc/v6/stat.c

Some system calls are changed from version 6 to version 7. A library of system call entries, that make a version 6 UNIX look like a version 7 system, is provided to run some useful version 7 utilities, like ’tar’, on UNIX-6. The entry for ’stat’ contained two bugs: the 24-bit file size was incorrectly converted to 32 bits (sign extension of bit 15) and the uid/gid fields suffered from sign extension.

Transferring files from version 6 to version 7 using ’tar’ will fail for all files for which

( (size & 0100000) != 0 )

These two errors are fixed if stat.c is modified as follows:

/* original /usr/src/libc/v6/stat.c */

11

char os_size0;
12

short os_size1;
13

short os_addr[8];

49

buf->st_nlink = osbuf.os_nlinks;
50

buf->st_uid = osbuf.os_uid;
51

buf->st_gid = osbuf.os_gid;
52

buf->st_rdev = 0;

/* modified /usr/src/libc/v6/stat.c */

11

char os_size0;
12

unsigned os_size1;
13

short os_addr[8];

49

buf->st_nlink = osbuf.os_nlinks;
50

buf->st_uid = osbuf.os_uid & 0377;
51

buf->st_gid = osbuf.os_gid & 0377;
52

buf->st_rdev = 0;