Thread: Help with progamming assignment

  1. #16
    I'm a computer snoopfrogg's Avatar
    Join Date
    Feb 2019
    Posts
    29
    Quote Originally Posted by flp1969 View Post
    Probably not "seg fault" because the granularity of data segment (or rodata, or stack) is 4 KiB, but definitively "garbage".

    @snoopfrog, when you declare and initiailze an array as:
    Code:
    char s[] = "a";
    This array has 2 bytes only. It is the same as:
    Code:
    char s[] = { 'a', '\0' };
    If you do:
    Code:
    char *p = s;
    When you do an indirect access with * operador adding an offset of 2, like *(p+2), you are referencing something, but not an element of the array s.
    Thanks for the feedback. I really appreciate it. What's the best way to avoid referencing garbage in my case? The program works for the test cases I was given, but I'd rather not practice bad programming habits.
    "One of the best programming skills you can have is knowing when to walk away for awhile."

  2. #17
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,715
    Of course it will segfault if it has 2 or less characters, it means it would have reached the end of that 4Kib, it's just usually a null byte would normally be encountered before that happens, however I did forget about the garbage output and the memory corruption

  3. #18
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,715
    Quote Originally Posted by snoopfrogg View Post
    Thanks for the feedback. I really appreciate it. What's the best way to avoid referencing garbage in my case? The program works for the test cases I was given, but I'd rather not practice bad programming habits.
    Look back at the psuedo code I gave you and you'll find the answer

  4. #19
    Registered User
    Join Date
    May 2012
    Location
    Arizona, USA
    Posts
    904
    Quote Originally Posted by flp1969 View Post
    Still problematic... Consider if str points to string with a single character: "a". When your code do:
    Code:
    if(*(str) == *(str + 1) && (*(str) == *(str + 2)))
    Then (str+2) will point to "garbage"...
    Nope, it's not a problem.

    If "*(str + 1)" is the null terminator (which is will be if the string is "a"), then "*(str)" will not be equal to it, so then "(*(str) == *(str + 2))" will not be executed. Therefore there is no access to "*(str + 2)", and its contents don't matter.

  5. #20
    Registered User
    Join Date
    Feb 2019
    Posts
    1,048
    Quote Originally Posted by awsdert View Post
    Of course it will segfault if it has 2 or less characters
    Try it:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    int main ( void )
    {
      char s[2] = { 1, 2 };
      char *p = s;
      int count;
    
      // Printing all bytes from s to the end of the page.
      // NO SEGFAULT!
      count = 17;
      printf ( "%p:", p );
    
      for ( ; ( size_t ) p & 0xfff; p++ )
      {
        if ( ! --count )
        {
          printf ( "\n%p:", p );
          count = 16;
        }
    
        printf ( " %02hhx", *p );
      }
    
      putchar ( '\n' );
    }
    And you'll get something like this:
    Code:
    0x7ffcf2145dd6: 01 02 00 87 10 d2 f3 55 02 dd c0 e7 46 56 bd 55
    0x7ffcf2145de6: 00 00 97 cb 3c 72 06 7f 00 00 01 00 00 00 00 00
    0x7ffcf2145df6: 00 00 c8 5e 14 f2 fc 7f 00 00 00 80 00 00 01 00
    0x7ffcf2145e06: 00 00 fa e6 46 56 bd 55 00 00 00 00 00 00 00 00
    0x7ffcf2145e16: 00 00 ae 43 90 f2 8b 6a cf 56 f0 e5 46 56 bd 55
    0x7ffcf2145e26: 00 00 c0 5e 14 f2 fc 7f 00 00 00 00 00 00 00 00
    0x7ffcf2145e36: 00 00 00 00 00 00 00 00 00 00 ae 43 f0 86 2e 22
    0x7ffcf2145e46: 4c 02 ae 43 8e ab 7f 22 b9 03 00 00 00 00 fc 7f
    0x7ffcf2145e56: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x7ffcf2145e66: 00 00 33 c7 7a 72 06 7f 00 00 38 26 79 72 06 7f
    0x7ffcf2145e76: 00 00 aa 2d 0a 00 00 00 00 00 00 00 00 00 00 00
    0x7ffcf2145e86: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0x7ffcf2145e96: 00 00 f0 e5 46 56 bd 55 00 00 c0 5e 14 f2 fc 7f
    0x7ffcf2145ea6: 00 00 1a e6 46 56 bd 55 00 00 b8 5e 14 f2 fc 7f
    0x7ffcf2145eb6: 00 00 1c 00 00 00 00 00 00 00 01 00 00 00 00 00
    0x7ffcf2145ec6: 00 00 f2 80 14 f2 fc 7f 00 00 00 00 00 00 00 00
    0x7ffcf2145ed6: 00 00 f6 80 14 f2 fc 7f 00 00 0c 81 14 f2 fc 7f
    0x7ffcf2145ee6: 00 00 f8 86 14 f2 fc 7f 00 00 13 87 14 f2 fc 7f
    0x7ffcf2145ef6: 00 00 35 87 14 f2 fc 7f 00 00 4a 87 14 f2 fc 7f
    0x7ffcf2145f06: 00 00 62 87 14 f2 fc 7f 00 00 79 87 14 f2 fc 7f
    0x7ffcf2145f16: 00 00 8a 87 14 f2 fc 7f 00 00 95 87 14 f2 fc 7f
    0x7ffcf2145f26: 00 00 b5 87 14 f2 fc 7f 00 00 d4 87 14 f2 fc 7f
    0x7ffcf2145f36: 00 00 e8 87 14 f2 fc 7f 00 00 2e 88 14 f2 fc 7f
    0x7ffcf2145f46: 00 00 41 88 14 f2 fc 7f 00 00 66 88 14 f2 fc 7f
    0x7ffcf2145f56: 00 00 8a 88 14 f2 fc 7f 00 00 95 88 14 f2 fc 7f
    0x7ffcf2145f66: 00 00 be 88 14 f2 fc 7f 00 00 f4 88 14 f2 fc 7f
    0x7ffcf2145f76: 00 00 08 89 14 f2 fc 7f 00 00 19 89 14 f2 fc 7f
    0x7ffcf2145f86: 00 00 42 89 14 f2 fc 7f 00 00 51 89 14 f2 fc 7f
    0x7ffcf2145f96: 00 00 68 89 14 f2 fc 7f 00 00 7a 89 14 f2 fc 7f
    0x7ffcf2145fa6: 00 00 9b 89 14 f2 fc 7f 00 00 f1 89 14 f2 fc 7f
    0x7ffcf2145fb6: 00 00 24 8a 14 f2 fc 7f 00 00 46 8a 14 f2 fc 7f
    0x7ffcf2145fc6: 00 00 5b 8a 14 f2 fc 7f 00 00 70 8a 14 f2 fc 7f
    0x7ffcf2145fd6: 00 00 85 8a 14 f2 fc 7f 00 00 ac 8a 14 f2 fc 7f
    0x7ffcf2145fe6: 00 00 bf 8a 14 f2 fc 7f 00 00 d2 8a 14 f2 fc 7f
    0x7ffcf2145ff6: 00 00 e7 8a 14 f2 fc 7f 00 00
    Maybe, if I try to read one more byte there'll be a segfault (if that page is not mapped).
    Declare s[] as global and test it again... different addresses, but no segfault!

    Quote Originally Posted by awsdert View Post
    , it means it would have reached the end of that 4Kib, it's just usually a null byte would normally be encountered before that happens, however I did forget about the garbage output and the memory corruption
    How an array 2 bytes long "means it would have reached the end of that 4 KiB"?
    Last edited by flp1969; 04-05-2019 at 02:13 PM.

  6. #21
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,715
    Quote Originally Posted by flp1969 View Post
    How an array 2 bytes long "means it would have reached the end of that 4 KiB"?
    Well when it doesn't segfault on memory beyond the actual string length then it will continue until it hits either a null byte or it tries to go beyond addressable memory (accept where it clamps which is instead an inifinite loop) which is where it would then segfault. Just because 99.9% of the time it encounters that null byte does not mean it will always encounter that null byte which means when it does eventually reach the last 2 characters (0xEFFFFFFF) then it will finally crash, possibly cause a BSOD too.

  7. #22
    Registered User
    Join Date
    Feb 2019
    Posts
    1,048
    Quote Originally Posted by awsdert View Post
    Well when it doesn't segfault on memory beyond the actual string length then it will continue until it hits either a null byte or it tries to go beyond addressable memory (accept where it clamps which is instead an inifinite loop) which is where it would then segfault. Just because 99.9% of the time it encounters that null byte does not mean it will always encounter that null byte which means when it does eventually reach the last 2 characters (0xEFFFFFFF) then it will finally crash, possibly cause a BSOD too.
    This is not how it works... It will segfault when trying to make an access to memory not mapped on the page tables. Maybe you wanted to say "if the 2 bytes array is at the end of a page AND the next page is not mapped, it will segfault".

    The same goes to modes with no paging enabled (i386). If you try to access memory outside of the limit of de descriptor references by the selector, segfault.

    Of course, there will be segfault also if the privileges rules are broken (cpl=3 or rpl=3 cannot reference memory described with dpl=0, for instance).

    The only garanteed address that WILL segfault is 0 (NULL pointer). The other ones, depends on the memory mapping.
    Last edited by flp1969; 04-05-2019 at 02:35 PM.

  8. #23
    Registered User
    Join Date
    May 2012
    Location
    Arizona, USA
    Posts
    904
    You guys are going down a rabbit-hole tangent of a problem that doesn't exist. With an expression like if(*(str) == *(str + 1) && (*(str) == *(str + 2))), no memory is accessed that shouldn't be. It works perfectly in all cases in the context of the program in post #11, even when the memory beyond the string is filled with dragons.

  9. #24
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,715
    Quote Originally Posted by flp1969 View Post
    This is not how it works... It will segfault when trying to make an access to memory not mapped on the page tables. Maybe you wanted to say "if the 2 bytes array is at the end of a page AND the next page is not mapped, it will segfault".

    The same goes to modes with no paging enabled (i386). If you try to access memory outside of the limit of de descriptor references by the selector, segfault.

    Of course, there will be segfault also if the privileges rules are broken (cpl=3 or rpl=3 cannot reference memory described with dpl=0, for instance).

    The only garanteed address that WILL segfault is 0 (NULL pointer). The other ones, depends on the memory mapping.
    Ah ok, still seems better to assume it will segfault though, at least you can't hit an unexpected scenario that way

  10. #25
    Registered User
    Join Date
    Feb 2019
    Posts
    1,048
    Quote Originally Posted by christop View Post
    You guys are going down a rabbit-hole tangent of a problem that doesn't exist. With an expression like if(*(str) == *(str + 1) && (*(str) == *(str + 2))), no memory is accessed that shouldn't be. It works perfectly in all cases in the context of the program in post #11, even when the memory beyond the string is filled with dragons.
    Nope... consider we have an string big enough:
    Code:
    char s[] = "abcdeeeff";
    And, at some point str is pointing to the last char (the last 'f'). So (str+1) will point to the NUL char, but (str+2) will point to garbage...

    Ok... I've got sideways explaining why segfault MAY not happen, but this is a forum, isn't it? We are supposed to discuss things, isn't it?

  11. #26
    Registered User
    Join Date
    May 2012
    Location
    Arizona, USA
    Posts
    904
    Quote Originally Posted by flp1969 View Post
    Nope... consider we have an string big enough:
    Code:
    char s[] = "abcdeeeff";
    And, at some point str is pointing to the last char (the last 'f'). So (str+1) will point to the NUL char, but (str+2) will point to garbage...
    Yes, when str points to the last 'f', (str+2) will point to "garbage", but it's never accessed in the code in question. So it doesn't matter what's at (str+2). It's never accessed. Why do you think it would be accessed?

  12. #27
    Registered User
    Join Date
    Feb 2019
    Posts
    1,048
    Quote Originally Posted by awsdert View Post
    Ah ok, still seems better to assume it will segfault though, at least you can't hit an unexpected scenario that way
    It is a good rule of thumb, but it is useful to know also when segfault will not occur...
    As I said, *(str+2) probably will not segfault (it doesn't mean it won't!).

  13. #28
    Registered User
    Join Date
    May 2012
    Location
    Arizona, USA
    Posts
    904
    You have to remember that the && operator is "short-circuiting", which means that it will not evaluate the right-hand operand if the result of the whole expression is known based on the left-hand operand. That is, if the left-hand operand is false, then there's no point in evaluating the right-hand operand (the same happens with the || operator too, except the right-hand operand is evaluated only when the left-hand operand is false).

    In the "replace" function in post #11, *(str) == *(str + 1) is false when (str+1) points at the NUL character, so the right-hand expression (*(str) == *(str + 2)) will not be evaluated.

    Edit to add: this is why it's safe to do something like if (p && *p == '\0')... *p is evaluated only if p is not a null pointer.
    Last edited by christop; 04-05-2019 at 02:59 PM.

  14. #29
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,715
    Quote Originally Posted by christop View Post
    You guys are going down a rabbit-hole tangent of a problem that doesn't exist. With an expression like if(*(str) == *(str + 1) && (*(str) == *(str + 2))), no memory is accessed that shouldn't be. It works perfectly in all cases in the context of the program in post #11, even when the memory beyond the string is filled with dragons.
    Since its an assignment there is the possibility his teacher will throw a different string at it to see how well he programed it, these considerations could be the difference between a C and a A+

  15. #30
    Registered User
    Join Date
    Feb 2019
    Posts
    1,048
    @awsdert, Another example... when you free() a block of memory previously allocated with malloc() it is an error to access that particular address. But it doesn't mean you'll get an segfault. Because it is impossible to allocate less than 4 KiB of memory with paging enabled. If the block isn't occupying the entire page, there is room for malloc() to "allocate" another block in this same page for other blocks. So, this code probably will not segfault:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    int main ( void )
    {
      char *p;
    
      puts( "Allocating 100 bytes on heap." );
      if ( ! ( p = malloc ( 100 ) ) )
      {
        fputs( "ERROR allocating 100 bytes. Aborted.\n", stderr );
        return EXIT_FAILURE;
      }
    
      printf( "100 bytes block allocated at %p.\n", p );
    
      free( p );
    
      printf( "Previously allocated block freed.\n"
              "Access to memory at %p, probably will %ssegfault!\n", 
        p, (size_t)p & 0xfff ? "NOT " : "" );
    
      // this should be illegal!
      *p = '\0';
    
      printf( "See? I wrote a 0 byte at %p. Nothing happens!\n", p );
    
      return EXIT_SUCCESS;
    }
    Compiling and running:

    Code:
    $ cc -o test test.c
    $ ./test
    Allocating 100 bytes on heap.
    100 bytes block allocated at 0x560873087670.
    Previously allocated block freed.
    Access to memory at 0x560873087670, probably will NOT segfault!
    See? I wrote a 0 byte at 0x560873087670. Nothing happens!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. The C Progamming Language Excercise 5-4
    By mekadir in forum C Programming
    Replies: 7
    Last Post: 09-03-2015, 07:05 AM
  2. Help for my assignment!
    By 110abbidi in forum C Programming
    Replies: 5
    Last Post: 08-09-2012, 11:25 PM
  3. Replies: 4
    Last Post: 01-08-2012, 05:31 AM
  4. Replies: 3
    Last Post: 04-26-2009, 08:54 AM
  5. new to c progamming any one can help
    By manalidris in forum C Programming
    Replies: 1
    Last Post: 05-13-2002, 05:05 AM

Tags for this Thread