why this program is not crashing

Discussion in 'C Programming' started by ghyott@yahoo.com, Feb 11, 2005.

  1. Guest

    hello,
    In my opinion the following code should crash when run with
    *(argv+1)="1234567890" and *(argv+2)="1234567890" .

    int main(int argc,char **argv)
    {
    char buf1[5];
    char buf2[5];
    char buf3[5];
    strncpy(buf2,*(argv+1),sizeof(buf2));
    strncpy(buf3,*(argv+2),sizeof(buf3));
    sprintf(buf1,"%s",buf2);
    return 0;
    }

    The last element of buf2 is not NULL.Therefore sprintf should copy
    "1234512345"
    to buf1 and which should result in segmentation fault.However,this is
    not the case and the program is running normally.Can anybody please
    pin-point my error.

    Thanks
    , Feb 11, 2005
    #1
    1. Advertising

  2. Ben Pfaff Guest

    writes:

    > In my opinion the following code should crash when run with
    > *(argv+1)="1234567890" and *(argv+2)="1234567890" .


    You seem to be one of a class of newbies I spot here
    occasionally, who think that *(a+b) is somehow different from
    a. That's not true, and the former just makes it look like
    you don't know what you're doing.

    > int main(int argc,char **argv)
    > {
    > char buf1[5];
    > char buf2[5];
    > char buf3[5];
    > strncpy(buf2,*(argv+1),sizeof(buf2));
    > strncpy(buf3,*(argv+2),sizeof(buf3));
    > sprintf(buf1,"%s",buf2);
    > return 0;
    > }
    >
    > The last element of buf2 is not NULL.


    Of course not--it's not a pointer. The proper terminology is
    "null terminator", not NULL. The latter always refers to a
    pointer.

    > Therefore sprintf should copy "1234512345" to buf1 and which
    > should result in segmentation fault.However,this is not the
    > case and the program is running normally.Can anybody please
    > pin-point my error.


    There are two errors here. The first is your assumption that
    buf2[] and buf3[] are stored contiguously, so that reading or
    writing past the end of buf2[] will give you the beginning of
    buf3[]. This is not guaranteed and many implementations will not
    yield this behavior.

    The second error is your assumption that accessing beyond the end
    of buf3[] should produce a segmentation fault. The language does
    not guarantee that. In fact, it does not make any guarantees at
    all: the behavior is formally "undefined", meaning that anything
    at all is allowed to happen.
    --
    "I should killfile you where you stand, worthless human." --Kaz
    Ben Pfaff, Feb 11, 2005
    #2
    1. Advertising

  3. Richard Bos Guest

    wrote:

    > In my opinion the following code should crash when run with
    > *(argv+1)="1234567890" and *(argv+2)="1234567890" .


    It could, but there's no guarantee.

    > int main(int argc,char **argv)
    > {
    > char buf1[5];
    > char buf2[5];
    > char buf3[5];
    > strncpy(buf2,*(argv+1),sizeof(buf2));
    > strncpy(buf3,*(argv+2),sizeof(buf3));
    > sprintf(buf1,"%s",buf2);
    > return 0;
    > }
    >
    > The last element of buf2 is not NULL.Therefore sprintf should copy
    > "1234512345"


    The last element of buf2 is never NULL, because NULL is a null pointer
    constant and buf2 is an array of char. You mean that it's not null
    (i.e., not a zero character), or not NUL (the ASCII character 0).

    And no, it isn't; and therefore your program invokes undefined
    behaviour, and may do whatever it pleases. This _could_ mean crashing;
    it could also mean ignore whatever does not fit in the buffer; it could
    also mean blot over whatever memory happens to lie beyond buf1 and
    continue. The last option is particularly nasty if what happens to lie
    beyond buf1 is a return address, or a totally unrelated variable which
    you then use. In theory, invoking undefined behaviour could even result
    in confusing the computer so badly that it writes your resignation
    letter and emails it to your CEO.

    BTW, even if you do assume (not necessarily correctly, but it's one of
    the possibilities) that this particular kind of undefined behaviour
    results in merrily trying to continue copying from beyond the end of the
    source array, _and_ that your three arrays lie next to one another in
    memory, I still don't see why that would try to copy "1234512345". You
    have the same error with buf3 that you have with buf2; it would be more
    likely that it would (try to) copy "1234512345Some random fluff that
    happens to be on the stack beyond buf3, possibly including your return
    address.".
    Even then, the crash is hardly guaranteed, though. Undefined behaviour
    is exactly that: undefined.

    Richard
    Richard Bos, Feb 11, 2005
    #3
  4. Guest

    wrote:
    > hello,
    > In my opinion the following code should crash when run with
    > *(argv+1)="1234567890" and *(argv+2)="1234567890" .


    It crashed when i ran this with microsoft visual c 7
    >
    > int main(int argc,char **argv)
    > {
    > char buf1[5];
    > char buf2[5];
    > char buf3[5];
    > strncpy(buf2,*(argv+1),sizeof(buf2));
    > strncpy(buf3,*(argv+2),sizeof(buf3));
    > sprintf(buf1,"%s",buf2);
    > return 0;
    > }
    >
    > The last element of buf2 is not NULL.Therefore sprintf should copy
    > "1234512345"
    > to buf1 and which should result in segmentation fault.However,this is
    > not the case and the program is running normally.Can anybody please
    > pin-point my error.
    >
    > Thanks

    buf1,buf2 and buf3 are stored in stack,so incrementing pointer to buf2
    goes towards buf1 not buf3.if they were global then it will be as you
    say.

    buf1,buf2 buf3 have padding to make them start in addresses divisible
    by 4.so most possibly 3 bytes padding.one of them may be zero by chance
    that may be why it didn't crash in your system.
    , Feb 11, 2005
    #4
  5. Guest

    wrote:
    >
    > buf1,buf2 buf3 have padding to make them start in addresses divisible
    > by 4.

    read the 4 as word size of processer. sorry about that.
    , Feb 11, 2005
    #5
  6. Richard Bos Guest

    wrote:

    > wrote:
    > > int main(int argc,char **argv)
    > > {
    > > char buf1[5];
    > > char buf2[5];
    > > char buf3[5];
    > > strncpy(buf2,*(argv+1),sizeof(buf2));
    > > strncpy(buf3,*(argv+2),sizeof(buf3));
    > > sprintf(buf1,"%s",buf2);
    > > return 0;
    > > }

    > buf1,buf2 and buf3 are stored in stack,


    Possibly, but even if so...

    > so incrementing pointer to buf2 goes towards buf1 not buf3.


    ....there's no reason to assume that this is true in the general case. It
    may be true for you, but that doesn't automatically make it true for the
    OP or anyone else. Not all the world is a Microsoft boxlet.

    > buf1,buf2 buf3 have padding to make them start in addresses divisible
    > by 4.


    There is no reason whatsoever to assume this.

    Richard
    Richard Bos, Feb 11, 2005
    #6
  7. Guest

    Richard Bos wrote:
    > wrote:
    >
    > > buf1,buf2 and buf3 are stored in stack,

    >
    > Possibly, but even if so...
    >
    > > so incrementing pointer to buf2 goes towards buf1 not buf3.

    >
    > ...there's no reason to assume that this is true in the general case.

    It
    > may be true for you, but that doesn't automatically make it true for

    the
    > OP or anyone else. Not all the world is a Microsoft boxlet.
    >

    If they are stored in stack,then the direction will be this.right? I am
    not talking about the distance.

    I made that comments after seeing gcc output.

    ~ > cat test.c
    #include <stdio.h>

    int main(void)
    {
    char buf1[5];
    char buf2[5];
    char buf3[5];
    printf("%p %p %p\n",buf1,buf2,buf3);
    return 0;
    }
    ~ > gcc test.c
    ~ > ./a.out
    ffbef958 ffbef950 ffbef948
    ~ > gcc -v
    Reading specs from
    /usr/local/lib/gcc-lib/sparc-sun-solaris2.8/2.95.3/specs
    gcc version 2.95.3 20010315 (release)
    ~ >
    , Feb 11, 2005
    #7
  8. Richard Bos Guest

    wrote:

    > Richard Bos wrote:
    > > wrote:
    > >
    > > > so incrementing pointer to buf2 goes towards buf1 not buf3.

    > >
    > > ...there's no reason to assume that this is true in the general case. It
    > > may be true for you, but that doesn't automatically make it true for the
    > > OP or anyone else. Not all the world is a Microsoft boxlet.
    > >

    > If they are stored in stack,then the direction will be this.right?


    Wrong. You _do_ _not_ _know_ _this_. _Not_ all the world runs on your
    kind of computer!

    > I made that comments after seeing gcc output.


    Never assume that _anything_ is required (or possibly even allowed) just
    because Ganuck does it that way.

    Richard
    Richard Bos, Feb 11, 2005
    #8
  9. -berlin.de Guest

    wrote:

    > Richard Bos wrote:
    >> wrote:
    >>
    >> > buf1,buf2 and buf3 are stored in stack,

    >>
    >> Possibly, but even if so...
    >>
    >> > so incrementing pointer to buf2 goes towards buf1 not buf3.

    >>
    >> ...there's no reason to assume that this is true in the general case.

    > It
    >> may be true for you, but that doesn't automatically make it true for

    > the
    >> OP or anyone else. Not all the world is a Microsoft boxlet.
    >>

    > If they are stored in stack,then the direction will be this.right? I am
    > not talking about the distance.


    No. Already your first assumption that things are stored on a stack
    is not necessary true - variables could also be in registers only or
    there might be even machines not having a simple, linear stack. More-
    over, things might not only depend on the direction the stack on your
    machine grows (there are two alternatives, and both are used on diff-
    erent architctures), but the compiler is in no way obliged to store
    variables in a sequence resembling the the sequence the variables are
    defined in the C code. It may, for example, recognize that, due to
    alignment reasons, it would have to leave holes between the variables
    and thus reorder them to avoid that as far as possible. So making any
    assuptions about the relative positions of variables is plain wrong.
    It may work in a certain way on your machine when you compile with a
    certain set of options, but already changing the compiler options could
    change things dramatically.
    Regards, Jens
    --
    \ Jens Thoms Toerring ___ -berlin.de
    \__________________________ http://www.toerring.de
    -berlin.de, Feb 11, 2005
    #9
  10. infobahn Guest

    wrote:
    >
    > #include <stdio.h>
    >
    > int main(void)
    > {
    > char buf1[5];
    > char buf2[5];
    > char buf3[5];
    > printf("%p %p %p\n",buf1,buf2,buf3);


    printf, when faced with %p, expects to find a void * waiting for
    it in its variable argument list. Since char * and void * have
    the same size and representation, you *might* get away with it,
    but in general it's wiser to cast non-void pointers when matching
    them to %p, as follows:

    printf("%p %p %p\n", (void *)buf1, (void *)buf2, (void *)buf3);
    infobahn, Feb 11, 2005
    #10
  11. Michael Mair Guest

    infobahn wrote:
    > wrote:
    >
    >>#include <stdio.h>
    >>
    >>int main(void)
    >>{
    >> char buf1[5];
    >> char buf2[5];
    >> char buf3[5];
    >> printf("%p %p %p\n",buf1,buf2,buf3);

    >
    >
    > printf, when faced with %p, expects to find a void * waiting for
    > it in its variable argument list. Since char * and void * have
    > the same size and representation, you *might* get away with it,
    > but in general it's wiser to cast non-void pointers when matching
    > them to %p, as follows:
    >
    > printf("%p %p %p\n", (void *)buf1, (void *)buf2, (void *)buf3);


    I have no standard on my fingertips right now but IIRC for
    vararg functions, pointers/addresses always will be passed as void *
    and if anything you would have to cast (char *)buf if you explicitly
    need a char *. I may be wrong, though.


    Cheers
    Michael
    --
    E-Mail: Mine is a gmx dot de address.
    Michael Mair, Feb 11, 2005
    #11
  12. kingzog Guest

    infobahn wrote:
    > wrote:
    > >
    > > #include <stdio.h>
    > >
    > > int main(void)
    > > {
    > > char buf1[5];
    > > char buf2[5];
    > > char buf3[5];
    > > printf("%p %p %p\n",buf1,buf2,buf3);

    >
    > printf, when faced with %p, expects to find a void * waiting for
    > it in its variable argument list. Since char * and void * have
    > the same size and representation, you *might* get away with it,
    > but in general it's wiser to cast non-void pointers when matching
    > them to %p, as follows:
    >
    > printf("%p %p %p\n", (void *)buf1, (void *)buf2, (void *)buf3);


    Is there a machine that needs this? Surely if they have the same size
    and representation it whould work without the cast. I've certainly
    never needed to cast char * to void * in a printf like this, and I've
    used some really wierd C compilers, e.g. on DSPs.

    I'd bet that the addresses passed to printf will be on the stack too.
    Even on a 64 bit machine, where buf1[5] might fit in a register, the C
    compiler would need to stack it before the call to printf.

    Zog.
    kingzog, Feb 11, 2005
    #12
  13. infobahn Guest

    kingzog wrote:
    >
    > infobahn wrote:


    <snip>

    > > but in general it's wiser to cast non-void pointers when matching
    > > them to %p, as follows:
    > >
    > > printf("%p %p %p\n", (void *)buf1, (void *)buf2, (void *)buf3);

    >
    > Is there a machine that needs this? Surely if they have the same size
    > and representation it whould work without the cast.


    comp.lang.c have argued about this in the past without reaching any
    firm conclusion that I can remember. If there was any consensus at
    all, it was "better safe than sorry".
    infobahn, Feb 11, 2005
    #13
  14. Michael Mair <> writes:
    > infobahn wrote:
    >> wrote:
    >>
    >>>#include <stdio.h>
    >>>
    >>>int main(void)
    >>>{
    >>> char buf1[5];
    >>> char buf2[5];
    >>> char buf3[5];
    >>> printf("%p %p %p\n",buf1,buf2,buf3);

    >> printf, when faced with %p, expects to find a void * waiting for
    >> it in its variable argument list. Since char * and void * have
    >> the same size and representation, you *might* get away with it,
    >> but in general it's wiser to cast non-void pointers when matching
    >> them to %p, as follows:
    >> printf("%p %p %p\n", (void *)buf1, (void *)buf2, (void *)buf3);

    >
    > I have no standard on my fingertips right now but IIRC for
    > vararg functions, pointers/addresses always will be passed as void *
    > and if anything you would have to cast (char *)buf if you explicitly
    > need a char *. I may be wrong, though.


    No, pointers are passed as whatever type they happen to be. The only
    conversions are "default argument promotions"; small integer types are
    converted to int or unsigned int, and float is converted to double.
    If, for example, int* and void* have different representations, you
    must convert an int* argument to void* if it's matched by a "%p"
    specifier.

    There's some special-case wording about void* and character pointer
    types. It's intended that they're interchangeable as function
    arguments, but that intent is only stated in a footnote (if I recall
    correctly). It's best, IMHO, to use an explicit cast even in that
    case (one of the few cases where a cast is a good idea).

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
    Keith Thompson, Feb 11, 2005
    #14
  15. Michael Mair Guest

    Keith Thompson wrote:
    > Michael Mair <> writes:
    >
    >>infobahn wrote:
    >>
    >>> wrote:
    >>>
    >>>
    >>>>#include <stdio.h>
    >>>>
    >>>>int main(void)
    >>>>{
    >>>> char buf1[5];
    >>>> char buf2[5];
    >>>> char buf3[5];
    >>>> printf("%p %p %p\n",buf1,buf2,buf3);
    >>>
    >>>printf, when faced with %p, expects to find a void * waiting for
    >>>it in its variable argument list. Since char * and void * have
    >>>the same size and representation, you *might* get away with it,
    >>>but in general it's wiser to cast non-void pointers when matching
    >>>them to %p, as follows:
    >>> printf("%p %p %p\n", (void *)buf1, (void *)buf2, (void *)buf3);

    >>
    >>I have no standard on my fingertips right now but IIRC for
    >>vararg functions, pointers/addresses always will be passed as void *
    >>and if anything you would have to cast (char *)buf if you explicitly
    >>need a char *. I may be wrong, though.

    >
    >
    > No, pointers are passed as whatever type they happen to be. The only
    > conversions are "default argument promotions"; small integer types are
    > converted to int or unsigned int, and float is converted to double.
    > If, for example, int* and void* have different representations, you
    > must convert an int* argument to void* if it's matched by a "%p"
    > specifier.


    Okay, so I remembered it wrong. Thanks for clarifying!


    > There's some special-case wording about void* and character pointer
    > types. It's intended that they're interchangeable as function
    > arguments, but that intent is only stated in a footnote (if I recall
    > correctly). It's best, IMHO, to use an explicit cast even in that
    > case (one of the few cases where a cast is a good idea).


    I know that -- at least something :)


    Cheers
    Michael
    --
    E-Mail: Mine is a gmx dot de address.
    Michael Mair, Feb 11, 2005
    #15
  16. On Fri, 11 Feb 2005 03:59:35 -0800, manoj1978 wrote:

    >
    > Richard Bos wrote:
    >> wrote:
    >>
    >> > buf1,buf2 and buf3 are stored in stack,

    >>
    >> Possibly, but even if so...
    >>
    >> > so incrementing pointer to buf2 goes towards buf1 not buf3.

    >>
    >> ...there's no reason to assume that this is true in the general case.

    > It
    >> may be true for you, but that doesn't automatically make it true for

    > the
    >> OP or anyone else. Not all the world is a Microsoft boxlet.
    >>

    > If they are stored in stack,then the direction will be this.right? I am
    > not talking about the distance.


    How separate objects are laid out in memory is not specified by C.
    Compilers can and do do things differently.

    > I made that comments after seeing gcc output.


    gcc had to do it some way, it might have decided to put buf2 first
    followed by buf1 then buf3. There is no guarantee that a different version
    of gcc would do it the same way, or even the same version of gcc with
    different options. Optimisation levels can easily change this sort of
    thing. However there's no reason for the correct behaviour of a program to
    depend on this so it isn't a problem.

    Lawrence
    Lawrence Kirby, Feb 11, 2005
    #16
  17. Jack Klein Guest

    On 11 Feb 2005 05:31:01 -0800, "kingzog" <> wrote
    in comp.lang.c:

    > infobahn wrote:
    > > wrote:
    > > >
    > > > #include <stdio.h>
    > > >
    > > > int main(void)
    > > > {
    > > > char buf1[5];
    > > > char buf2[5];
    > > > char buf3[5];
    > > > printf("%p %p %p\n",buf1,buf2,buf3);

    > >
    > > printf, when faced with %p, expects to find a void * waiting for
    > > it in its variable argument list. Since char * and void * have
    > > the same size and representation, you *might* get away with it,
    > > but in general it's wiser to cast non-void pointers when matching
    > > them to %p, as follows:
    > >
    > > printf("%p %p %p\n", (void *)buf1, (void *)buf2, (void *)buf3);

    >
    > Is there a machine that needs this? Surely if they have the same size
    > and representation it whould work without the cast. I've certainly
    > never needed to cast char * to void * in a printf like this, and I've
    > used some really wierd C compilers, e.g. on DSPs.


    That fact that it works on the compilers where you have tested it, or
    99% of all compilers, or even 101% of all compilers does not prove
    anything.

    Here is the exact wording of the C standard. First the normative text
    in 6.2.5 paragraph 6:

    ========
    A pointer to void shall have the same representation and alignment
    requirements as a pointer to a character type.39)
    ========

    And footnote 39:

    ========
    The same representation and alignment requirements are meant to imply
    interchangeability as arguments to functions, return values from
    functions, and members of unions.
    ========

    But footnotes are not normative, and note the phrase "are meant to
    imply."

    The standard specifically does not specify this and make it mandatory.

    So this is a QOI issue, not a standard one.


    > I'd bet that the addresses passed to printf will be on the stack too.
    > Even on a 64 bit machine, where buf1[5] might fit in a register, the C
    > compiler would need to stack it before the call to printf.


    What "stack"? On some platforms, the four arguments in that printf()
    call would all be passed in registers. And the return address in a
    dedicated register of its own. No "stack" need apply.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++
    http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
    Jack Klein, Feb 12, 2005
    #17
  18. kingzog Guest

    Jack Klein wrote:
    > On 11 Feb 2005 05:31:01 -0800, "kingzog" <> wrote
    >
    > > Is there a machine that needs this? Surely if they have the same

    size
    > > and representation it whould work without the cast. I've certainly
    > > never needed to cast char * to void * in a printf like this, and

    I've
    > > used some really wierd C compilers, e.g. on DSPs.

    >
    > That fact that it works on the compilers where you have tested it, or
    > 99% of all compilers, or even 101% of all compilers does not prove
    > anything.
    >


    Yes but if all the compilers I need to support don't need it, my code
    doesn't need it either. In fact most embedded C code is only designed
    to support one compiler and one architecture and has far more serious
    portability issues than this - e.g. assumptions about endianess or
    stucture packing or gobs of inline assembler and hardware access.

    >
    > So this is a QOI issue, not a standard one.


    ??

    >
    >
    > > I'd bet that the addresses passed to printf will be on the stack

    too.
    > > Even on a 64 bit machine, where buf1[5] might fit in a register,

    the C
    > > compiler would need to stack it before the call to printf.

    >
    > What "stack"? On some platforms, the four arguments in that printf()
    > call would all be passed in registers. And the return address in a
    > dedicated register of its own. No "stack" need apply.


    Every platform I've seen uses the stack for printf, because it's the
    most efficient way to implement va_next - va_start can create a hidden
    pointer to the args on the stack, and va_next can do *hidden_ptr++ and
    some masking.

    If the args were in registers, you'd need either a need a wierd
    addressing mode like this

    mov Rdest, Registers[Rcount] ; mov the register number Rcount into
    Rdest

    I've never seen a architectures that provides this addressing mode. As
    a HW guy it looks hard to implement. You could do two loads from the
    register file, one to read Rcount and one to read Registers[Rcount], or
    you could have add _lots_ of read ports to the register file.

    On a normal chip, the C compiler could use self modifying code to
    synthesise it -

    mov Rtmp, Rcount
    shift Rtmp, #xx ; shift Rcount to line up with the register field
    ; in the instruction
    or Rtmp, [label]
    label:
    mov Rdest, R0 ; R0 is a constant field in the instruction
    ; which the previous instruction overwrites

    But self modifying code is slow because it flushes pipelines, and
    causes problems if you have a read only code page. It's also worth
    pointing out that both of these solutions will break if you try to pass
    more arguments to printf than you have usuable argument registers.
    E.g. consider a printf on a Risc chip which allows 4 registers to pass
    arguments. One call to printf with 5 arguments would require a second
    copy of the function with the stack based calling convention.

    So even on Risc machines where the normal calling convention is to pass
    args in registers, variadic functions still pass the args to printf on
    the stack. It's probably fast too, because the top of the stack is
    pretty much guaranteed to be in a cache or write buffer when the
    variadic function calls va_next. Then again, if you want speed, you'd
    make the function non variadic and declare it INLINE with inline
    #defined to be something appropriate for the compiler
    (http://www.greenend.org.uk/rjk/2003/03/inline.html)

    >
    > --
    > Jack Klein
    > Home: http://JK-Technology.Com
    > FAQs for
    > comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
    > comp.lang.c++ http://www.parashift.com/c -faq-lite/
    > alt.comp.lang.learn.c-c++
    > http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
    kingzog, Feb 14, 2005
    #18
  19. Flash Gordon Guest

    wrote:
    > wrote:
    >
    >>hello,
    >>In my opinion the following code should crash when run with
    >>*(argv+1)="1234567890" and *(argv+2)="1234567890" .

    >
    >
    > It crashed when i ran this with microsoft visual c 7
    >
    >> int main(int argc,char **argv)
    >> {
    >> char buf1[5];
    >> char buf2[5];
    >> char buf3[5];
    >> strncpy(buf2,*(argv+1),sizeof(buf2));
    >> strncpy(buf3,*(argv+2),sizeof(buf3));
    >> sprintf(buf1,"%s",buf2);
    >> return 0;
    >> }
    >>
    >>The last element of buf2 is not NULL.Therefore sprintf should copy
    >>"1234512345"
    >>to buf1 and which should result in segmentation fault.However,this is
    >>not the case and the program is running normally.Can anybody please
    >>pin-point my error.
    >>
    >>Thanks

    >
    > buf1,buf2 and buf3 are stored in stack,so incrementing pointer to buf2
    > goes towards buf1 not buf3.if they were global then it will be as you
    > say.


    Maybe on your implementation, but in general it is whatever the compiler
    feels like doing. The compiler could see that main is not called
    recursively and therefore implement buf1, buf2 and buf3 as if they were
    static, it could reorder them, possibly on the basis of when they are
    used, it could add in sentinel values between them to allow for the
    detection of buffer overflows, or anything else it likes.

    > buf1,buf2 buf3 have padding to make them start in addresses divisible
    > by 4.so most possibly 3 bytes padding.


    Again, that may apply to your system but it is not true in general.

    > one of them may be zero by chance
    > that may be why it didn't crash in your system.


    Speculating why someone else's system does not crash on buffer overflow
    (or any other undefined behaviour) on the basis of you implementation is
    generally pointless.
    --
    Flash Gordon
    Living in interesting times.
    Although my email address says spam, it is real and I read it.
    Flash Gordon, Feb 15, 2005
    #19
  20. wrote in message news:<>...
    > hello,
    > In my opinion the following code should crash when run with
    > *(argv+1)="1234567890" and *(argv+2)="1234567890" .
    >
    > int main(int argc,char **argv)
    > {
    > char buf1[5];
    > char buf2[5];
    > char buf3[5];
    > strncpy(buf2,*(argv+1),sizeof(buf2));
    > strncpy(buf3,*(argv+2),sizeof(buf3));
    > sprintf(buf1,"%s",buf2);
    > return 0;
    > }
    >
    > The last element of buf2 is not NULL.Therefore sprintf should copy
    > "1234512345"
    > to buf1 and which should result in segmentation fault.However,this is
    > not the case and the program is running normally.Can anybody please
    > pin-point my error.
    >
    > Thanks


    Hi, I think you misunderstand about memory layout. From your code it should be

    buf1[4]
    buf1[3]
    buf1[2]
    buf1[1]
    buf1[0]
    buf2[4]
    buf2[3]
    ..
    ..
    ..
    buf3[0]

    when you 'sprintf(buf1,"%s", buf2); the NULL character comes from buf1[0].

    Regards,
    Prawit Chaivong, Feb 16, 2005
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Mr. SweatyFinger
    Replies:
    2
    Views:
    1,739
    Smokey Grindel
    Dec 2, 2006
  2. James

    why this program is crashing

    James, Apr 17, 2005, in forum: C Programming
    Replies:
    6
    Views:
    294
    Barry Schwarz
    Apr 18, 2005
  3. code break

    Why this program is crashing ???

    code break, Mar 3, 2006, in forum: C Programming
    Replies:
    8
    Views:
    333
    Keith Thompson
    Mar 3, 2006
  4. Pallav singh

    why this program is Crashing

    Pallav singh, Jul 14, 2009, in forum: C++
    Replies:
    5
    Views:
    351
    James Kanze
    Jul 16, 2009
  5. Pallav singh
    Replies:
    17
    Views:
    597
    Jerry Coffin
    Aug 7, 2009
Loading...

Share This Page