Rival library?

More safety problems than security problems, though there are points
where the two overlap. By passing (copies of) stack-allocated objects
outside the library to user code, which the user code was then able to
obtain references to. Hilarity ensues once the stack gets cleaned up
and objects that the object contains a reference to are deallocated
out from under the user.

Errr… That’s a typical newbie error, right? Compilers issue warnings
for these types of errors.

Only when the compiler knows what’s going on. See above, re:
passing them outside of the library.

No, of course not. See above, “stack allocation is wonderful for
value types.” I’m suggesting that C++ should dump stack allocation
for objects altogether.

So where exactly do you draw the line between “objects” and “value
types”? Is a class containing only a few ints and no
pointers/references to anything an object, or a “value type”?

That sounds like a value type to me, and a good candidate for putting
into a struct, though it depends on how many ints constitute “a few”.
Anything significantly larger than sizeof(pointer) probably should be a
reference type anyway, for performance reasons.

Still, I don’t think the dumbness of a few programmers should dumb down
the whole language. :slight_smile:

Neither do I, but you have to draw the line somewhere. I prefer to err on
the side of caution. These aren’t issues for “a few dumb programmers”.
They’re very common C++ gotchas that everyone ends up getting tripped
up by, and has to learn and commit to memory, and even then can end up
forgetting, causing embarrassing and occasionally dangerous problems.
When it’s that easy to get it wrong, that’s a strong indication that the
underlying system is badly-designed. The correct solution isn’t “bend
every single user’s thought patterns away from what’s intuitive into what
fits the system,” it’s “fix the system to make it more intuitive!”

Let’s not discuss performance issues of C-style vs Pascal-style
strings :slight_smile: I don’t think it makes a huge difference one way or the
other.

Please don’t take this the wrong way, but if you truly think that
having to run a linear scan to find the length of a string in O(n) time
instead of having it immediately available in O(1) time, and needing
to perform all string operations one byte at a time, with a conditional
test between each byte, instead of in the largest chunks the CPU can
use to transfer data, with the conditional test against a length value
that’s known from the start and can be kept in a register that doesn’t
have to have values loaded into it over and over, doesn’t make a
significant difference, (especially on low-end CPUs like you’re
talking about!) then yes, I probably shouldn’t be discussing
performance issues with you.

But the memory usage might. Making the length prefix
variable-sized isn’t really feasible since then you would have to
compile all the code an app uses (including libraries) with the same
prefix-size options. So you end up using 4-byte prefixes. So each
string uses 3 bytes more memory than a C string would. This doesn’t
normally matter on desktops of course, but on microcontrollers and the
like, it does matter.

What sort of microcontrollers are you referring to? These days, even
tiny embedded systems like cellphones have access to hundreds of
megabytes of RAM. An extra 3 bytes per string might have been
significant 10 years ago, but today?

But due to pointer aliasing, changing a string with multiple
references to it would cause trouble. So how do you fix that?

If you change a string, it is changed, no matter how many references to
it exist. This is just plain obvious. Everything else would be
counter-intuitive, and wrong. Nothing to fix here.

Not necessarily. Yes, you need to copy a string when you make
changes to it, to avoid stomping aliased references, but how do you
know when is the right time to copy? If you pass a C string into a
function, you don’t know if it’s got one reference to it or a hundred,
so you end up needing to make a (possibly unnecessary) copy
if you’re going to change it. This can be very expensive if it’s a
large string, especially since C has to copy the string one byte at a
time with a conditional test between each byte.

By building reference counting into the language’s string type,
you ensure that copying always takes place when it needs to, and
never when it doesn’t. No chance of user error there. I’d have to
check to make sure, but I don’t think the Delphi standard library
even has a strcopy() function, because it doesn’t need one.>----- Original Message ----

From: Johannes Kroll
Subject: Re: [SDL] rival library?

Hey guys, this is a great discussion, but it’s gotten big and off
topic. Please take it off list.

Thanks!

Ack! Sorry, I sent my last reply before I saw this request.>----- Original Message ----

From: Sam Lantinga
Subject: Re: [SDL] rival library?

Sorry about that. Stopping right now.On Sun, Dec 20, 2009 at 5:21 PM, Sam Lantinga wrote:

Hey guys, this is a great discussion, but it’s gotten big and off
topic. Please take it off list.

Thanks!

On Sun, Dec 20, 2009 at 8:17 AM, Johannes Kroll wrote:

On Sun, 20 Dec 2009 07:48:36 -0800 Jeff Post <j_post at pacbell.net> wrote:

