Pelles C forum

Pelles C => Bug reports => Topic started by: KEL26 on August 30, 2026, 11:09:48 PM

Title: optimiser emits ud2 (invalid-opcode trap) for a fully defined C loop at -Ot and
Post by: KEL26 on August 30, 2026, 11:09:48 PM
Hello Pelle,

First, thank you for Pelles C — it has just carried a full port of CFITSIO
4.7.0 (NASA's FITS library, 59 sources), zlib, libpng and FFTW 3.3.11 to a
clean finish, so the report below comes from a codebase your compiler
otherwise handles admirably.

SUMMARY
-------
Pelles C 14.50.0 for Windows x64, compiling the attached self-contained
program (about one screen of code), translates the loop

    for (i = 0; i < 200; i += 1) {
        data = (unsigned char)(i % 256);
    }

(over a local  unsigned char data[200])  into a loop body whose FIRST
instruction is  ud2 , so the program dies with exception 0xC000001D on the
first iteration. The store that follows the trap reads  al , which no
instruction in the function ever writes — the value computation has been
deleted entirely. The statement is fully defined ISO C: i is in [0,200),
so i % 256 is well defined and non-negative, the conversion to unsigned
char is well defined, and the store is in bounds.

ENVIRONMENT
-----------
    Pelles C 14.50.0, Windows 10 x64 (build 19045)
    pocc -Tx64-coff -Ot -W1 -std:C17 -Ze pelle_repro.c
    polink -machine:x64 -subsystem:console pelle_repro.obj kernel32.lib

OBSERVED (same source, three settings)
--------------------------------------
    -Ot          RESULT : EXCEPTION 0xC000001D
    -Os          RESULT : EXCEPTION 0xC000001D
    (no -O...)   RESULT : SURVIVED   checksum 19900 (expect 19900)

DISASSEMBLY (podump /disasm of the -Ot object, the loop in full)
----------------------------------------------------------------
    [0050] 0F0B            ud2
    [0052] 4863D3          movsxd  rdx,ebx
    [0055] 888414EC000000  mov     byte ptr [rsp+rdx+0ECh],al
    [005C] 83C301          add     ebx,1
    [005F] 81FBC8000000    cmp     ebx,0C8h
    [0065] 7CE9            jl      0050

NOTES THAT MAY HELP LOCATE IT
-----------------------------
1. The mistranslation is sensitive to the surrounding frame: the identical
   loop in a different function (static buffer, checksum in a separate
   loop) compiles correctly at -Ot on the same machine. The attached
   reproducer therefore keeps the exact frame of the function in which the
   fault was first observed — the same locals in the same order, and calls
   through a volatile function pointer where the original code called into
   a library. Simplifying the frame may make the fault vanish.
2. The pattern (unsigned char)(expr % 256) appears in a dozen other files
   of the same project that compile correctly, consistent with note 1.
3. Discovered because a unit test of the CFITSIO port died with
   "CRT: unhandled exception" before its first library call; an
   __try/__except wrapper reported 0xC000001D, and podump named the ud2.

A SECOND, UNRELATED ISSUE, MENTIONED FOR COMPLETENESS
-----------------------------------------------------
The same project also hit what the evidence indicates is a stack-slot
assignment fault at -Ot in one large function of CFITSIO's imcompress.c:
two live locals (a 4-byte char array, address escaping through a pointer
array, and a 12-byte char array) appear to have shared storage, so a
12-byte strcpy destroyed the 4-byte string; rearranging the locals into
one union cured it. An isolated replica of the declarations does NOT
reproduce it — the full function seems to be needed — so I am not
attaching that one until it has a reproducer worth your time. I can supply
the full analysis on request.

With thanks and best regards,
Kelly

Attachment: pelle_repro.c