Re: Append with sprintf

Discussion in 'C Programming' started by Tom St Denis, Jun 4, 2010.

  1. Tom St Denis

    Tom St Denis Guest

    On Jun 4, 5:31 am, "Guillaume Dargaud"
    <> wrote:
    > Hello all,
    > this is something I commonly do, but I have a nagging doubt that it may not
    > be correct and/or dangerous in some situations:
    >
    > // Append
    > sprintf(Str, "%s (Id=%d, Pnl=%d)", Str, Id, Pnl);
    >
    > I know from experience (and _some_ sense of logic) that the following is a
    > no-no:
    > // Prepend
    > sprintf(Str, "(Id=%d, Pnl=%d) %s", Id, Pnl, Str);
    >
    > Comments ?


    Why hasn't anyone suggested that at the very least you should be using
    snprintf not sprintf....

    Tom
    Tom St Denis, Jun 4, 2010
    #1
    1. Advertising

  2. Tom St Denis

    Tom St Denis Guest

    On Jun 4, 7:56 am, Richard Heathfield <> wrote:
    > Tom St Denis wrote:
    >
    > <snip>
    >
    > > Why hasn't anyone suggested that at the very least you should be using
    > > snprintf not sprintf....

    >
    > Perhaps he doesn't /have/ snprintf.
    >
    > sprintf is perfectly safe if used correctly.


    So is gets... :)

    If by used you mean by the user...

    snprintf is fairly ubiquitous even MSVC has it (though under a diff
    name).

    Tom
    Tom St Denis, Jun 4, 2010
    #2
    1. Advertising

  3. Tom St Denis

    Ike Naar Guest

    In article <>,
    Richard Heathfield <> wrote:
    >Perhaps he doesn't /have/ snprintf.


    That's possible, though all C99 compilers and many C89 compilers have snprintf.

    >sprintf is perfectly safe if used correctly.


    True, but sometimes it's much harder to use sprintf correctly than to
    use snprintf correctly. Here's a simple example:
    for double d and char buf[64],

    sprintf(buf, "%p %f", (void*) &d, d);

    Is it safe? It might be, depending on how pointers are formatted, and
    depending on the value of d; or else it might cause a buffer overflow.

    With snprintf it's not difficult to check:

    if (snprintf(buf, sizeof buf, "%p %f", (void*) &d, d) < sizeof buf)
    {
    /* correct, go on */
    }

    Without snprintf, the check would be much, much more elaborate,
    for instance, writing the output to a temporary file using fprintf
    and counting the number of bytes in the file.
    --

    SDF Public Access UNIX System - http://sdf.lonestar.org
    Ike Naar, Jun 4, 2010
    #3
  4. Tom St Denis

    Tom St Denis Guest

    On Jun 4, 9:39 am, Kenneth Brody <> wrote:
    > On 6/4/2010 6:46 AM, Tom St Denis wrote:
    >
    >
    >
    >
    >
    > > On Jun 4, 5:31 am, "Guillaume Dargaud"
    > > <>  wrote:
    > >> Hello all,
    > >> this is something I commonly do, but I have a nagging doubt that it may not
    > >> be correct and/or dangerous in some situations:

    >
    > >> // Append
    > >> sprintf(Str, "%s (Id=%d, Pnl=%d)", Str, Id, Pnl);

    >
    > >> I know from experience (and _some_ sense of logic) that the following is a
    > >> no-no:
    > >> // Prepend
    > >> sprintf(Str, "(Id=%d, Pnl=%d) %s", Id, Pnl, Str);

    >
    > >> Comments ?

    >
    > > Why hasn't anyone suggested that at the very least you should be using
    > > snprintf not sprintf....

    >
    > Is snprintf() safe in either of the above cases?  Why replace one form of UB
    > with another?


    "at the very least" ... :)

    I wasn't commenting on the UB [I'd never write either form] just
    saying at the very least sprintf should go the way of gets().

    Tom
    Tom St Denis, Jun 4, 2010
    #4
  5. Tom St Denis

    Tom St Denis Guest

    On Jun 4, 12:02 pm, Richard Heathfield <> wrote:
    > If it's under a different name, it isn't snprintf.


    Could just as easily do a

    #ifdef MSVC
    #define snprintf _snprintf
    #endif

    zomg that's unpossible.

    Sometimes, just sometimes, I have to side with the local riff-raff in
    calling you out on your stupid replies. Encouraging people to use
    sprintf() is just playing with fire.

    Tom
    Tom St Denis, Jun 4, 2010
    #5
  6. Tom St Denis

    Tom St Denis Guest

    On Jun 4, 3:11 pm, Richard Heathfield <> wrote:
    > Tom St Denis wrote:
    > > On Jun 4, 12:02 pm, Richard Heathfield <> wrote:
    > >> If it's under a different name, it isn't snprintf.

    >
    > > Could just as easily do a

    >
    > > #ifdef MSVC
    > > #define snprintf _snprintf
    > > #endif

    >
    > > zomg that's unpossible.

    >
    > Ugly, but possible - *provided* snprintf is available, under some name
    > or another, on all target platforms, with the same semantics on each.
    >
    > > Sometimes, just sometimes, I have to side with the local riff-raff in
    > > calling you out on your stupid replies.

    >
    > If your compiler has snprintf and portability is of no consequence, by
    > all means use snprintf. But that is not an assumption that I like to
    > make when giving general replies. If you think that's stupid, well,
    > that's your prerogative.
    >
    > > Encouraging people to use
    > > sprintf() is just playing with fire.

    >
    > Which is better - to be *able* to use sprintf safely (by learning and
    > practice), or to rely on the availability of snprintf? I suspect that we
    > would answer that question very differently. You are entitled to call my
    > answer stupid, of course, but you really, really wouldn't like to hear
    > what I think of your answer.


    I'd rather "deal with" the portability issues of using snprintf on the
    few targets left that don't support it then use sprintf throughout my
    code. glibc/ulibc are fairly common place, so really there are only
    few places of ACTIVE development without snprintf handy [I'm sure on
    your VAX in your basement using a copy of UNIX from 1974 there is no
    snprintf, but I'll be damned if I'm developing on that platform
    ANYTIME in my lifetime, nor are any of my customers...].

    For ref: windows does have an snprintf function it's works just like
    snprintf, it's just not CALLED snprintf. Hence my comment about the
    macro.

    Tom
    Tom St Denis, Jun 4, 2010
    #6
  7. Tom St Denis

    Seebs Guest

    On 2010-06-04, Richard Heathfield <> wrote:
    > Which is better - to be *able* to use sprintf safely (by learning and
    > practice), or to rely on the availability of snprintf? I suspect that we
    > would answer that question very differently. You are entitled to call my
    > answer stupid, of course, but you really, really wouldn't like to hear
    > what I think of your answer.


    Given that snprintf has been written portably under terms which allow
    its inclusion in commercial code, I would say that relying on the availability
    of snprintf (but being prepared to provide it if you're using an old compiler)
    is probably a better choice.

    Even with a great deal of experience, it's possible to screw up sprintf in
    a variety of ways that snprintf won't be screwed up, and it requires more
    fiddly work and provides more points of failure.

    And, frankly, there are no longer any systems I care about which lack
    snprintf. It's been effectively universal, for my purposes, since last
    century. If there are exceptions, I've had no reason to try to target them.
    The embedded vendor I work at provides it for all conceivable targets, the
    desktop operating systems I use all ship with a compiler and C library
    which have a working snprintf...

    There are C99 features I don't try to rely on in code I think needs to be
    portable. snprintf isn't one of them. It's easy enough to get an
    implementation if one is really needed, and it's sufficiently useful, to
    go ahead and use it.

    -s
    --
    Copyright 2010, all wrongs reversed. Peter Seebach /
    http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
    http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
    Seebs, Jun 4, 2010
    #7
  8. Tom St Denis

    Tom St Denis Guest

    On Jun 4, 5:05 pm, Richard Heathfield <> wrote:
    > Tom St Denis wrote:
    > > On Jun 4, 3:11 pm, Richard Heathfield <> wrote:
    > >> Tom St Denis wrote:

    >
    > <snip>
    >
    > >>> Encouraging people to use
    > >>> sprintf() is just playing with fire.
    > >> Which is better - to be *able* to use sprintf safely (by learning and
    > >> practice), or to rely on the availability of snprintf? I suspect that we
    > >> would answer that question very differently. You are entitled to call my
    > >> answer stupid, of course, but you really, really wouldn't like to hear
    > >> what I think of your answer.

    >
    > > I'd rather "deal with" the portability issues of using snprintf on the
    > > few targets left that don't support it then use sprintf throughout my
    > > code.  glibc/ulibc are fairly common place, so really there are only
    > > few places of ACTIVE development without snprintf handy [I'm sure on
    > > your VAX in your basement using a copy of UNIX from 1974 there is no
    > > snprintf, but I'll be damned if I'm developing on that platform
    > > ANYTIME in my lifetime, nor are any of my customers...].

    >
    > Yes, that's the kind of answer I was expecting. The widespread
    > availability of gcc/glibc is of course a Good Thing, but it does tend to
    > lead people to the erroneous conclusion that "widespread" ==
    > "ubiquitous". I've worked on a number of sites that don't have snprintf,
    > or which have it with different semantics, leading to - um - interesting
    > debugging sessions. I'd rather play with fire, and make sure I've got
    > the right tools for dealing with fire - Nomex mat, extinguisher, phone,
    > etc - so that I can keep it under control. Fire works under any
    > implementation, but fnire is less available and less predictable.


    I'd hardly call snprintf some obscure function. The fact that it's
    not universal is just a flaw of the platforms that choose not to
    support it. The thing is you should make your assumptions simple and
    no simpler. I mean can you really assume all platforms support
    sprintf? Let alone any formatted printing anyways?

    I work in desktop/server/embedded spaces and a decent libc is a common
    thing nowadays. I don't tend to work with UNIXes too much [other than
    Linux] granted, but I have yet to really walk into any situation where
    snprintf isn't handy.

    > Yes. I've seen code littered with #if THIS_PLATFORM and #if
    > THAT_PLATFORM. You can keep it.


    It's not that hard to have a define in some common header somewhere.

    I do this already for heap functions so I can remap them to user
    supplied functions [almost always for non-hosted embedded targets].
    Doing the same thing for snprintf is not that hard.

    I can't believe we're actually chatting about this though. I'd rather
    promote safer functions like snprintf and for the few odd targets that
    don't support it work around it, then use a less safe function like
    sprintf(). Sure you can code up a million lines of wrapper code for
    every sprintf call to ensure you don't overwrite the buffer, or you
    can write your own snprintf ONCE and include it on platforms where
    snprintf is not provided...

    Given that platforms for which you would use snprintf and it's not
    provided would probably be running programs dealing only with integers
    and strings you could probably write an snprintf function from scratch
    in fewer lines of code than in all of our back-and-forth.

    Best, you could put your snprintf function in what we in the industry
    call a "library" and then refer to it in future projects when needed.
    You could do this instead of writing custom buffer checking code for
    every invocation of sprintf in every application you ever right.
    [hint: if you're picking up on attitude, take a hint].

    Tom
    Tom St Denis, Jun 4, 2010
    #8
  9. Tom St Denis

    Tom St Denis Guest

    On Jun 4, 6:33 pm, Richard Heathfield <> wrote:
    > Seebs wrote:
    >
    > <snip>
    >
    > > And, frankly, there are no longer any systems I care about which lack
    > > snprintf.

    >
    > Sure. Thing is, there are more systems on this good earth than the ones
    > *you* care about. :)


    Except that not using a function like snprintf is just poor form.
    It's smarter to just write your own snprintf for the platforms that
    lack it, than to work around with sprintf.

    Tom
    Tom St Denis, Jun 4, 2010
    #9
  10. Tom St Denis

    Tom St Denis Guest

    On Jun 4, 6:57 pm, Richard Heathfield <> wrote:
    > > Best, you could put your snprintf function in what we in the industry
    > > call a "library" and then refer to it in future projects when needed.

    >
    > Is that right? Hey, why didn't I think of that? [Checks stretchy string
    > library.] Oh look, I did.


    So your solution to the non-universal nature of snprintf is to write
    functions which are also non-universal?

    Anyways, let's leave it be.

    Tom
    Tom St Denis, Jun 5, 2010
    #10
  11. Tom St Denis

    Richard Bos Guest

    Tom St Denis <> wrote:

    > On Jun 4, 7:56=A0am, Richard Heathfield <> wrote:
    > > Tom St Denis wrote:
    > >
    > > > Why hasn't anyone suggested that at the very least you should be using
    > > > snprintf not sprintf....

    > >
    > > Perhaps he doesn't /have/ snprintf.
    > >
    > > sprintf is perfectly safe if used correctly.

    >
    > So is gets... :)


    No, it isn't, and you damned well know it.

    Richard
    Richard Bos, Jun 5, 2010
    #11
  12. Tom St Denis

    Seebs Guest

    On 2010-06-04, Richard Heathfield <> wrote:
    > Sure. Thing is, there are more systems on this good earth than the ones
    > *you* care about. :)


    True. But again, if I really, really, need to run on one of them, snprintf
    is easy to come by.

    -s
    --
    Copyright 2010, all wrongs reversed. Peter Seebach /
    http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
    http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
    Seebs, Jun 5, 2010
    #12
  13. Tom St Denis

    Seebs Guest

    On 2010-06-04, Richard Heathfield <> wrote:
    > Any C90-conforming hosted implementation supports sprintf - and there
    > does not exist *any* mainstream hosted platform without a C compiler
    > that provides sprintf.


    Although rumor has it Windows compilers used to omit it in some cases.

    > Any C99-conforming hosted implementation supports snprintf - and I think
    > Chris Hills (C99 committee) mentioned that there are FOUR such
    > implementations so far. Whoopy-doo.


    Irrelevant. We don't care how many systems fully comply with all the
    crazy floating point stuff; we care how many systems have a working snprintf.

    I haven't seen one in ages that doesn't.

    > Of course, not all clients are like that - but, in my experience, enough
    > *are* like that that I am not about to start committing to an optimistic
    > reliance on snprintf.


    So go for a pessimistic one, in which you provide your own as a fallback.

    > And do you advocate strncpy as a "safer strcpy", too? Same deal, really.


    No, not really. strncpy is visibly busted by design. I would say that
    strlcpy() may well be a safer strcpy.

    However, snprintf() is safer than sprintf() for another reason, which is
    that it is not always *possible* for you to determine the resulting
    length. (Hint: "%p".)

    -s
    --
    Copyright 2010, all wrongs reversed. Peter Seebach /
    http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
    http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
    Seebs, Jun 5, 2010
    #13
  14. Tom St Denis

    Seebs Guest

    On 2010-06-04, Richard Heathfield <> wrote:
    > Seebs wrote:
    >> Irrelevant. We don't care how many systems fully comply with all the
    >> crazy floating point stuff; we care how many systems have a working snprintf.


    > Sorry, Seebs, but it's not irrelevant at all. Tom St D was talking about
    > the possible unavailability of sprintf. I answered that point
    > (satisfactorily, I think). Then, for completeness, I added the
    > equivalent answer for snprintf, but it is necessary to bear in mind that
    > *only* implementations that conform to C99 are *required* not only to
    > provide snprintf but to conform with C99 semantics for that function. If
    > you've just got a J Random C90/C95 compiler that also provides snprintf,
    > be very *very* careful - the behaviour of its snprintf function is not
    > constrained by anything except the documentation for that implementation!


    Can you offer a single example of a system which offers a function named
    snprintf that is not substantively identical to the behavior of the standard
    function? All I can think of is that you might not want to do the thing
    of passing a null pointer and a zero length to query the length you need.

    >> However, snprintf() is safer than sprintf() for another reason, which is
    >> that it is not always *possible* for you to determine the resulting
    >> length. (Hint: "%p".)


    > Of course it's possible:


    > fprintf(fptmp, "%p%n\n", (void *)p, &n);


    > And once you know, you know, so you only have to do this once.


    That assumes that you are able to open a file, and that a file can hold the
    complete length of a %p, and also that all %p will be the same length...

    Basically, using sprintf safely is moderately hard, though certainly
    possible, but using snprintf safely is consistent and easy -- and the
    function is consistently either available or easily provided.

    The point of a library feature is that you are not really dependent on
    the implementation for it in some cases. Sure, not quite *trivial* to
    get an snprintf implementation, but it's in no way hard.

    I view the question of whether to rely on a feature as largely a matter
    of tradeoffs; there is a continuum from "runs only on this particular
    locally-patched implementation" to "runs on everything including pre-ISO
    C". There is also a continuum of utility, which depends greatly on what
    you're trying to do. From my point of view, snprintf is of extremely high
    utility, and is about as portable as anything outside of C90 ever gets. The
    only instance yet suggested of an implementation lacking it that anyone
    might care about is an MS compiler which provides the exact semantics of
    the standard library function under a different name, which is easily worked
    around.

    It's not as though I'm suggesting that people depend on the semantics of code
    which takes the address of a compound literal of variably-modified type
    in order to reduce a million line function by one line of code or anything.
    This is a major shift in functionality that has helped a great deal in writing
    robust code relatively quickly, and I've yet to hear of a real-world
    circumstance in which it's unavailable to me. (And from my point of view,
    "I can add an implementation to my program and run it" is available, and
    since the name "snprintf" isn't in implementation namespace, I'm safe
    to do so.)

    -s
    --
    Copyright 2010, all wrongs reversed. Peter Seebach /
    http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
    http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
    Seebs, Jun 5, 2010
    #14
  15. Tom St Denis

    Tom St Denis Guest

    On Jun 4, 7:47 pm, Richard Heathfield <> wrote:
    > > Anyways, let's leave it be.

    >
    > If you like. I doubt whether either of us is about to be convinced by
    > the other...


    That was kinda my point, I was trying to respectfully leave it be :)

    Since I'm not against rolling-my-own functions for non-portable
    things. In this case I respectfully disagree and would just write my
    own snprintf. But to each their own.

    Anyways, game #4 is on. Peace out.

    Tom
    Tom St Denis, Jun 5, 2010
    #15
  16. Tom St Denis

    Seebs Guest

    On 2010-06-05, William Ahern <william@wilbur.25thandClement.com> wrote:
    > The Windows(tm) implemention returns a negative value on overflow, rather
    > than the logical length, nor will it necessarily nul-terminate the buffer.
    >
    > If len > count, then count characters are stored in buffer, no
    > null-terminator is appended, and a negative value is returned.
    >
    > -- http://msdn.microsoft.com/en-us/library/2ts7cx93.aspx
    >
    > Considering that most people (*cough* myself *cough*) rarely expect
    > snprintf() to fail means this can be a serious security issue.


    Wow, that is spectacularly stupid.

    This just goes to support my general contention: You can write reliable
    code, but it cannot incorporate Microsoft code even by calling it for a
    very well-defined interface. They just plain don't care.

    If you have to target that system, you're just plain screwed out of the box.
    Consider looking for something more pleasant to do.

    -s
    --
    Copyright 2010, all wrongs reversed. Peter Seebach /
    http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
    http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
    Seebs, Jun 5, 2010
    #16
  17. Tom St Denis

    Ben Pfaff Guest

    Seebs <> writes:

    > On 2010-06-05, William Ahern <william@wilbur.25thandClement.com> wrote:
    >> The Windows(tm) implemention returns a negative value on overflow, rather
    >> than the logical length, nor will it necessarily nul-terminate the buffer.
    >>
    >> If len > count, then count characters are stored in buffer, no
    >> null-terminator is appended, and a negative value is returned.
    >>
    >> -- http://msdn.microsoft.com/en-us/library/2ts7cx93.aspx

    >
    > Wow, that is spectacularly stupid.


    It just means that Microsoft implemented an old, pre-standard
    version of this function and never updated it for C99. I don't
    think Microsoft makes any claims of C99 conformance.

    Old versions of GNU libc used the same return value convention.
    From the snprintf(3) manpage on my machine:

    The glibc implementation of the functions snprintf() and vsnprintf()
    conforms to the C99 standard, that is, behaves as described above,
    since glibc version 2.1. Until glibc 2.0.6 they would return -1 when
    the output was truncated.
    --
    char a[]="\n .CJacehknorstu";int putchar(int);int main(void){unsigned long b[]
    ={0x67dffdff,0x9aa9aa6a,0xa77ffda9,0x7da6aa6a,0xa67f6aaa,0xaa9aa9f6,0x11f6},*p
    =b,i=24;for(;p+=!*p;*p/=4)switch(0[p]&3)case 0:{return 0;for(p--;i--;i--)case+
    2:{i++;if(i)break;else default:continue;if(0)case 1:putchar(a[i&15]);break;}}}
    Ben Pfaff, Jun 5, 2010
    #17
  18. Tom St Denis

    Seebs Guest

    On 2010-06-05, Ben Pfaff <> wrote:
    > It just means that Microsoft implemented an old, pre-standard
    > version of this function and never updated it for C99. I don't
    > think Microsoft makes any claims of C99 conformance.


    Nope.

    > Old versions of GNU libc used the same return value convention.


    But not the behavior of NOT TERMINATING THE STRING.

    Which is a big part of the point.

    -s
    --
    Copyright 2010, all wrongs reversed. Peter Seebach /
    http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
    http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
    Seebs, Jun 5, 2010
    #18
  19. Tom St Denis

    Ike Naar Guest

    In article <>,
    Seebs <> wrote:
    >Can you offer a single example of a system which offers a function named
    >snprintf that is not substantively identical to the behavior of the standard
    >function? All I can think of is that you might not want to do the thing
    >of passing a null pointer and a zero length to query the length you need.


    Some older (pre-C99) implementations of snprintf produced return
    values different from the value required by the standard function.
    As an example, I have worked on an HP-UX system where snprintf returned
    a negative value if the buffer was too short to contain the output string.
    Ike Naar, Jun 5, 2010
    #19
  20. Tom St Denis

    Seebs Guest

    On 2010-06-05, Richard Heathfield <> wrote:
    > This is the "safer sprintf" snprintf function that y'all were touting so
    > heavily, right?


    No, this is Microsoft crap.

    > Well, I'd still rather play with fire than with fnire. Fire is honest.
    > It doesn't say "trust me, trust me, I'm safe" just before burning your
    > house down.


    Again, everyone who actually provides snprintf seems to be quite consistent
    about the key attributes:

    1. Does not overrun array.
    2. Terminates array correctly (there will be a null byte before the end of
    the string).

    I've used snprintf hundreds of times, and most of them would go from one
    line of code to dozens of lines of code if I had to try to correctly
    precalculate lengths to avoid overruns. It would be substantially more
    code than writing snprintf myself, and WAY more effort than just picking
    up a copy if there were a platform I had reason to care about which didn't
    have snprintf.

    There is a certain elemental joy to realizing that you never again have
    to program for a Microsoft system. It's like learning about portable code,
    and standards. Eerily like.

    -s
    --
    Copyright 2010, all wrongs reversed. Peter Seebach /
    http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
    http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
    Seebs, Jun 5, 2010
    #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. shea martin

    sprintf

    shea martin, Sep 2, 2004, in forum: Java
    Replies:
    5
    Views:
    3,593
    shea martin
    Sep 3, 2004
  2. Pep
    Replies:
    5
    Views:
    4,059
  3. CJ
    Replies:
    1
    Views:
    1,322
    Davlet Panech
    Oct 28, 2003
  4. HYRY
    Replies:
    10
    Views:
    598
    Bruno Desthuilliers
    Sep 26, 2007
  5. Ersek, Laszlo

    Re: Append with sprintf

    Ersek, Laszlo, Jun 4, 2010, in forum: C Programming
    Replies:
    1
    Views:
    883
    Fire Crow
    Jun 4, 2010
Loading...

Share This Page