Download Pelles C here: http://www.pellesc.se
unsigned int decide(unsigned int x, unsigned int m)
{
return !((x & m) != 0) && ((x & 0x100u) == 0);
}
x & m = 0x279 & 0x002 = 0
(x & m) != 0 = 0
!((x & m) != 0) = 1
x & 0x100u = 0x279 & 0x100 = 0
(x & 0x100u) == 0 = 1
1 && 1 = 1
decide:
mov dword ptr [rsp+8],ecx
mov dword ptr [rsp+10],edx
mov eax,dword ptr [rsp+10]
test dword ptr [rsp+8],eax ; x & m
jne L_false
test dword ptr [rsp+8],100 ; x & 0x100
jne L_false
mov eax,1
ret
L_false:
mov eax,0
ret
decide:
xor eax,eax
test ecx,ecx ; x is tested against ITSELF
sete al
ret
_decide:
xor eax,eax
cmp dword ptr [esp+4],0
sete al
ret
both_const:
xor eax,eax
test ecx,102 ; 0x002 | 0x100 = 0x102 CORRECT
sete al
ret
unsigned int fused_by_hand(unsigned int x, unsigned int m)
{
return ((x & m) | (x & 0x100u)) == 0;
}
fused_by_hand:
xor eax,eax
or edx,100 ; m | 0x100
test ecx,edx
sete al
ret ; CORRECT
form emitted test verdict
----------------------------------------------------------------------
both masks compile-time constants test ecx,102 correct
first mask a parameter, second constant test ecx,ecx WRONG
first mask constant, second a parameter test ecx,ecx WRONG
both masks parameters test ecx,ecx WRONG
three conjuncts, first mask a parameter test ecx,ecx WRONG
signed int operands, otherwise identical test ecx,ecx WRONG
shared value left in first &, right in second test ecx,ecx WRONG
shared value is the right operand of both two tests correct
shared operand is a variable mask, values differ two tests correct
shared operand is a constant mask, values differ two tests correct
both masks are enumeration constants test ecx,14000 correct
single masked test, variable mask, no && test ecx,edx correct
the two tests on different variables two tests correct
fusion written by hand with | or, then test correct
|| with != 0 (the De Morgan dual) two tests correct
----------------------------------------------------------------------
decide:
xor %eax,%eax
or $0x1,%dh # sets bit 8 of edx: m | 0x100
test %ecx,%edx
sete %al
ret
if (!isFillOrder(tif, td->td_fillorder) &&
(tif->tif_flags & TIFF_NOBITREV) == 0)
TIFFReverseBits((uint8_t *)data, cc);
#define isFillOrder(tif, o) (((tif)->tif_flags & (o)) != 0)
#define TIFF_NOBITREV 0x00100U
pocc -Tx64-coff -std:C17 -c pellesc_1450_optimiser_bug.c
polink -subsystem:console -machine:x64 pellesc_1450_optimiser_bug.obj ^
crt64.lib kernel32.lib -out:noopt.exe
noopt.exe -> "All 7 cases correct." exit status 0
pocc -Tx64-coff -Ot -std:C17 -c pellesc_1450_optimiser_bug.c
polink -subsystem:console -machine:x64 pellesc_1450_optimiser_bug.obj ^
crt64.lib kernel32.lib -out:opt.exe
opt.exe -> "4 of 7 cases WRONG." exit status 1
src/pellesc_1450_optimiser_bug.c self-checking reproducer, run it twice
src/bug.c the single function, for disassembly
src/variants.c ten of the forms in the table above
src/characterise.c the same test across operand values
src/hypothesis.c demonstrates the transformation performed
src/shared_mask.c shared mask versus shared value
src/position.c which operand position matters
src/enum_masks.c enumeration constants as masks
disassembly/bug_no_optimisation_x64.asm correct
disassembly/bug_Ot_x64.asm WRONG
disassembly/bug_Ot_x86.asm WRONG
disassembly/variants_Ot_x64.asm all variants
disassembly/shared_mask_Ot_x64.asm
disassembly/position_Ot_x64.asm
disassembly/enum_masks_Ot_x64.asm
disassembly/bug_gcc_O2_control.asm GCC 13 -O2, correct
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
FindChar PROC src:DWORD,char:DWORD
eax to point the string to search for a specific character :
mov eax,DWORD PTR [esp+4]
ecx holding the character to be found :
mov ecx,DWORD PTR [esp+8]
Decrement eax so modifying eax should not interfer with the only jmp jz
dec eax
@@:
inc eax
Get a byte from eax pointing the string
mov dl,BYTE PTR [eax]
Check if it's NULL terminator
test dl,dl
If dl is NULL set dh to 1
setz dh
If ( dl XOR cl ) == 0 the we found the char we were looking for.
dl XOR cl is zero if dl == cl :
xor dl,cl
setz ch
If none of the conditions above are met then return back to the top of the loop :
or ch,dh
jz @b
retn 8
FindChar ENDP
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDefQuote from: KEL26 on September 03, 2026, 01:39:12 AM=====================================Kelly PellesC isn't open source, the only person that could take a corrective action is Pelle.
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.
sum += (*data)++;
Quote from: TimoVJL on September 01, 2026, 07:42:46 PMint __cdecl printf(const char * restrict format, ...);also with
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;
}sum += (*data)++;outputchecksum 19900 (correct 19900)
EDIT: a simple checkint __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;
}
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
#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);
}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
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
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
pocc /?
int t = i % 300;
*pdata = (unsigned char)t; /* see my note below, just in case any one wants to write to me! */
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.
Page created in 0.050 seconds with 15 queries.