Thread: Passing restricted pointers to non-restricted function parameters

  1. #1
    Registered User
    Join Date
    Mar 2024
    Posts
    20

    Passing restricted pointers to non-restricted function parameters

    Is passing a restricted pointer to a function parameter that has no restrict qualifier defined behavior?

    For example:
    Code:
    #include <string.h>
    
    int main(void) {
        char *restrict s = "string";
        size_t n = strlen(s);
        
        return 0;
    }
    The strlen prototype is:
    Code:
    size_t strlen(const char *s);
    Is this valid?
    Last edited by Sabidos; 07-26-2024 at 03:53 PM.

  2. #2
    Registered User
    Join Date
    Dec 2017
    Posts
    1,664
    restrict only applies when the object is modified.
    strlen does not modify the passed object.
    See strcpy. Also, compare memcpy and memmove.
    Code:
    char *strcpy( char *restrict dest, const char *restrict src );
    
    void* memcpy ( void *restrict dest, const void *restrict src, size_t count );
    void* memmove( void *         dest, const void *         src, size_t count );
    Also note that in your code, s should be const char * since it points to a string literal, which cannot be modified.
    Last edited by john.c; 07-27-2024 at 11:25 AM.
    All truths are half-truths. - A.N. Whitehead

  3. #3
    Registered User
    Join Date
    Apr 2021
    Posts
    148
    The restrict qualifier tells the compiler that the data accessed through a pointer is only accessible through that pointer -- there is no other way to get to that data.

    This means that the compiler can generate code that assumes the data fetched through the pointer does not change, except when the compiler tells it to change using the pointer (or some derivative).

    Note the "or some derivative" part. If your function receives a restrict pointer and makes a copy of it:
    Code:
    void f(char restrict *p) {
        char * q = p;
    
        q[2] = 'x';
    }
    That is perfectly okay. That does not violate the restrict qualifier. And the compiler can know the effect simply by analyzing the behavior of the code inside the function.

    Realistically, this means that the compiler has to tag all the "related" pointers that might be based on the input pointer, and when a change is made through one such pointer, all the other pointers have to be marked as possibly tainted unless the compiler can show they pointer to different areas in memory - which is usually either impossible or really easy to do.

    If you have a function that does not declare its pointer arguments restrict it either means (1) the coder that wrote the function didn't know how to use restrict; or (2) the function really doesn't care about changes that might take place via other paths. As @john.c points out, a function that doesn't make any changes, like strlen, definitely doesn't need to know about "other" changes.

    On the other hand, if you take a pointer and make changes through it, and don't mark it restrict, the compiler may be forced to generate slightly slower code. Most of the time, you don't care about this.

    For more information, look up the Strict Aliasing Rule, a different approach to the same problem (aliasing).

  4. #4
    Registered User
    Join Date
    Mar 2024
    Posts
    20
    So the behavior is undefined only if the variable is modified through another pointer that's not the restricted pointer itself? What if the value is changed through the variable the restricted pointer points to?

    For example:
    Code:
    #include <stdio.h>
    
    int main(void) {
        int i = 0;
        int *ptr = &i;
        int *restrict r_ptr = &i; /*    Wouldn't this be undefined? Another pointer
                                        points to that address */
        
        // Accessing value through non-restricted pointer
        (void) printf("%i\n", *ptr);
        
        
        /* Modifying value through variable, and accessing value through
        non-restricted pointer */
        i = 1;
        (void) printf("%i\n", *ptr);
        
        
        /* Modifying and accessing value through restriced pointer */
        *r_ptr = 2;
        (void) printf("%i\n", *r_ptr);
        
        
        /* Modifying value through variable, and accessing value through restricted
        pointer */
        i = 3;
        (void) printf("%i\n", *r_ptr);
        
        
        /* Modifying value through non-restricted pointer, and accessing value
        through restricted pointer. Is this the only undefined case? */
        *ptr = 4;
        (void) printf("%i\n", *r_ptr);
        
        
        return 0;
    }
    Wouldn't the assignment of the address to the restricted pointer cause undefined behavior? And if it doesn't, is the last scenario the only one that causes undefined behavior?

    And if read-only variables are unaffected, why do some functions in the standard library declare parameters as restricted pointers to constants?

    Code:
    int printf(const char *restrict format, ...);
    
    size_t fwrite(const void * restrict ptr, size_t size, size_t nmemb, FILE * restrict stream);
    Os is this a safeguard just in case the pointer points to a string literal (in the case of printf) or a constant array (in the case of fwrite)?
    Last edited by Sabidos; 08-01-2024 at 01:35 PM.

  5. #5
    Registered User
    Join Date
    Apr 2021
    Posts
    148
    First, you're right. The mix of restrict and non-restrict in your example will likely create a cascade of diagnostic messages.

    Second, keep in mind that const in a parameter declaration does not say "this is in read-only memory." It says "this function will not modify what you pass in."
    Code:
    main()
    {
        char buf[100] = "%s\n";
    
        printf(buf, "My dog has fleas!");
    }
    Why does this not cause problems? Because the const char * declaration of the first argument to printf is a promise that printf won't modify the string. It's not a promise that the program won't change buf while printf is running -- because when printf is running, the rest of the program is not running, so of course it won't change!

    So const char *restrict fmt declares a parameter that (1) this function promises not to modify; and (2) this function demands had better not overlap with any other input.

    If you think about it, the "modification" option for -/s/f printf only exists relative to the %n option for storing the number of bytes. There just isn't anything else that printf does that modifies outside memory. So printf is really saying "you had better not point the %n parameter at the format string!"

  6. #6
    Registered User
    Join Date
    Dec 2017
    Posts
    1,664
    As aghast said, for printf the format string could be written into by the %n specifier. That would be very strange, but possible.
    For fwrite, the buffer could in theory be written to by the stream, since a stream is not necessarily a file (consider C++ stringstream).
    Again, strange but possible.
    All truths are half-truths. - A.N. Whitehead

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Restricted floats for scanf
    By scotdani in forum C Programming
    Replies: 1
    Last Post: 04-10-2018, 07:04 PM
  2. Restricted pointers C99.
    By Mr.Lnx in forum C Programming
    Replies: 7
    Last Post: 07-20-2013, 07:06 PM
  3. Restricted Integer
    By kolucoms6 in forum C++ Programming
    Replies: 6
    Last Post: 03-01-2008, 08:59 PM
  4. Forum Restricted
    By XelleX90 in forum A Brief History of Cprogramming.com
    Replies: 5
    Last Post: 12-26-2006, 08:54 AM
  5. How restricted am I by console mode
    By The Gweech in forum C++ Programming
    Replies: 2
    Last Post: 03-20-2002, 09:25 PM

Tags for this Thread