56

The following code crashes C++ with a runtime error:

#include <string>

using namespace std;

int main() {
    string s = "aa";
    for (int i = 0; i < s.length() - 3; i++) {

    }
}

While this code does not crash:

#include <string>

using namespace std;

int main() {
    string s = "aa";
    int len = s.length() - 3;
    for (int i = 0; i < len; i++) {

    }
}

I just don't have any idea how to explain it. What could be the reason for this behavior?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user2534633
  • 945
  • 1
  • 8
  • 11
  • 21
    You should be getting a compiler warning about a signed/unsigned integer mismatch... – Cody Gray - on strike Jul 01 '13 at 07:01
  • it should run on a infinite loop. do you get a `segfault`? – DevZer0 Jul 01 '13 at 07:03
  • 7
    To understand the problem, try a `cout << s.length() - 3 << endl;`. Then, enable compiler warnings at their highest level... – gx_ Jul 01 '13 at 07:04
  • 1
    With VS2012, warning C4365 is disabled by default. You must 1) enable all warnings but then you get a lot of other useless warnings; 2) use #pragma warning(default : 4365) to "manually" activate it and set warnings level to 4. – Korchkidu Jul 01 '13 at 08:15
  • 6
    Can you explain how it was crashing though? seeing the answers I can understand an infinite loop, but not a crash – Akash Jul 01 '13 at 12:10
  • 3
    What compiler are you using, because using the g++ compiler both seem to run without error for me? – Sabashan Ragavan Jul 01 '13 at 14:26
  • 2
    @Akash it's undefined behaviour. Some machines 'wrap around' the unsigned part; others do not. – TheBlueCat Jul 01 '13 at 14:30
  • @Korchkidu: I believe /W4 turns that one on. – Billy ONeal Jul 01 '13 at 14:34
  • @BillyONeal: C4018 is. Unfortunately, C4365 is not. This specific warning is disabled by default http://msdn.microsoft.com/en-us/library/23k5d385.aspx. So you have to set the correct warnings level (4) plus enable C4365. – Korchkidu Jul 01 '13 at 15:52
  • @Korchkidu: Ah, yes. It looks like C4018 should flag this though. http://msdn.microsoft.com/en-us/library/y92ktdf2.aspx – Billy ONeal Jul 01 '13 at 16:30
  • @Korchkidu http://ideone.com/xHdWUx – Billy ONeal Jul 01 '13 at 16:34
  • @BillyONeal: ideone uses gcc it seems. Not surprising that VC++2012 and gcc behave differently for warnings though. – Korchkidu Jul 01 '13 at 17:22
  • @Korchkidu: I didn't compile that on IDEOne. If you look I put the cl command line there. IDEOne is in text mode in that post. – Billy ONeal Jul 01 '13 at 17:42
  • @BillyONeal: Indeed. But I am talking about C4365, not C4018 (this latter is not on the list I provided you). So for C4365, I think you must use pragma to activate it. – Korchkidu Jul 01 '13 at 17:55
  • @Korchkidu: Yes. My point is that 4365 is not relevant here. – Billy ONeal Jul 01 '13 at 19:47
  • I am still not getting why it's crashing. It should be an infinite loop. The comments mention some CXXXX stuff which do not make any sense to me. Is it a Microsoft issue? I haven't seen author mentioning Microsoft compiler, though. – varepsilon Jul 03 '13 at 10:00

8 Answers8

85

s.length() is unsigned integer type. When you subtract 3, you make it negative. For an unsigned, it means very big.

A workaround (valid as long the string is long up to INT_MAX) would be to do like this:

#include <string>

using namespace std;

int main() {

    string s = "aa";

    for (int i = 0; i < static_cast<int> (s.length() ) - 3; i++) {

    }
}

Which would never enter the loop.

A very important detail is that you have probably received a warning "comparing signed and unsigned value". The problem is that if you ignore those warnings, you enter the very dangerous field of implicit "integer conversion"(*), which has a defined behaviour, but it is difficult to follow: the best is to never ignore those compiler warnings.


