*Use a typedef rather than a macro definition for va_list. (The C standards specify that va_list is a type, although this would make a practical difference only if someone #undef'd it.)
*Don't include a semicolon in va_start(), so it expands to an expression rather than a statement. This could make a difference in a construct like "if (...) va_start(...); else ...".
An extra, fourth byte was being generated for the bitfield(s). This would cause all subsequent members of the struct and any enclosing object not to be initialized at the proper locations, which would generally corrupt their values.
The following program illustrates the issue:
#include <stdio.h>
struct X {
int a:9;
int b:9;
int c;
} x = {123,234,12345};
int main(void) {
printf("x.a = %i, x.b = %i, x.b = %i\n", x.a, x.b, x.c);
}
The initialized bytes for the bitfield(s) could wind up improperly being placed after those for the non-bitfield, generally corrupting both values.
The following program illustrates the problem:
#include <stdio.h>
struct X {
int a:9;
int b;
} x = {42,123};
int main(void) {
printf("x.a = %i, x.b = %i\n", x.a, x.b);
}
Note that this code currently permits discarding the const qualifier via such an initialization. That should give a diagnostic, but currently it doesn't in this or various other cases.
The following code (derived from a csmith-generated test case) illustrates the problem:
struct S0 {
const long f4;
};
const struct S0 g_149;
const long *g_311 = &g_149.f4;
This could happen because the left subexpression does not produce a result for use in the enclosing expression, and therefore is not of the form expected by the CSE code.
The following program (derived from a csmith-generated test case) illustrates the problem:
#pragma optimize 16
int main(void) {
int i;
i, (i, 1);
}
There was a bug when storing addresses generated by expressions like &a[i], where a is a global array and i is a variable. In certain cases where the destination location was a local variable that didn't fit in the direct page, the result of the address calculation would be stored to the wrong location on the stack. This failed to give the correct result, and could also sometimes cause crashes or other problems due to stack corruption.
The following program (derived from a csmith-generated test case) illustrates the issues:
#pragma optimize 1
long g_87[5];
static int g_242 = 4;
int main(void) {
char l_298[256];
long *l_284[3] = {0, 0, &g_87[g_242]};
return l_284[2]-g_87; /* should be 4 */
}
Specifically:
*The result of pointer arithmetic (or equivalent operations like &a[i]) always has pointer type.
*Array types decay to integer types in the context of comparison operations, so it is legal to compare two differently-sized arrays with the same element type.
The following program (partially derived from a csmith-generated test case) illustrates the issues:
int main(void) {
int a[2], b[10];
if (a == b) ; /* legal */
if (&a[1] != &b[0]) ; /* legal */
return sizeof(&b[1]); /* Should be sizeof(int*), i.e. 4 on GS */
}
The code would trash other data on the stack, which could corrupt other variables and in some cases lead to crashes.
The following program (derived from a csmith-generated test case) shows the problem:
#pragma optimize -1
int main(void) {
char arr[256] = {0};
char l_565[3][2] = {{3,4}, {5,6}, {7,8}};
l_565[0][0]++;
return l_565[0][0];
}
The following program (derived from a csmith-generated test case) demonstrates the crash:
#pragma optimize 8+64
#include <stdio.h>
long g = 0;
int main (void) {
long l = 0x10305070;
printf("%08lx\n", l ^ (g = (1 , 0x12345678)));
}
This was a bug with the code for moving the return address. It would generate a "LDA 0" instruction when it was trying to load the value at DP+256.
The following program (derived from a csmith-generated test case) demonstrates the crash:
#pragma optimize 8
int main (int argc, char **argv) {
char s[0xFC];
}
This problem could lead to crashes in code like the following (derived from a csmith-generated test case):
#pragma optimize 1
int main (void)
{
if (1L) ;
}
This problem could lead to crashes in code like the following (derived from a csmith-generated test case):
#pragma optimize 1
static int main(void) {
long i = 2;
(long)(i > 1);
}
The previous code may have been intended to convert this to a "!=0" test, which would have been valid if correctly implemented, but with the current code generator that actually yields worse code than the original version, so for now I just removed the optimization for this case.
This problem could lead to crashes in code like the following (derived from a csmith-generated test case):
#pragma optimize 1
int main(int argc, char *argv[]){
long l_57 = argc;
return (4 ^ l_57) && 6;
}
This affected comparisons of the form "logical operation or comparison == constant other than 0 or 1". These should always evaluate to 0 (false), but could mis-evaluate to true due to the bad optimization.
The following program gives an example showing the problem:
#pragma optimize 1
int main(void) {
int i = 0, j = 42;
return (i || j) == 123;
}
Here's an example that shows the issues (derived from a csmith-generated test case):
struct S {
unsigned f;
};
void f1(struct S p) {
printf("%u\n", p.f);
}
int main(void) {
const struct S l = {123};
struct S s;
f1(l);
s = l;
printf("%u\n", s.f);
}
Such subexpressions are not of the right form to work with the existing code, because they do not generate a value for use in the enclosing expression. For now, the code has been changed to simply not remove the subexpression in these cases. Alternative code could be written to make it work, but that might be more trouble than it's worth.
Here's an example that shows the problem (derived from a csmith-generated test case):
#pragma optimize 32+1 /* also had a problem with just 32 */
int main(void) {
int x, y=10; /* also had problems if x was global */
do {
x=42, y-=1;
} while (y);
return x+y;
}
This would lead to errors in programs like the following:
int main(void) {
typedef int x;
x: ;
}
Even before support for mixed statements and declarations was introduced, this error could happen if the labeled statement was the first statement after the declarations in a block (as in the above example). Adding that support also allowed this error to happen with later statements in a block. The C4.2.4.1.CC test case was affected by this.
Under these rules, if, switch, for, while, and do statements each have their own block scopes separate from the enclosing scope, and their substatements also have their own block scopes.
This patch always applies the C99 scope rules, but a flag can be changed to disable them or make them conditional on a configuration setting.
commit 4265329097538640e9e21202f1b141bcd42a44f3
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date: Fri Mar 23 21:45:32 2018 -0400
indent to match standard indent.
commit 783518fbeb01d2df43ef2083d3341004c05e4e2e
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date: Fri Mar 23 20:21:15 2018 -0400
clean up the typenames
commit 29b627ecf5ca9b8a143761f85a1807a6ca35ddd9
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date: Fri Mar 23 20:18:04 2018 -0400
enable feature_hh, warn about %n with non-int modifier.
commit fc4ac8129e3772c4eda36658e344ec475938369c
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date: Fri Mar 23 15:13:47 2018 -0400
warn thar %lc, %ls, etc are unsupported.
commit 7e6b433ba0552f7e52f0f034d398e9195c764326
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date: Fri Mar 23 13:36:25 2018 -0400
warn about hh/ll modifier (if not supported)
commit 1943c9979d0013f9f38045ec04a962fbf0269f31
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date: Fri Mar 23 11:42:41 2018 -0400
use error facilities for format errors.
commit 7811168f56dca1387055574ba8d32638da2fad96
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date: Thu Mar 22 15:34:21 2018 -0400
add feature flags to disable c99 enhancements until orca lib is updated.
commit c2149cc5953155cfc3c3b4d0483cd25fb946b055
Author: Kelvin Sherlock <ksherlock@gmail.com>
Date: Thu Mar 22 08:59:10 2018 -0400
Add printf/scanf format checking [WIP]
This parses out the xprintf / xscanf format string and compares it with the function arguments.
enabled via #pragma lint 16.
In the case of structs or unions, an error is now produced. This addresses one of the problems mentioned in issue #53.
In the case of arrays, tentative definitions like "int i[];" are now permitted at file scope. If not completed by a subsequent definition, this winds up producing an array with one element, initialized to 0. See the discussion and example in C99/C11 section 6.9.2 (or C90 section 6.7.2 and example in TC1).
Memory for them is still allocated from the global pool, to ensure they remain available for as long as the function prototype that references them.
This addresses one of the problems mentioned in issue #53.
In order to work right, this needs either GNO's ORCALib (which already included isblank()) or a copy of ORCA's ORCALib with the corresponding patch applied.
Previously, when a struct type first appeared in a symbol table nested within another struct type, subsequent references to that type would use the wrong offset and be corrupted. This occurred because the symbol table length had not yet been updated to reflect the size of the entry for the outer structure at the time the inner one was processed.
Fixes#54.
It had been changed to reflect changes in the ORCALib code that added a second putback buffer element, but those changes were problematic and have been reverted for now. (It's also not clear if ORCALib binaries with the larger putback buffer were ever distributed--at the least, they aren't on Opus ][ or in any of the ORCA/C 2.2.0 beta releases.)
This allows the code to be displayed properly on GitHub and in modern text editors, which typically do not support the irregularly-spaced tab stops used for ORCA/M code. It also avoids any possibility of problems building the code if the SysTabs file is missing or has been customized with non-standard tab stops.
If there are no varargs calls (and nothing else that saves stack positions), then space doesn't need to be allocated for the saved stack position. This can also lead to more efficient prolog/epilog code for small functions.
Previously, the stack repair code always generated code to save and restore a register, but this can be omitted except in cases where a 32-bit value or pointer is returned.
Previously, when stack repair code was generated, it always included instructions to save and restore a previously-saved stack position, but this was only actually used for function calls nested within the arguments to other function calls using stack repair code. Now that code is only generated in cases where it is needed, and the stack repair code for other calls is simplified to omit it.
This optimization affects all (non-nested) function calls when not using optimize bit 3, and varargs function calls when not using optimize bit 6.