On Sunday 20 December 2009 03:40, Johannes Kroll wrote:

Unlike heap allocation, using data on the stack is automatically
cache-friendly. It’s perfectly possible to allocate data from the heap
though. It’s done all the time. I’m not familiar with QT, so I can’t
comment on whether using stack-allocated objects in QT causes security
problems (how?).

Stack (or buffer) overrun. The following copied from
http://weblogs.asp.net/gad/archive/2004/03/23/94996.aspx

[…]

Apparently Mason Wheeler was not talking about buffer overflows. He was
talking about returning addresses of stack-allocated data (in QT).
Besides, 1) if I understand him correctly, he would still allocate
"value types" on the stack, making stack overflows still possible, 2)
Buffer overflows on the heap can be just as dangerous, 3) … like you
said, learn to use the screwdriver, or don’t use it :wink:


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


-Sam Lantinga, Founder and President, Galaxy Gameworks LLC


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Mason Wheeler skrev:

It’s a telling point that RAII isn’t found hardly anywhere outside of
C++ Land. The only other language I’m aware of that implements it is
D, which based a lot of its object model off of C++'s.

Just look it up on Wikipedia: “Resource Acquisition Is Initialization,
often referred to by the acronym RAII (or, erroneously, RIIA), is a
popular design pattern in several object oriented programming languages
like C++, D and Ada.”

I have used RAII in both C++ and Ada. It is NOT a broken design pattern.
Nor is stack allocation. I wrote a whole crossword generation algorithm
without heap allocation in Ada2005, a language superior to C++ in most
aspects. A stack is excellent for such algorithms using backtracking.

When given a choice, I use Ada. The thing where it is most superior to
C++ is type safety. It has typesafe integers, enumeration types,
modular types, fixed point types, floating point types. Every time when
I have spent hours (or days) of my free time hunting down a bug in C++
where someone mixed up x/y coordinates, I curse that it is not Ada,
where the compiler would have caught it immediately.

Ada does not have full multiple inheritance like C++, only one main base
and the rest are so called interfaces. Bindings to C and C++ are part of
the Ada standard. Ada has strings with O(1) length. It has real package
semantics instead of C++'s hackish include guards, translation units and
namespaces. Each floating point type can be set individually to use
machine rounding for maximum speed or portable arithmetics for identical
results on different platforms, while C++ only has -ffast-math, that
enables machine rounding for all floating point calculations in a
translation unit. Returning pointers to objects that go out of scope is
prohibited by having two ways to take the address of something. With the
regular way, the compiler will complain if the pointer still exists when
the object pointed to goes out of scope. With the unsafe way, the
programmer can get around that restriction when he knows what he is
doing. Furthermore, it is possible to say that a pointer should be
constant and not null (like a reference in C++), just constant (like *
const in C++), neither constant nor not null (like * in C++) or even
nonconstant but not null (which can not be expressed in C++). It it is
only possible to take the address of something that has been declared as
aliased. Therefore it is clear to both humans and machines exactly what
can have aliases. This allows optimizations without complicated (and in
some jurisdictions possibly patented) alias analysis. No other
general-purpose programming language gives faster executables than Ada.
Arrays are automatically rangechecked when accessed. That can be
disabled for performance (I have yet to find out how to disable the
range check in std::vector::at for release builds). Manual memory
management is available, as well as compiling to Java virtual machine
with garbage collection. Memory can be allocated in different so called
pools.

The common C++ error that a member function is intended to override a
virtual member function of a base type, but it does not happen because
the function signatures are not identical or the “virtual” keyword is
missing in the base, is eliminated with the keyword “overrides”. If a
function with this keyword does not override anything, it is an error.

Error messages are incredibly more useful in Ada than in C++. Ever
forgot a ; when using templates in C++ and got a 20 pages long error
message? The Ada compiler will just say file:line:column: missing ;

Ever got “terminate called after throwing an instance of
’std::out_of_range’” from a C++ program and wondered why it could not
include filename:linenumber? An Ada program would show it to you.

However, some little things annoy me in Ada, such as the lack of += and
similar operators from C++. So instead of
Some_Very_Long_And_Complicated_Expression +:= A; I have to write
Some_Very_Long_And_Complicated_Expression :=
Some_Very_Long_And_Complicated_Expression + A;

Ada was designed to enable efficient development of very complex and
very critical software systems that work right. But it is surprising
that not more people have realized how useful it is even for little
projects that are not so complex or critical, like games. I have, but I
like to work on existing projects, so I do not have a choice.