News:

Download Pelles C here: http://www.pellesc.se

Main Menu

Recent posts

#1
Bug reports / Re: optimiser emits ud2 (inval...
Last post by Michele - September 03, 2026, 08:38:21 AM
Quote from: KEL26 on September 03, 2026, 01:39:12 AM=====================================

Please, to all helpful users, read all of my text in each section,  before 'helping' me out - I explained the problem as clear as I could, with code and words - please explain using sentences rather than just pure code - the penny will then, hopefully, drop.
Kelly PellesC isn't open source, the only person that could take a corrective action is Pelle.
What the other users are doing is to supply other test cases for Pelle to hopefully help debugging.
Those aren't answers to help directly with your case.
We have to wait for Pelle now.

And I still couldn't understand the sense to insert such opcode, if the compiler meet a problem should fail under compilation phase, not let a time bomb instruction code in the executable, unless it was there to help compiler debug. And for some reason Pelle forget to remove it when the compiler was released.
#2
Bug reports / Re: optimiser emits ud2 (inval...
Last post by KEL26 - September 03, 2026, 01:39:12 AM
=====================================

Please, to all helpful users, read all of my text in each section,  before 'helping' me out - I explained the problem as clear as I could, with code and words - please explain using sentences rather than just pure code - the penny will then, hopefully, drop.
I am a professional programmer and I have been debugging C-language with (almost) 'ease' for years.  How to detect the bug, this code, has been shown in my zipped folder, that I attached for Dear Pelle and for all who wish to see, I appreciate explanations with any code you post to help me and others.

=====================================

Robert, thank you. Your printf line gives the clearest picture of the fault so far. Under /O2 it prints all two hundred stored values cycling 0 to 43, and it does so in both of your optimised runs. That is the bug in full: 300 modulo 256 is 44.

The change to the checksum line does not alter that, and your own output shows it. The printed array is identical, and wrong, in both /O2 runs. Only the checksum differs, and the reason is that

sum += (*data)++;

never reads the element at index i. It reads the first element two hundred times, adding the old value and incrementing it, so from zero it sums 0+1+...+199 = 19900 whatever the other 199 bytes contain. I checked this by filling the array with 0xFF in every byte but the first, which was set to zero: that loop still prints 19900.

So the fix changed the measurement rather than the data. The array your program prints is the real result. It is wrong under /O2 and right without it, which is exactly what Timo's element check found and what has now gone to Pelle. Your run makes it three machines.
#3
Bug reports / Re: optimiser emits ud2 (inval...
Last post by Robert - September 02, 2026, 10:54:39 PM
Quote from: TimoVJL on September 01, 2026, 07:42:46 PMint __cdecl printf(const char * restrict format, ...);
int __cdecl main(void)
{
    int i;
    unsigned long sum = 0;
    unsigned char *pdata;    // pointer to data
    unsigned char data[200];    // safer stack place at end ?

    pdata = data;
    for (i = 0; i < 200; i++)
        *pdata++ = (unsigned char)(i % 300);

    pdata = data;
    for (i = 0; i < 200; i++)
        sum += *pdata++;
        //sum += (*data)++;

    printf("checksum %lu (correct 19900)\n", sum);
    return 0;
}
also with
sum += (*data)++;output
checksum 19900 (correct 19900)
EDIT: a simple check
int __cdecl printf(const char * restrict format, ...);
int __cdecl main(void)
{
    unsigned char *pdata; // pointer to data
    int i;
    unsigned char data[200];

    pdata = data;
    for (i = 0; i < 200; i++)
    {
        *pdata = (unsigned char)(i % 300);
        if (*pdata != i)
        {
            printf("\nerror: %u != %u\n", i, *pdata);
            break;
        }
        printf("%u ", *pdata);
        pdata++;
    }
    return 0;
}


int __cdecl printf(const char * restrict format, ...);
int __cdecl main(void)
{
    int i;
    unsigned long sum = 0;
    unsigned char *pdata;    // pointer to data
    unsigned char data[200];    // safer stack place at end ?

    pdata = data;
    for (i = 0; i < 200; i++)
        *pdata++ = (unsigned char)(i % 300);

    pdata = data;
    for (i = 0; i < 200; i++)
        {
        printf("%i ", data[i]);
        // sum += *pdata++;
         sum += (*data)++;
        }

    printf("checksum %lu (correct 19900)\n", sum);
    return 0;
}

/*
/O2 optimization
using "sum += *pdata++;"
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 checksum 4060 (correct 19900)
*/

/*
/O2 optimization
using "sum += (*data)++;"
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 checksum 19900 (correct 19900)
*/
 
/*
No /O2 optimization
using "sum += *pdata++;"
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 checksum 19900 (correct 19900)
*/

/*
No /O2 optimization
using "sum += (*data)++;"
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 checksum 19900 (correct 19900)
*/

#4
Assembly discussions / NetUserGetInfo example
Last post by Vortex - September 02, 2026, 09:38:12 PM
Based on the NetUserGetInfo API function, command-line application displaying the lockout status of a local account :

include LockStatus.inc

.data

f1      dw 'The account %s is NOT locked.',0
f2      dw 'The account %s is locked.',0
f3      db 'Usage : LockStatus <Account>'
        db 13,10,0

sTable  dd OFFSET f1,OFFSET f2
ErrMsg  db 'NetUserGetInfo failed.',0

.data?

ui4     dd ? ; USER_INFO_4
args    dd ?

.code

start:

    call    main
    invoke  ExitProcess,eax
   
main PROC uses esi

    invoke  GetCommandLineW
    invoke  CommandLineToArgvW,eax,ADDR args

    cmp     args,1
    jne     @f

    invoke  printf,ADDR f3
    ret
@@:
    mov     esi,eax
    invoke  NetUserGetInfo,0,\
            DWORD PTR [eax+4],4,ADDR ui4

    test    eax,eax
    jz      @f

    invoke  printf,ADDR ErrMsg
    xor     eax,eax
    ret
@@:
    mov     eax,USER_INFO_4.usri4_flags[ui4]
    and     eax,UF_LOCKOUT
    shr     eax,2
    lea     edx,[sTable+eax]
    shr     eax,2
    push    eax
    invoke  wprintf,DWORD PTR [edx],\
            DWORD PTR [esi+4]

    invoke  NetApiBufferFree,ui4
    pop     eax
    ret

main ENDP

END start
#5
Bug reports / Re: optimiser emits ud2 (inval...
Last post by TimoVJL - September 02, 2026, 08:29:49 PM
Kelly,
You found a bug and now we have a small example code for it, so now just wait Pelle's opinion.
Using pointer was just an another test for it.

EDIT: for minimal executable for debugging, but needs msvcrt.libs :
#pragma comment(lib, "msvcrt.lib")
int __cdecl printf(const char * restrict format, ...);
int __stdcall ExitProcess(int);
void __cdecl mainCRTStartup(void)
{
    unsigned char *pdata; // pointer to data
    int i;
    unsigned char data[200];

    pdata = data;
    for (i = 0; i < 200; i++)
    {
        *pdata = (unsigned char)(i % 300);
        if (*pdata != i)
        {
            printf("\nerror: %u != %u\n", i, *pdata);
            break;
        }
        printf("%u ", *pdata);
        pdata++;
    }

    ExitProcess(0);
}

EDIT: useful Add-Ins ?

https://forum.pellesc.de/index.php?topic=5248.0

https://forum.pellesc.de/index.php?topic=4467.0

https://forum.pellesc.de/index.php?msg=26516
#6
Bug reports / Re: optimiser emits ud2 (inval...
Last post by KEL26 - September 02, 2026, 06:49:20 PM
Please reply with the information I request. Thank you, TimoVJL.

Your second program is a better test than my checksum,
because it can fail on the exact element that goes wrong, and I have adopted it.

Compiled exactly as you posted it, with no changes, on Pelles C 14.50.0 for x64:

pocc -Tx64-coff -std:C17 -Ze -Zx -W1 -Ot check.c
polink -subsystem:console -machine:x64 check.obj crt64.lib kernel32.lib -out:check.exe
check.exe

it prints

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
error: 44 != 0

The same with -Os and with -Ox. With no -O switch at all it prints all
two hundred values and no error line.

The object code for the store that your check reads back, at -Ot:

mov     dl,2C            ; 0x2C is 44, and 300 mod 256 is 44
mov     al,dil
xor     ah,ah
div     dl               ; the 8-bit divide
mov     al,ah            ; the remainder
mov     byte ptr [rsi],al
cmp     byte ptr [rsi],dil

44 mod 44 is 0, which is the 0 in the error line.

Your first program, the pointer checksum,
behaves the same way here: 4060 at -Ot, -Os and -Ox,
and 19900 with no optimisation.
So the pointer form does not avoid it on this machine,
and neither does the position of the array in the frame.

That leaves exactly one difference between us: the optimisation switch.
Would you run your own check with -Ot given explicitly on the command line, as above,
and say what it prints? If it prints the error line, we have the same result.
If it prints all two hundred values for you at -Ot,
then something differs between our installations that I would very much like to identify,
and the first line of

pocc /?

would help.

For anyone hitting this today, the form I would still suggest is

int t = i % 300;
*pdata = (unsigned char)t;  /* see my note below, just in case any one wants to write to me! */

which keeps the remainder in an int object, so the narrowing to unsigned char
is never part of the same expression and the rewrite has nothing to attach to.

N.B.
Why *pdata is right in TimoVJL's loop

TimoVJL's check walks the array with the pointer itself:
it stores through *pdata, compares, and then does pdata++ at the bottom of the loop.
Inside that loop the current element is *pdata, full stop.
My suggestion keeps his loop shape and changes only the two lines that matter — compute in int,
then narrow — so he can drop it straight into his own program.
I verified it: at -Ot it stores all two hundred elements correctly and the check never fires.


Using pdata[i] inside TimoVJL's loop would compile, but combined with his pdata++ it would
advance twice per iteration and write to the wrong places.
Using *pdata inside an indexed loop would write every value to element zero.
Each form is right in its own loop; *pdata[i] is right in neither.

#8
Bug reports / Re: optimiser emits ud2 (inval...
Last post by John Z - September 02, 2026, 09:58:19 AM
Hi KEL26,

Wow what can I say? Thank you!
Exemplary, superb, an excellent piece of work.
Thanks for your work and help and I appreciate the
time you spent doing the extra extensive documentation.

John Z

#9
Beginner questions / Re: Working Directory woes
Last post by MrBcx - September 02, 2026, 01:37:50 AM
Quote from: John Z on September 01, 2026, 09:24:22 PMDon't delete a good example for others to see to not give up.


That's good advice. 

If you're not making mistakes then you're not learning anything.

... and ...

You gotta break a few eggs, if you wanna make an omelet!


#10
Bug reports / Re: optimiser emits ud2 (inval...
Last post by KEL26 - September 02, 2026, 12:57:34 AM

The defect, stated exactly,

At -Os, -Ot and -Ox, Pelles C 14.50 for Windows x64 can replace the
constant divisor K of an integer remainder by K modulo 256.

I attach a zipped folder (edited) showing how to build a bug/defect free zlib (no source patch is required) and folder of code which shows evidence for this bug and my bug tracing code!

Hope it helps others - and hope soon this excellent IDE and compiler become open source - it would make the process of bug tracking and fixing super-fast - I am from a Linux background.