This fixes the following issues:
*If n was 0x80000000 or greater, strncmp would return 0 without performing a comparison.
*If n was 0x1000000 or greater, strncmp might compare fewer characters than it should because the high byte of n was effectively ignored, causing it to return 0 when it should not.
Here is an example demonstrating these issues:
#pragma memorymodel 1
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define LEN 100000
int main(void) {
char *s1 = malloc(LEN+1);
char *s2 = malloc(LEN+1);
if (!s1 || !s2)
return 0;
for (unsigned long i = 0; i < LEN; i++) {
s2[i] = s1[i] = '0' + (i & 0x07);
}
s1[LEN] = 'x';
return strncmp(s1,s2,0xFFFFFFFF);
}
This addresses the following issues:
*If the low-order 16 bits of n were 0x0000, no concatenation would be performed.
*If n was 0x1000000 or greater, the output could be cut off prematurely because the high byte of n was effectively ignored.
The following test program demonstrates these issues:
#pragma memorymodel 1
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define LEN2 100000
int main(void) {
char *s1 = malloc(LEN2+2);
char *s2 = malloc(LEN2+1);
if (!s1 || !s2)
return 0;
for (unsigned long i = 0; i < LEN2; i++)
s2[i] = '0' + (i & 0x07);
strcpy(s1,"a");
strncat(s1, s2, 0x1000000);
puts(s1);
printf("len = %zu\n", strlen(s1));
}
There were two issues:
*If bit 15 of the n value was set, the second string would not be copied.
*If the length of the second string was 64K or more, it would not be copied properly because the pointers were not updated.
This test program demonstrates both issues:
#pragma memorymodel 1
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define LEN2 100000
int main(void) {
char *s1 = malloc(LEN2+2);
char *s2 = malloc(LEN2+1);
if (!s1 || !s2)
return 0;
for (unsigned long i = 0; i < LEN2; i++)
s2[i] = '0' + (i & 0x07);
strcpy(s1,"a");
strncat(s1, s2, LEN2);
puts(s1);
printf("len = %zu\n", strlen(s1));
}
Previously, the pointer was not properly updated to account for the bank crossing, so the characters from the second string would be written to the wrong bank.
Here is an example that illustrates this:
#include <memory.h>
#include <string.h>
#include <orca.h>
#include <stdio.h>
int main(void) {
Handle hndl = NewHandle(0x1000f, userid(), 0xC000, 0);
if (toolerror())
return 0;
char *s = *hndl;
s = (void*)((unsigned long)s | 0xffff);
strcpy(s, "foo");
strcat(s, "bar");
strncat(s, "baz", 5);
puts(s);
}
Most files already used spaces, but three used tabs for indentation. These have been converted to use spaces. This allows the files to be displayed with proper formatting in modern editors and on GitHub. It also removes any dependency on SysTabs settings when assembling them.
The spacing in fpextra.asm was also modified to use standard column positions.
There are no non-whitespace changes in this commit.
If the upper byte of the int argument was nonzero, it could write the wrong value (the OR of the upper and lower bytes). It should convert the value to unsigned char, i.e. just use the lower byte.
Tabs have been expanded to spaces in several files that use mainly spaces for indentation.
The files ctype.asm, stdio.asm, and string.asm consistently use tabs for indentation. The tabs in these files have been left alone, except that a few tabs between sentences in comments were changed to spaces. One space-indented line in stdio.asm was changed to use a tab.
It had been doing a null pointer dereference and effectively treating memory locations starting from 0 as the continuation of the string, potentially producing inappropriate results depending on what they contained.