Thread: size_t and negative values

  1. #1
    Registered User
    Join Date
    Feb 2022
    Location
    Canada, PEI
    Posts
    103

    size_t and negative values

    I have a problem with validating the values of a size_t. How do I prevent negative values assigned to a size_t variable..

    Here's the code that's causing the problems:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    #define DEFAULT_ARRAY_SIZE 2
    
    void check_allocation(void * ptr, const char * func) {
      if (!ptr) {
        fprintf(stderr, "Allocation failed for %s\n", func);
        //exit(EXIT_FAILURE);
      }
    }
    
    unsigned int* create_array(size_t length) {//This fails if length is < 0
      size_t _length = length <= 0 ? DEFAULT_ARRAY_SIZE : length;
      fprintf(stdout, "create_array _length: %ld\n", _length);
      unsigned int* ans = calloc(_length, sizeof(*ans));
      check_allocation(ans, "create_array");
      return ans;
    }
    
    unsigned int* create_array_2(signed int length) {//This does not fail if length is < 0
      size_t _length = length <= 0 ? DEFAULT_ARRAY_SIZE : length;
      fprintf(stdout, "create_array_2 _length: %ld\n", _length);  
      unsigned int* ans = calloc(_length, sizeof(*ans));
      check_allocation(ans, "create_array_2");
      return ans;
    }
    
    int main(int argc, char ** argv) {
      unsigned int * arr = create_array(-12);
      unsigned int * arr_2 = create_array_2(-12);
    
      fprintf(stdout, "%p %p\n", (void*)arr, (void*)arr_2);//just to block warnings about unused vars
      return 0;
    }
    The problem is in create_array function. If I pass a negative value to this function it fails in unpredictable ways(well unpredictable me).
    If I use the function create_array_2 then I can check for a negative values and take corrective actions.

    Is create_array_2 the correct way to valid the values used for something that will eventually be a size_t value?

  2. #2
    Registered User
    Join Date
    Apr 2021
    Posts
    140
    The standard specifies that size_t is an "unsigned integer type." If you declare a parameter of type size_t and try to pass a negative value as an argument in a call to the function, the compiler should be emitting a warning about type conversion.

    In addition, if you are comparing the parameter for less-than-zero, you should be getting another "wasting the CPU's time" warning message.

    Finally, if you "hide" or "shadow" a parameter with a local variable, you should probably get another warning about that.

    So recommendation 1 is going to be: "Compile with ALL the warnings turned on."

  3. #3
    Registered User
    Join Date
    Feb 2022
    Location
    Canada, PEI
    Posts
    103
    Actually I did compile with all warnings on.
    gcc -Wall -pedantic -Werror -o main main.c
    This is not generating any warnings when I compile. This why I posted the question.

    Here's my compiler specs:
    gcc (Ubuntu 9.4.0-1ubuntu1~20.04) 9.4.0
    I even tried some online C compilers and all ran without generating any warnings.
    Last edited by G4143; 03-09-2022 at 10:07 PM.

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    This is the flag you want.
    Code:
    $ gcc -Wall -Wconversion foo.c
    foo.c: In function ‘create_array_2’:
    foo.c:22:20: warning: conversion to ‘size_t’ {aka ‘long unsigned int’} from ‘int’ may change the sign of the result [-Wsign-conversion]
       22 |   size_t _length = length <= 0 ? DEFAULT_ARRAY_SIZE : length;
          |                    ^~~~~~
    foo.c: In function ‘main’:
    foo.c:30:37: warning: unsigned conversion from ‘int’ to ‘size_t’ {aka ‘long unsigned int’} changes value from ‘-12’ to ‘18446744073709551604’ [-Wsign-conversion]
       30 |   unsigned int * arr = create_array(-12);
          |                                     ^~~
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    Feb 2022
    Location
    Canada, PEI
    Posts
    103
    @Salem... That did it. Its funny that -Wall doesn't include -Wconversion.

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    Like many warnings that are not enabled by default, they can be more annoying than useful in many cases.

    Even with a warning, you might want to do this anyway.
    Code:
    // if length is bigger than this, maybe it's an errant negative
    #define NEGATIVE_LENGTH_TRAP 10000000
    // if overall size is bigger than this, bail out
    #define MAX_ALLOC_SIZE 1000000000
    
    unsigned int* create_array(size_t length) {
      if ( length >= NEGATIVE_LENGTH_TRAP ) return NULL;
    
      fprintf(stdout, "create_array length: %zd\n", length);
      unsigned int* ans = NULL;
    
      // trap for arithmetic overflow in computing length * sizeof(*ans) later on in calloc
      if ( MAX_ALLOC_SIZE / sizeof(*ans) < length ) return NULL; 
    
      ans = calloc(length, sizeof(*ans));
      check_allocation(ans, "create_array");
      return ans;
    }
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Registered User
    Join Date
    Feb 2019
    Posts
    1,078
    It is good to remember that "signal" on integer types are just semantic.
    Code:
    // with sizeof(int)=4.
    int x = -1;
    unsigned int y == 0xffffffff;
    At binary level, both values are the same if two's complement is in use (almost all computers today!).
    If you do:
    Code:
    void *p = malloc( -1 );
    You are asking to allocate 4 GiB - 1 bytes (2³²-1 = 0xffffffff) for i386 mode or 16 EiB - 1 bytes (2⁶⁴-1 = 0xffffffffffffffff) for x86-64 mode.
    Last edited by flp1969; 03-10-2022 at 04:56 AM.

  8. #8
    Registered User
    Join Date
    Feb 2022
    Location
    Canada, PEI
    Posts
    103
    Quote Originally Posted by Salem View Post
    Like many warnings that are not enabled by default, they can be more annoying than useful in many cases.

    Even with a warning, you might want to do this anyway.
    Code:
    // if length is bigger than this, maybe it's an errant negative
    #define NEGATIVE_LENGTH_TRAP 10000000
    // if overall size is bigger than this, bail out
    #define MAX_ALLOC_SIZE 1000000000
    
    unsigned int* create_array(size_t length) {
      if ( length >= NEGATIVE_LENGTH_TRAP ) return NULL;
    
      fprintf(stdout, "create_array length: %zd\n", length);
      unsigned int* ans = NULL;
    
      // trap for arithmetic overflow in computing length * sizeof(*ans) later on in calloc
      if ( MAX_ALLOC_SIZE / sizeof(*ans) < length ) return NULL; 
    
      ans = calloc(length, sizeof(*ans));
      check_allocation(ans, "create_array");
      return ans;
    }
    Now that encourages me to ask... Can you define the sizes on the compile line? I know you can interact with defined entities to some extent on the compile line but can you actually modify the values of defined entities from the compile line.

    I'd think that would be handy. You could compile the code to certain constraints.

  9. #9
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    You can do this in the code.
    Code:
    #ifndef NEGATIVE_LENGTH_TRAP
    #define NEGATIVE_LENGTH_TRAP 10000000
    #endif

    And this on the command line for the default
    gcc foo.c

    And this if you want your own special sauce.
    gcc -DNEGATIVE_LENGTH_TRAP=123456789 foo.c
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. what is size_t and why should we use it
    By cooper1200 in forum C Programming
    Replies: 11
    Last Post: 06-03-2019, 09:40 AM
  2. Replies: 2
    Last Post: 02-04-2016, 08:11 AM
  3. Replies: 2
    Last Post: 06-29-2012, 05:11 AM
  4. Replies: 3
    Last Post: 06-21-2012, 01:16 AM
  5. entering 0s and negative values into while
    By cool_guy in forum C++ Programming
    Replies: 5
    Last Post: 04-14-2010, 06:34 PM

Tags for this Thread