Menu

#4056 Pointer math on void * results in no change

closed-fixed
None
Front-end
5
2026-09-12
2026-08-10
Under4Mhz
No

The following code incorrectly calculates the pointer value. void * is still a pointer and should be able to add to it. gcc seems to default to a size of 1 byte for void * .
If the decision is void * is of unknown size and should not be able to add it, then I think an error would be more appropriate. I was expecting the gcc behaviour and it was unexpected to find it adding nothing, without a warning.

/// GPL 2.0 or later
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

#define VDU_RAM_START 0xc000

void GameSet( uint8_t game ) {

    printf( "%p\n", (void*)VDU_RAM_START + 0x100 );
    printf( "%p\n", ((void*)VDU_RAM_START) + 0x100 );
    printf( "%p\n", (void*)(VDU_RAM_START + 0x100) );
    printf( "%p\n", (uint8_t*)VDU_RAM_START + 0x100 );

    void *ptr = (void*)VDU_RAM_START;
    ptr++;

    printf( "%p\n", ptr );
}

void main(void) {

    printf( "Start\n" );

    GameSet( 1 );

    printf( "End\n" );
}

#ifdef __SDCC
__sfr __at 0xff sif;
int putchar( int c ) {

    sif = 'p';
    sif = c;

    return c;
}
#endif
$ sdcc -mz80 --fverbose-asm ./ptr_math.c  -o ptr_math.ihx && ucsim_z80 -I if=outputs[0xff] ptr_math.ihx
Simulation started, PC=0x000000
Start
0xc000
0xc000
0xc100
0xc100
0xc000
End


$ gcc ./ptr_math.c && ./a.out
Start
0xc100
0xc100
0xc100
0xc100
0xc001
End
$ sdcc -v
SDCC : z80/sm83/ez80/z80n/mos6502/mos65c02 4.6.2 #16701 (Linux)
2 Attachments

Discussion

  • Maarten Brock

    Maarten Brock - 2026-08-10

    AFAIK in general sizeof(void) is undefined behaviour.
    SDCC has chosen that the size of void is zero and thus a void* increments with 0.

     
  • Maarten Brock

    Maarten Brock - 2026-08-10

    Looking deeper in the C standard (my emphasis):

    6.2.5.24 The void type comprises an empty set of values; it is an incomplete object type that cannot be completed.

    6.5.3.4.1 The sizeof operator shall not be applied to an expression that has function type or an incomplete type, to the parenthesized name of such a type, or to an expression that designates a bit-field member. The alignof operator shall not be applied to a function type or an incomplete type.

    Thus, SDCC should probably output at least a warning and possibly an error.

     
    • Benedikt Freisen

      Yes. I agree that this should probably result in a diagnostic message, regardless of the chosen behavior. I wouldn't mind sizeof(void) == 1, though.

       
  • Maarten Brock

    Maarten Brock - 2026-08-27

    In [r833] I introduced warning W_SIZEOF_VOID, but it seems not to be triggered here. It only triggers on ++ and --. And we also have error E_SIZEOF_INCOMPLETE_TYPE which does not trigger.

     

    Last edit: Maarten Brock 2026-08-27
    • Philipp Klaus Krause

      Yes, and we have ptr++ here, and I see the warning on that line when compiling the given ode sample. So the bug here is that we don't emit the warning for other additions / subtractions.

      P.S.: subtractions are worst: we don't even get the error when the pointer points to an incompletet type other than void!

       

      Last edit: Philipp Klaus Krause 2026-08-29
  • Philipp Klaus Krause

    • assigned_to: Philipp Klaus Krause
    • Category: other --> Front-end
     
  • Philipp Klaus Krause

    • status: open --> closed-fixed
     
  • Philipp Klaus Krause

    Fixed in [r16829].

     

    Related

    Commit: [r16829]

  • Maarten Brock

    Maarten Brock - 2026-08-30

    I see now that regression test bug-524691.c tries to subtract two void pointers and was added to test there was no division by zero generated. But with sizeof(void)==0 a division by zero is exactly what should be generated.

          void * pBase, *p;
    
          /* A divide by zero is added just before iDiff is assigned */
          int iDiff = pBase - p;
    
          if (iDiff > 0)
            <something>
          else if (iDiff < 0)
            <something else>
          else
            <last resort>
    

    I would be ok with comparing any void pointer against another void pointer, but subtracting is really wrong IMHO.

          void * pBase, *p;
    
          if (pBase > p)
            <something>
          else if (pBase < p)
            <something else>
          else
            <last resort>
    
     
  • Maarten Brock

    Maarten Brock - 2026-08-30

    @spth Can you please have a look at the attached patch. I think these are also places that could use the warning.

    Maarten

     
    • Philipp Klaus Krause

      I'm a bit busy at the moment, will have a look towards the end of next week.

       
    • Philipp Klaus Krause

      Regarding the warning put into SDCCicode.c: I think this needs to be much broader. void * is the harmless case here. The much bigger problem is incompatible types in general: we currently don't warn for e.g. subtracting a char* from an int*, and just pretend the right operand has the same type as the left one. It makes sense to have the warning in your patch for subtracting void* from void*, but the patch also emits it if just one is void*, IMO if just one is void* we should get a warning about incompatible types instead.

       
      • Maarten Brock

        Maarten Brock - 2026-09-12

        Oops, SDCC indeed just subtracts char* from int*. That's not good!

        I can imagine casting a single void* to the other pointer type as that resembles the automatic cast case when assigning. Two void pointers should IMHO not be subtractable.

         
    • Philipp Klaus Krause

      Regarding the warning put into SDCCast.c: the first and second look good to me, but we should also introduce a test for them in support/valdiag/tests; for the third I don't understand how we could reach the new warning.

       

Log in to post a comment.