~mcf

https://mforney.org

Trackers

~mcf/cproc

Last active 2 days ago

~mcf/x509cert

Last active 1 year, 1 month ago

~mcf/dnssec-rr

Last active 2 years ago

~mcf/libtls-bearssl

Last active 2 years ago

~mcf/qbe

Last active 3 years ago

~mcf/oasis

Last active 3 years ago

~mcf/sbase

Last active 3 years ago

~mcf/samurai

Last active 3 years ago

#80 segfault when returning before a switch statement 22 hours ago

Comment by ~mcf on ~mcf/cproc

This is a long-standing issue that stems from funcinst returning NULL when we haven't introduced a new QBE block, and we have already have a jump for the current block. The intent was to avoid generating unreachable code, but it causes problems when more control flow follows after the jump.

One fix could be to make stmt() split up parsing and code generation, and skip the latter if the current block is already terminated. However, the much simpler solution is just to insert a dummy block when we encounter this situation. QBE will discard unreachable blocks quite early in the pipeline, so I think that's what I'll do.

Fixed by 4fa48e716d6381e51ae8dc7a9992c4c7d50219a1.

REPORTED RESOLVED FIXED

#79 Assertion failed: tq == QUALNONE (expr.c: decay: 101) 3 days ago

Comment by ~mcf on ~mcf/cproc