(*) You might also be interested to know about "integer promotion".
Antonio
  • 19,451
  • 13
  • 99
  • 197
  • 8
    It is a workaround in this particular case, but a poor one generally. If the length of your string is larger than the maximum value representable by a signed integer, your cast risks undefined behavior. – Cody Gray - on strike Jul 01 '13 at 07:22
  • There's no reason to use an `int` in the first place. Using unsigned types only, the cast _and_ undefined behaviour can be avoided completely. – stefan Jul 01 '13 at 09:02
  • 3
    @SChepurin What do you mean exactly? – Antonio Jul 01 '13 at 09:04
  • @Antonio Sure it does, see my answer – stefan Jul 01 '13 at 09:08
  • @stefan Ok, so you meant using `unsigned int` AND changing the expression, that works indeed. Although the expression becomes slightly less readable. – Antonio Jul 01 '13 at 09:13
  • @Antonio I disagree about the expression beeing less readable, but anyway: Please see my updated answer that now includes a way to preserve the subtraction. – stefan Jul 01 '13 at 09:49
  • 6
    @Antonio This behavior is not called "integer promotion" but "integral conversion". "Integral promtions" happen when `char`, `short` and bitfields are implicitly promoted to the wider type `int`. – TemplateRex Jul 01 '13 at 11:00
  • 4
    “It is a workaround in this particular case, but a poor one generally”, I disagree that this is poor generally. How often do you expect to have strings with length greater than 2 billion characters? Sure, *be aware* that you may get truncation, but the alternatives to this sort of solution are often way more complex and often, this is fine. – mxcl Jul 01 '13 at 12:07
  • Most STL classes use `std::size_t` as a return type for "something that makes no sense to have a negative value" e.g. sizes of containers or lengths of strings. `std::size_t` is usually a typedef for an unsigned integer type. [See here](http://en.cppreference.com/w/cpp/types/size_t) – rwols Jul 01 '13 at 14:11
  • @TemplateRex Thanks for noticing that! I have updated my answer! – Antonio Jul 01 '13 at 21:19
  • 7
    Wow 57 upvotes (so far) for a solution that uses a cast instead of just using the right types? No offense, this will work, but imho this isn't the right way of doing it. I'm just impressed on how popular this answer seems to be. – stefan Jul 01 '13 at 21:23
  • @stefan I agree this attention is undeserved, but you don't need to state more than twice that your answer is better. – Antonio Jul 01 '13 at 21:30
  • @Antonio I actually didn't mention my answer at all. ;-) Seriously I congratulate you on this very popular answer. – stefan Jul 01 '13 at 21:32
  • 2
    Yes I don't agree with this answer either. Casting a string length (inherently unsigned) to a signed integer sounds like a design flaw just waiting to blow up. If you need your string to be at least three characters long, it means there's some kind of format you need it to obey, which means you should be validating it before manipulating it. – Thomas Jul 01 '13 at 21:51
  • @RichardHansen The program shown does not crash, as the loop is made empty. So giving the *exact* reason for which the original program was crashing is not possible, and not even necessary as braking boundaries is an obvious reason for crashing. Consider this: Would you have given `-1` if the current score of this answer was zero? – Antonio Jul 03 '13 at 06:12
  • The OP's code may not crash for you, but it could crash for someone else because there is undefined behavior in that code (see my answer). I'm not too concerned about an incorrect/incomplete answer with a score of 0; visitors to SO are more likely to be skeptical of such an answer. An incorrect/incomplete answer at 60+ is far more dangerous. – Richard Hansen Jul 03 '13 at 16:32
  • @RichardHansen That code with empty loop won't crash for anybody. Might hang in an infinite loop, but not crash. – Antonio Jul 03 '13 at 20:18
  • The C++ spec says that `int i = INT_MAX; i++;` has undefined behavior, which means the OP's code could theoretically crash even with an empty loop body. I'm not familiar with any implementation that would crash, but maybe the OP has a funny C++ compiler or a bizarre CPU architecture. All implementations I know of will wrap `i` to `INT_MIN`, which won't go into an infinite loop -- it'll stop once `i` gets to -1 because that will be converted to `(size_t)-1` and compare equal to `s.length() - 3`. – Richard Hansen Jul 03 '13 at 20:58
  • @RichardHansen I agree on the undefined behaviour. I do not believe though that code could crash in any machine or any implementation. Unfortunately, the OP did not respond to requests of clarifications, and didn't confirm if he experienced a crash or, instead, an infinite loop. – Antonio Jul 03 '13 at 21:55
28

First of all: why does it crash? Let's step through your program like a debugger would.

Note: I'll assume that your loop body isn't empty, but accesses the string. If this isn't the case, the cause of the crash is undefined behaviour through integer overflow. See Richard Hansens answer for that.

std::string s = "aa";//assign the two-character string "aa" to variable s of type std::string
for ( int i = 0; // create a variable i of type int with initial value 0 
i < s.length() - 3 // call s.length(), subtract 3, compare the result with i. OK!
{...} // execute loop body
i++ // do the incrementing part of the loop, i now holds value 1!
i < s.length() - 3 // call s.length(), subtract 3, compare the result with i. OK!
{...} // execute loop body
i++ // do the incrementing part of the loop, i now holds value 2!
i < s.length() - 3 // call s.length(), subtract 3, compare the result with i. OK!
{...} // execute loop body
i++ // do the incrementing part of the loop, i now holds value 3!
.
.

We would expect the check i < s.length() - 3 to fail right away, since the length of s is two (we only every given it a length at the beginning and never changed it) and 2 - 3 is -1, 0 < -1 is false. However we do get an "OK" here.

This is because s.length() isn't 2. It's 2u. std::string::length() has return type size_t which is an unsigned integer. So going back to the loop condition, we first get the value of s.length(), so 2u, now subtract 3. 3 is an integer literal and interpreted by the compiler as type int. So the compiler has to calculate 2u - 3, two values of different types. Operations on primitive types only work for same types, so one has to be converted into the other. There are some strict rules, in this case, unsigned "wins", so 3 get's converted to 3u. In unsigned integers, 2u - 3u can't be -1u as such a number does not exists (well, because it has a sign of course!). Instead it calculates every operation modulo 2^(n_bits), where n_bits is the number of bits in this type (usually 8, 16, 32 or 64). So instead of -1 we get 4294967295u (assuming 32bit).

So now the compiler is done with s.length() - 3 (of course it's much much faster than me ;-) ), now let's go for the comparison: i < s.length() - 3. Putting in the values: 0 < 4294967295u. Again, different types, 0 becomes 0u, the comparison 0u < 4294967295u is obviously true, the loop condition is positively checked, we can now execute the loop body.

After incrementing, the only thing that changes in the above is the value of i. The value of i will again be converted into an unsigned int, as the comparison needs it.

So we have

(0u < 4294967295u) == true, let's do the loop body!
(1u < 4294967295u) == true, let's do the loop body!
(2u < 4294967295u) == true, let's do the loop body!

Here's the problem: What do you do in the loop body? Presumably you access the i^th character of your string, don't you? Even though it wasn't your intention, you didn't only accessed the zeroth and first, but also the second! The second doesn't exists (as your string only has two characters, the zeroth and first), you access memory you shouldn't, the program does whatever it wants (undefined behaviour). Note that the program isn't required to crash immediately. It can seem to work fine for another half an hour, so these mistakes are hard to catch. But it's always dangerous to access memory beyond the bounds, this is where most crashes come from.

So in summary, you get a different value from s.length() - 3 from that what you'd expect, this results in a positive loop condition check, that leads to repetitive execution of the loop body, which in itself accesses memory it shouldn't.

Now let's see how to avoid that, i.e. how to tell the compiler what you actually meant in your loop condition.


Lengths of strings and sizes of containers are inherently unsigned so you should use an unsigned integer in for loops.

Since unsigned int is fairly long and therefore undesirable to write over and over again in loops, just use size_t. This is the type every container in the STL uses for storing length or size. You may need to include cstddef to assert platform independence.

#include <cstddef>
#include <string>

using namespace std;

int main() {

    string s = "aa";

    for ( size_t i = 0; i + 3 < s.length(); i++) {
    //    ^^^^^^         ^^^^
    }
}

Since a < b - 3 is mathematically equivalent to a + 3 < b, we can interchange them. However, a + 3 < b prevents b - 3 to be a huge value. Recall that s.length() returns an unsigned integer and unsigned integers perform operations module 2^(bits) where bits is the number of bits in the type (usually 8, 16, 32 or 64). Therefore with s.length() == 2, s.length() - 3 == -1 == 2^(bits) - 1.


Alternatively, if you want to use i < s.length() - 3 for personal preference, you have to add a condition:

for ( size_t i = 0; (s.length() > 3) && (i < s.length() - 3); ++i )
//    ^             ^                    ^- your actual condition
//    ^             ^- check if the string is long enough
//    ^- still prefer unsigned types!
stefan
  • 10,215
  • 4
  • 49
  • 90
  • @MichaelKjörling Nope this is impossible. `i` starts with 0 and goes up. So at `i == INT_MAX - 4`, it holds that `i + 3 == s.length()`. Therefore the condition is broken and the loops ends. No possibility of failure whatsoever. Be careful if the incrementation is not `i++`. If this is e.g. `i *= 2`, the condition should be changed. For looping with `i++`, this simply can't fail. Note that the starting point must be small enough too. So `for ( size_t i = std::numeric_limits::max() - 1; i + 3 < n; ++i )` would not do the intended thing, but starting from 0 always works. – stefan Jul 01 '13 at 09:41
  • Ahh, you are correct. It's scary territory when you start getting close to INT_MAX and friends. – user Jul 01 '13 at 09:43
  • Why would you need `unsigned int`? I prefer just `for (unsigned i =...`, which is nicely readable and equivalent. — `size_t` is good because it's the same type as `std::vector::length()`, but totally misses the intention. – leftaroundabout Jul 01 '13 at 12:37
  • @leftaroundabout yes, technically `unsigned` suffices. I personally dislike this, because there are other unsigned types and I want to be 100% clear in my programs. size_t is just the perfect compromise. It's the type used for `std::string::length()` and `somestdcontainer::size()` and is unsigned and very short to write. – stefan Jul 01 '13 at 21:20
  • 1
    That doesn't make sense to me. If you want to be _clear_, `size_t` is hardly a good choice – it's conceptually weird to be iterating over a size, when actually the container size stays fixed. `size_t` is _concise_, and correct, yes – but not as clear as `unsigned`. – leftaroundabout Jul 02 '13 at 00:53
  • @leftaroundabout If you want elements of a container (here, characters of a string), neither `size_t` nor `int` or `unsigned int` really say that. You'd have to go with `for ( auto c : string ){...}`. But this doesn't work with manipulated start or end condition. Iterators are unnecessary here, but also feasible. `size_t` _should_ be used as it is the only type _guaranteed_ to be the same type as returned by `.length()` (or `.size()`). – stefan Jul 02 '13 at 06:41
  • 1
    @leftaroundabout You're not iterating over a size, you're iterating over an array (or vector, or container, whatever) which *has* a size. So it conceptually makes perfect sense. I guess it is up to interpretation. – Thomas Jul 02 '13 at 12:30
  • @RichardHansen Thank's for pointing that out to me. I've added (quite a long) explanation. I'd love to read your thoughts on that! – stefan Jul 03 '13 at 07:44
  • Much improved, although I see you're assuming that the OP left out code in the `for` loop body. That's not what the OP asked -- there's nothing to indicate that the provided code is an abbreviated stand-in for some other code. See my answer. – Richard Hansen Jul 03 '13 at 16:37
  • @RichardHansen Added that as well referring to your good answer. – stefan Jul 03 '13 at 17:12
12

Actually, in the first version you loop for a very long time, as you compare i to an unsigned integer containing a very large number. The size of a string is (in effect) the same as size_t which is an unsigned integer. When you subtract the 3 from that value it underflows and goes on to be a big value.

In the second version of the code, you assign this unsigned value to a signed variable, and so you get the correct value.

And it's not actually the condition or the value that causes the crash, it's most likely that you index the string out of bounds, a case of undefined behavior.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • 2
    Are you sure the first loop is just very long, and not infinite? Can an int ever reach std::numeric_limits::max() ? What will happen when `i` reach is boundary? Answering my self, probably it will become negative and in integer promotion it will really become bigger/the same value of the right part of the expression. Difficult case though! :) – Antonio Jul 01 '13 at 07:12
  • 1
    As far as the comparison goes, the type of `i` doesn't really matter; even without knowing the rules of promotion (which in this case will make `i` unsigned), you can reason that you're comparing two bit representations, and the less than condition will fail when `i` is the maximum representable value. The fact that as an int it is signed isn't relevant for that comparison. – sapi Jul 01 '13 at 08:16
  • 5
    Over/underflow of *unsigned* types is actually well-defined. See: http://stackoverflow.com/q/988588/1030702, http://stackoverflow.com/a/2760612/1030702, the C/C++ standards. It's undefined for *signed* types, though popular compilers (VC++, GCC) do the same thing nowadays - still not good to rely on it. – Bob Jul 01 '13 at 12:46
  • "it's most likely that you index the string out of bounds, a case of undefined behavior" -- where in the original code is a string being indexed? – Richard Hansen Jul 02 '13 at 22:05
  • @RichardHansen In the code the OP doesn't show. If you have a string, and uses the string length in a loop condition, it's very likely that you will use the iterator value as index in that string in the loop. Of course I'm not sure, that's why I said that it's *likely*. – Some programmer dude Jul 03 '13 at 05:40
5

Assuming you left out important code in the for loop

Most people here seem unable to reproduce the crash—myself included—and it looks like the other answers here are based on the assumption that you left out some important code in the body of the for loop, and that the missing code is what is causing your crash.

If you are using i to access memory (presumably characters in the string) in the body of the for loop, and you left that code out of your question in an attempt to provide a minimal example, then the crash is easily explained by the fact that s.length() - 3 has the value SIZE_MAX due to modular arithmetic on unsigned integer types. SIZE_MAX is a very big number, so i will keep getting bigger until it is used to access an address that triggers a segfault.

However, your code could theoretically crash as-is, even if the body of the for loop is empty. I am unaware of any implementations that would crash, but maybe your compiler and CPU are exotic.

The following explanation does not assume that you left out code in your question. It takes on faith that the code you posted in your question crashes as-is; that it isn't an abbreviated stand-in for some other code that crashes.

Why your first program crashes

Your first program crashes because that is its reaction to undefined behavior in your code. (When I try running your code, it terminates without crashing because that is my implementation's reaction to the undefined behavior.)

The undefined behavior comes from overflowing an int. The C++11 standard says (in [expr] clause 5 paragraph 4):

If during the evaluation of an expression, the result is not mathematically defined or not in the range of representable values for its type, the behavior is undefined.

In your example program, s.length() returns a size_t with value 2. Subtracting 3 from that would yield negative 1, except size_t is an unsigned integer type. The C++11 standard says (in [basic.fundamental] clause 3.9.1 paragraph 4):

Unsigned integers, declared unsigned, shall obey the laws of arithmetic modulo 2n where n is the number of bits in the value representation of that particular size of integer.46

46) This implies that unsigned arithmetic does not overflow because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting unsigned integer type.

This means that the result of s.length() - 3 is a size_t with value SIZE_MAX. This is a very big number, bigger than INT_MAX (the largest value representable by int).

Because s.length() - 3 is so big, execution spins in the loop until i gets to INT_MAX. On the very next iteration, when it tries to increment i, the result would be INT_MAX + 1 but that is not in the range of representable values for int. Thus, the behavior is undefined. In your case, the behavior is to crash.

On my system, my implementation's behavior when i is incremented past INT_MAX is to wrap (set i to INT_MIN) and keep going. Once i reaches -1, the usual arithmetic conversions (C++ [expr] clause 5 paragraph 9) cause i to equal SIZE_MAX so the loop terminates.

Either reaction is appropriate. That is the problem with undefined behavior—it might work as you intend, it might crash, it might format your hard drive, or it might cancel Firefly. You never know.

How your second program avoids the crash

As with the first program, s.length() - 3 is a size_t type with value SIZE_MAX. However, this time the value is being assigned to an int. The C++11 standard says (in [conv.integral] clause 4.7 paragraph 3):

If the destination type is signed, the value is unchanged if it can be represented in the destination type (and bit-field width); otherwise, the value is implementation-defined.

The value SIZE_MAX is too big to be representable by an int, so len gets an implementation-defined value (probably -1, but maybe not). The condition i < len will eventually be true regardless of the value assigned to len, so your program will terminate without encountering any undefined behavior.

Richard Hansen
  • 51,690
  • 20
  • 90
  • 97
  • The program invokes UB probably a long time before i reaches INT_MAX, namely once the `i^th` character is accessed in the loop body for `i > 1 `. If the loop is empty or the characters are untouched, your explanation holds. – stefan Jul 03 '13 at 07:50
  • @stefan: You may be right, but I don't like assuming that there is missing code in the OP's question. To me, the question strongly indicated that the code was crashing as-is; that the code isn't an abbreviated stand-in for some other code that crashes. I updated my answer to make my interpretation of the question clear. – Richard Hansen Jul 03 '13 at 15:31
  • 1
    The assumption that code inside `{}` that was not posted causes the crash is very reasonable, though. While "program invokes UB" and "UB can be anything, including a crash" is technically of course correct, in practice it is utter nonsense. An overflowing integer does not produce a crash. There's trapping floating-point math, yes, but there's no such thing as "integer overflow trap" on any _real_ CPU. However, for example using `string::operator[]` with a negative index may very well produce a crash (or `string::at` may throw) which is a very real thing to happen, not only in theory. – Damon Jul 03 '13 at 16:15
  • @Damon: Fair point. I updated my answer to include the "missing code" case. – Richard Hansen Jul 03 '13 at 16:52
3

The type of s.length() is size_t with a value of 2, therefore s.length() - 3 is also an unsigned type size_t and it has a value of SIZE_MAX which is implementation defined (which is 18446744073709551615 if its size is 64 bit). It is at least 32 bit type (can be 64 bit in 64 bit platforms) and this high number means an indefinite loop. In order to prevent this problem you can simply cast s.length() to int:

for (int i = 0; i < (int)s.length() - 3; i++)
{
          //..some code causing crash
}

In the second case len is -1 because it is a signed integer and it does not enter the loop.

When it comes to crashing, this "infinite" loop is not the direct cause of the crash. If you share the code within the loop you can get further explanation.

fatihk
  • 7,789
  • 1
  • 26
  • 48
1

Since s.length() is unsigned type quantity, when you do s.length()-3, it becomes negative and negative values are stored as large positive values (due to unsigned conversion specifications) and the loop goes infinite and hence it crashes.

To make it work, you must typecast the s.length() as :

static_cast < int > (s.length())

Shekhar Kumar
  • 2,130
  • 1
  • 15
  • 14
1

The problem you are having arises from the following statement:

i < s.length() - 3

The result of s.length() is of the unsigned size_t type. If you imagine the binary representation of two:

0...010

And you then substitute three from this, you are effectively taking off 1 three times, that is:

0...001

0...000

But then you have a problem, removing the third digit it underflows, as it attempts to get another digit from the left:

1...111

This is what happens no matter if you have an unsigned or signed type, however the difference is the signed type uses the Most Significant Bit (or MSB) to represent if the number is negative or not. When the undeflow occurs it simply represents a negative for the signed type.

On the other hand, size_t is unsigned. When it underflows it will now represent the highest number size_t can possibly represent. Thus the loop is practically infinite (Depending on your computer, as this effects the maximum of size_t).

In order to fix this problem, you can manipulate the code you have in a few different ways:

int main() {
    string s = "aa";
    for (size_t i = 3; i < s.length(); i++) {

    }
}

or

int main() {
    string s = "aa";
    for (size_t i = 0; i + 3 < s.length(); i++) {

    }
}

or even:

int main() {
    string s = "aa";
    for(size_t i = s.length(); i > 3; --i) {

    }
}

The important things to note is that the substitution has been omitted and instead addition has been used elsewhere with the same logical evaluations. Both the first and last ones change the value of i that is available inside the for loop whereas the second will keep it the same.

I was tempted to provide this as an example of code:

int main() {
    string s = "aa";
    for(size_t i = s.length(); --i > 2;) {

    }
}

After some thought I realised this was a bad idea. Readers' exercise is to work out why!

meiamsome
  • 2,876
  • 1
  • 17
  • 19
0

The reason is the same as int a = 1000000000; long long b = a * 100000000; would give error. When compilers multiplies these numbers it evaluates it as ints, since a and literal 1000000000 are ints, and since 10^18 is much more large than the upper bound of int, it will give error. In your case we have s.length() - 3, as s.length() is unsigned int, it cant be negative, and since s.length() - 3 is evaluated as unsigned int, and its value is -1, it gives error here too.

Mamuka
  • 102
  • 1
  • 4