I noticed this issue also during bootstrap on OpenBSD (https://builds.sr.ht/~mcf/job/757621).

The issue is related to qualifiers on array types. The C standard says that when an array type is qualified, the qualifiers apply to the element type, not the array type itself. Although this is handled partially at the end of decl.c:declspecs(), there are still a few cases where we incorrectly applied qualifiers to an array type:

  1. If you qualify a nested array type, e.g. typedef int T[1][1]; const T x;. declspecs only passes the qualifiers through one layer of array, so x ends up as "array of const array of int" instead of "array of array of const int".
  2. If you access an array member of a struct or union, the qualifiers of the struct/union get applied to the member type, but don't get passed through to the element type of the array member.

Commit b82a231 fixed a bug where an expression with array type would decay into a pointer with the qualifiers of the array type (which should always be empty as per above) and ignore the qualifiers of the array element type. However, due to 1 and 2 above, there are cases where we might end up with a qualified array type, which now trigger the assertion. I think you are hitting case 2 above (removing the const from repl_cmds is a workaround).

As for a solution, I have two ideas:

  1. Add a function that applies qualifiers to an array type by walking down until it finds a non-array type, rebuilding it as it goes and applying the qualifiers to that non-array type. Then change declspecs and postfixexpr to use that.
  2. Previously, things mostly ended up working despite this bug since the qualifiers were applied down to the element type during the implicit conversion of an array to a pointer to first element. Perhaps it would be sufficient to combine the qualifiers in decay() (i.e. t->qual | tq), and then somehow relax typecompatible() to treat "qualified array of type" and "array of qualified type" the as equivalent.

I still need to think more about it to determine the best way forward. I have some plans to change up how types are represented, which I think should make this easier to deal with. So even though it's still not quite correct, perhaps the best thing to do for now is the diff below.

diff --git a/expr.c b/expr.c
index 67976b8..532ad60 100644
--- a/expr.c
+++ b/expr.c
@@ -98,9 +98,14 @@ decay(struct expr *e)
 	tq = e->qual;
 	switch (t->kind) {
 	case TYPEARRAY:
+		/*
+		TODO: qualifiers should be applied to the element
+		type of array types, not the array type itself
+
 		assert(tq == QUALNONE);
+		*/
 		e = mkunaryexpr(TBAND, e);
-		e->type = mkpointertype(t->base, t->qual);
+		e->type = mkpointertype(t->base, t->qual | tq);
 		e->decayed = true;
 		break;
 	case TYPEFUNC:

#1 Variable-length arrays 17 days ago

Comment by ~mcf on ~mcf/cproc

See the earlier discussion. The problem is that alloca and VLAs behave differently in a loop. Memory allocated by alloca gets deallocated when the function returns, but VLAs get deallocated at the end of the block. Naively compiling VLAs as alloca could result in stack overflows in some of the examples above.

#35 Prefixed string literals 8 months ago

on ~mcf/cproc

REPORTED RESOLVED FIXED

#62 Build musl libc 9 months ago

Comment by ~mcf on ~mcf/cproc

It only uses -fPIC when it detects that the compiler enables it by default. Since cproc is using gcc as a preprocessor, if gcc is built with --enable-default-pie it defines __PIC__ by default, which is not correct since qbe doesn't generate position-independent code.

I pushed a couple of commits to fix this. Now, you should be able to do CC=cproc ./configure --target=x86_64-linux-musl && make -k lib/libc.a to see all the errors.

There are only a handful of unique errors, but these are all major features that need support from QBE (apart from _Complex maybe):

$ make -k lib/libc.a 2>&1 | grep -e error: -e cproc-qbe: | sort -u
./arch/x86_64/atomic_arch.h:3:2: error: inline assembly is not yet supported
./arch/x86_64/syscall_arch.h:6:2: error: inline assembly is not yet supported
./include/complex.h:16:8: error: _Complex is not yet supported
cproc-qbe: long double is not yet supported
src/network/if_nameindex.c:95:52: error: VLAs are not yet supported
src/process/execl.c:12:20: error: VLAs are not yet supported
src/process/execle.c:12:20: error: VLAs are not yet supported
src/process/execlp.c:12:20: error: VLAs are not yet supported
src/process/execvp.c:29:15: error: VLAs are not yet supported
src/search/lsearch.c:6:17: error: VLAs are not yet supported
src/string/explicit_bzero.c:6:2: error: inline assembly is not yet supported
$

#75 Explicit Types Confuse Initializer 9 months ago

Comment by ~mcf on ~mcf/cproc

Thanks for the clear report and test case.

This syntax is perfectly fine for initializing local variables inside a function, but not for static or global variables. The C standard describes this restriction in 6.7.9p4:

All the expressions in an initializer for an object that has static or thread storage duration shall be constant expressions or string literals.

What you have here on the right hand side is a compound literal expression, which is not a constant expression or string literal. A constant expression must be one of the following (6.6p7):

  • an arithmetic constant expression,
  • a null pointer constant,
  • an address constant, or
  • an address constant for a complete object type plus or minus an integer constant expression.

I believe the reason why this works in gcc and clang is because of 6.7p10:

An implementation may accept other forms of constant expressions.

But this is not something you can rely upon in your code. And indeed, if you enable -Wpedantic, gcc will warn about this:

test.c:2:20: warning: initializer element is not constant [-Wpedantic]
    2 | struct dummy str = (struct dummy){.label = "Redraw"};

The reason that struct dummy str = {.label = "Redraw"}; works is because there is only one expression in the initializer, the string literal "Redraw", which is explicitly allowed in initializers of global and static variables.

I got in the habit of doing this back when initializer "type inference" was worse and noticed it while trying to compile a program of mine.

I'm not sure what you mean by this. C doesn't have any initializer type inference; you always have to specify the types of the objects you initialize.

#66 Handle #line directives 9 months ago

on ~mcf/cproc

REPORTED RESOLVED FIXED

#74 Segfaults on invalid syntax 10 months ago

Comment by ~mcf on ~mcf/cproc

Thanks for the report. The problem was that declarator() was allowing an abstract function declarator (struct x(), i.e. function with unspecified arguments returning struct x), even when allowabstract was false.

Fixed by 87553780.

REPORTED RESOLVED FIXED

#458 qbe fails to optimize away stack slot for unused value 11 months ago

~sircmpwn assigned ~mcf to #458 on ~sircmpwn/hare

#73 Incomplete enum is not caught in struct field 11 months ago

Comment by ~mcf on ~mcf/cproc

Thanks for the report. This is fixed in eb4320fc.

I also added a few other checks to make sure that structs have at least one member and the flexible array member (if present) is last.

REPORTED RESOLVED FIXED