Wednesday, March 8, 2023

Digest for comp.lang.c++@googlegroups.com - 25 updates in 5 topics

Paavo Helde <eesnimi@osa.pri.ee>: Mar 08 08:40AM +0200

08.03.2023 01:10 Richard kirjutas:
> do it. If I started bitching about Java and when asked to put up or
> shut up, I started showing JavaScript, people would rightly laugh at
> me.
 
+100
"Öö Tiib" <ootiib@hot.ee>: Mar 07 11:21PM -0800

On Wednesday, 8 March 2023 at 00:26:14 UTC+2, Lynn McGuire wrote:
> use Rust…'], C++ must evolve or be left behind. The question is, at what
> price?" he said."
> https://twitter.com/markrussinovich/status/1571995117233504257?lang=en
 
Most people agree that C++ contains too lot of features. They only differ
by opinion where to cut. I would put most effort into places where it says
"undefined behavior". I think half of such places can be replaced with
"program is ill formed", "std::terminate is called" or one of the features
that lead to described situation can be cut out (as badly thought thru).
scott@slp53.sl.home (Scott Lurndal): Mar 08 04:10PM

>"undefined behavior". I think half of such places can be replaced with=20
>"program is ill formed", "std::terminate is called" or one of the features
>that lead to described situation can be cut out (as badly thought thru).
 
The nice thing about C++ is that one need not use any of the new crap.
Keith Thompson <Keith.S.Thompson+u@gmail.com>: Mar 08 09:52AM -0800

> "undefined behavior". I think half of such places can be replaced with
> "program is ill formed", "std::terminate is called" or one of the features
> that lead to described situation can be cut out (as badly thought thru).
 
I'd be interested in seeing some cases of undefined behavior that could
reasonably be detected at compile time or at run time. I'm sure there
are some, but I'd be surprised it were as many as half.
 
Just one example: Signed integer overflow has undefined behavior, and
defining it would require runtime checks.
 
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for XCOM Labs
void Void(void) { Void(); } /* The recursive call of the void */
Malcolm McLean <malcolm.arthur.mclean@gmail.com>: Mar 08 10:18AM -0800

On Wednesday, 8 March 2023 at 17:53:09 UTC, Keith Thompson wrote:
> are some, but I'd be surprised it were as many as half.
 
> Just one example: Signed integer overflow has undefined behavior, and
> defining it would require runtime checks.
 
Not on the vast majority of platforms. However you'd have to define the
behaviour as a two's complement wrap.
"Alf P. Steinbach" <alf.p.steinbach@gmail.com>: Mar 08 07:20PM +0100

On 2023-03-08 6:52 PM, Keith Thompson wrote:
> are some, but I'd be surprised it were as many as half.
 
> Just one example: Signed integer overflow has undefined behavior, and
> defining it would require runtime checks.
 
I guess you meant to write, "detecting it", not "defining it".
 
Defining signed overflow as wrap-around requires no runtime checks, now
that C++ integers are guaranteed two's complement.
 
Some optimization opportunities would be lost, but maybe others gained.
 
 
- Alf
David Brown <david.brown@hesbynett.no>: Mar 08 07:47PM +0100

On 08/03/2023 17:10, Scott Lurndal wrote:
>> "program is ill formed", "std::terminate is called" or one of the features
>> that lead to described situation can be cut out (as badly thought thru).
 
> The nice thing about C++ is that one need not use any of the new crap.
 
Or one need not use the old crap, and can use the new better features
instead.
 
Or a mixture. Or all. Or nearly none.
 
It's a big language, and a big library - few people are going to have
use for all of it, but the subset you find useful will vary widely from
person to person.
James Kuyper <jameskuyper@alumni.caltech.edu>: Mar 08 02:10PM -0500

On 3/8/23 13:20, Alf P. Steinbach wrote:
> On 2023-03-08 6:52 PM, Keith Thompson wrote:
...
 
>> Just one example: Signed integer overflow has undefined behavior, and
>> defining it would require runtime checks.
 
> I guess you meant to write, "detecting it", not "defining it".
 
No, he meant "defining it". If they were to choose to define the
behavior of signed integer overflow, then on platforms where the defined
behavior was not the same as that which would naturally occur, run-time
checks would be required to change the behavior.
Michael S <already5chosen@yahoo.com>: Mar 08 11:21AM -0800

On Wednesday, March 8, 2023 at 6:10:28 PM UTC+2, Scott Lurndal wrote:
> >"program is ill formed", "std::terminate is called" or one of the features
> >that lead to described situation can be cut out (as badly thought thru).
> The nice thing about C++ is that one need not use any of the new crap.
 
That 's not 100% true.
Two example of [not so] new non-crap libraries that are entangled with [not so] new
crap - std::chrono and std::random.
The former is infected by rational numbers crap.
The later is soiled both with <functional> and and with std::ref.
And both of them misuse operator overloading.
Not that I am aware of many places in standard library where operator overloading
is not misused.
David Brown <david.brown@hesbynett.no>: Mar 08 08:45PM +0100

On 08/03/2023 19:18, Malcolm McLean wrote:
>> defining it would require runtime checks.
 
> Not on the vast majority of platforms. However you'd have to define the
> behaviour as a two's complement wrap.
 
Wrapping is not the only option. But since wrapping is the most useless
behaviour for signed integer overflow, doing something helpful (such as
the suggested call to std::terminate, or other error message to aid
debugging) /would/ require run-time checks.
Pawel Por <porparek@gmail.com>: Mar 08 10:29AM -0800

Thank you for response.
 
> Why? The code you provided does not use assignment operator at all. Why
> would you expect assignment operator to be called?
Right, I expect the move constructor to be called - sorry for confusion.
 
>> I expect the Dog::Dog(Dog&&) to be called (sorry for confusion)
>But it _is_ called. Here's the output I get from your code
It is the std::move that forces the move constructor to be called. For me it looks like the argument is passed by lvalue reference to the MyList<T>::push_front(T&&) function.
I've modified the code to show this:
 
#include <iostream>
#include <forward_list>
#include <utility>
 
template <typename T>
void p(const T &v)
{
std::cout << v << std::endl;
}
 
struct Dog
{
Dog() { p(__PRETTY_FUNCTION__); }
Dog(const Dog&) { p(__PRETTY_FUNCTION__); }
Dog(Dog&&) { p(__PRETTY_FUNCTION__); }
 
Dog& operator=(const Dog&) { p(__PRETTY_FUNCTION__); return *this; }
Dog& operator=(Dog &&) { p(__PRETTY_FUNCTION__); return *this; }
};
 
template<typename T>
struct MyList
{
void push_front(T &&v) { p(__PRETTY_FUNCTION__); p("before std::move"); T x = std::move( v ); p("after std::move"); (void) x;}
};
 
int main()
{
MyList<Dog> ml;
std::forward_list<Dog> fl;
Dog dog;
 
p("ml.push_front");
ml.push_front(std::move(dog));
p("fl.push_front");
fl.push_front(std::move(dog));
}
 
Here is the output:
Dog::Dog()
ml.push_front
void MyList<T>::push_front(T&&) [with T = Dog]
before std::move
Dog::Dog(Dog&&)
after std::move
fl.push_front
Dog::Dog(Dog&&)
 
I expect the Dog's move constructor to be called when passing an argument to MyList<T>::push_front(T&&)
Muttley@dastardlyhq.com: Mar 08 10:04AM

Just discovered that I can't do this in C++17:
 
throw pair<string,int>("hello",123)
 
catch(auto &[str,val])
{
}
 
Is there a good reason why this can't be implemented?
"Öö Tiib" <ootiib@hot.ee>: Mar 08 03:23AM -0800

> {
> }
 
> Is there a good reason why this can't be implemented?
 
Hmm I can't think of any way to implement it. Can you?
 
How can the compiler know what that exception could possibly be?
It has none of information at all. The throw can be anywhere far up
stack in dynamically linked library. So how to bind to unlimited kinds
of whatever (struct {? a, ? b;} , std::array<?,2>, std::tuple<?,?>,
std::pair<?, ?>, etc.) structurally by current language rules?
Muttley@dastardlyhq.com: Mar 08 11:45AM

On Wed, 8 Mar 2023 03:23:52 -0800 (PST)
 
>Hmm I can't think of any way to implement it. Can you?
 
>How can the compiler know what that exception could possibly be?
>It has none of information at all. The throw can be anywhere far up
 
Of course it has the information. It knows whats been thrown so it knows
if it can be captured in a structure binding. How does it know how to
set a binding from the return value of a function then?
 
>stack in dynamically linked library. So how to bind to unlimited kinds
>of whatever (struct {? a, ? b;} , std::array<?,2>, std::tuple<?,?>,
>std::pair<?, ?>, etc.) structurally by current language rules?
 
You could use the same argument for structured bindings anywhere.
Sam <sam@email-scan.com>: Mar 08 07:13AM -0500

> >It has none of information at all. The throw can be anywhere far up
 
> Of course it has the information. It knows whats been thrown so it knows
> if it can be captured in a structure binding.
 
It only knows what's thrown at runtime. Not at compile time. It is
fundamental to C++: the types of all objects must be known at compile time.
 
"auto" doesn't change that. All that "auto" is, is an alias that says, in a
matter of speaking "unchanged", or "same as whatever you're assigning me".
 
When a function's return value is declared as "auto", the compiler looks at
the actual "return" statements, and uses whatever they do. If only the
declaration is available you'll skate by until either the function
definition is available, or until something tries to use its return value in
any way.
 
> How does it know how to
> set a binding from the return value of a function then?
 
Because it knows the actual type of the object that the function returns, as
long as its declared.
 
Try to do the same structural binding with a function that, itself, is
declared as returning an auto, without the function's body being compiled.
See how much progress you'll make.
 
> >of whatever (struct {? a, ? b;} , std::array<?,2>, std::tuple<?,?>,
> >std::pair<?, ?>, etc.) structurally by current language rules?
 
> You could use the same argument for structured bindings anywhere.
 
No, you can't.
Muttley@dastardlyhq.com: Mar 08 04:21PM

On Wed, 08 Mar 2023 07:13:05 -0500
 
>> Of course it has the information. It knows whats been thrown so it knows
>> if it can be captured in a structure binding.
 
>It only knows what's thrown at runtime. Not at compile time. It is
 
It knows what is thrown at runtime.
It knows what *could* be thrown at compile time.
 
And if it knows what could be thrown and what catch statements are encompassing
those throws then it could compile in suitable types for an auto in the catch.
Bonita Montero <Bonita.Montero@gmail.com>: Mar 08 06:28PM +0100

> {
> }
> Is there a good reason why this can't be implemented?
 
With the thrown object there's some type information passed
along to verify if it fits against the type being catched.
If you want to catch sth. auto-ish you won't have a strong
type-match. So this doesn't work.
Bo Persson <bo@bo-persson.se>: Mar 08 07:21PM +0100


>> It only knows what's thrown at runtime. Not at compile time. It is
 
> It knows what is thrown at runtime.
> It knows what *could* be thrown at compile time.
 
But it doesn't. The called functions could be recompiled later, with new
exceptions added. Or a new version of a library could be installed.
 
How is the catch to know that?
 
 
> And if it knows what could be thrown and what catch statements are encompassing
> those throws then it could compile in suitable types for an auto in the catch.
 
Perhaps we need a templated catch that is instantiated at runtime? That
would be a novelty.
Muttley@dastardlyhq.com: Mar 08 09:21AM

On Wed, 8 Mar 2023 00:10:43 +0200
>rvalue whose final state would not be important anyway, or we use
>std::move() to explicitly declare we do not care about the final state
>of the object.
 
Thats fine, until its used in a library and someone doesn't look at the
code so don't realise the object they passed in is now invalid. Yes thats
a fairly unlikely scenario but something that needs to be considered when
using move. Will someone use your code who isn't aware of what you've done?
Paavo Helde <eesnimi@osa.pri.ee>: Mar 08 02:41PM +0200

> code so don't realise the object they passed in is now invalid. Yes thats
> a fairly unlikely scenario but something that needs to be considered when
> using move. Will someone use your code who isn't aware of what you've done?
 
Care to bring an example? I have hard time figuring out how one could
get a moved-away object via rvalue references inadvertently.
Muttley@dastardlyhq.com: Mar 08 04:26PM

On Wed, 8 Mar 2023 14:41:30 +0200
>> using move. Will someone use your code who isn't aware of what you've done?
 
>Care to bring an example? I have hard time figuring out how one could
>get a moved-away object via rvalue references inadvertently.
 
#include <iostream>
#include <string>
 
using namespace std;
 
void myfunc(string &s1)
{
string s2 = move(s1);
}
 
 
int main()
{
string s1 = "hello";
myfunc(s1);
cout << s1 << endl;
return 0;
}
"Alf P. Steinbach" <alf.p.steinbach@gmail.com>: Mar 08 06:08PM +0100

> cout << s1 << endl;
> return 0;
> }
 
Entirely safe code.
 
A move from any standard library object leaves the object in a
well-defined state.
 
The originally proposed rules didn't completely guarantee all desired
safety, but as I recall Scott Meyers posted in this very group about it,
and after some discussion reasonable compromise was reached. :)
 
 
- Alf
 
PS: You don't need the `return 0;`; that's the default for `main` in
both C and C++.
Paavo Helde <eesnimi@osa.pri.ee>: Mar 08 07:23PM +0200

> cout << s1 << endl;
> return 0;
> }
 
There is no rvalue reference in this example, only a non-const lvalue
reference which is known to be error-prone and tricky to use. Use rvalue
references instead:
 
#include <iostream>
#include <string>
 
using namespace std;
 
void myfunc(string &&s1)
{
string s2 = move(s1);
}
 
 
int main()
{
string s1 = "hello";
// myfunc(s1); // does not compile
myfunc(std::move(s1)); // ok, explicit move
cout << s1 << endl;
return 0;
}
Frederick Virchanza Gotham <cauldwell.thomas@gmail.com>: Mar 08 08:34AM -0800

I've been doing some major tinkering.
 
The entry point of an executable is '_start'. So, first I wrote a new entry point in x64 assembler that could differentiate between GUI mode and console mode depending upon the value of 'argc':
 
; This file contains x86_64 assembler for NASM, also known as x64.
; This file contains two functions:
; static void print8bytes(uint64_t eight_chars,uint64_t new_line);
; extern void pre_start(int argc);
 
section .text
 
print8bytes: ; This is a function that returns void
; Two parameters:
; r9: The 8-byte string to print
; r8: If true, prints a trailing new line
 
; save all the register values we're going to use
push rax
push rsi
push rdi
push rdx
 
;zero out the registers we are going to need
xor rax, rax
xor rsi, rsi
xor rdi, rdi
xor rdx, rdx
 
;write(int fd, char *msg, unsigned int len)
mov al, 1
add di, 1
mov rsi, r9
push rsi
mov rsi, rsp
mov dl, 8 ; Print 8 bytes at a time
syscall
pop rsi
 
cmp r8, 1 ; check if r8 is true or false
jl no_new_line
;zero out the registers we are going to need
xor rax, rax
xor rsi, rsi
xor rdi, rdi
xor rdx, rdx
;write(int fd, char *msg, unsigned int len)
mov al, 1
add di, 1
mov rsi, 0x000000000000000a ; new line
push rsi
mov rsi, rsp
mov dl, 1 ; Print just one byte
syscall
pop rsi
no_new_line: ; just a jump label - not a function name
pop rdx
pop rdi
pop rsi
pop rax
ret
 
global pre_start:function
pre_start:
; The 'argc' argument to 'main' is on the top of the stack so
; we will use the frame pointer 'rbp' to keep track of it.
push rbp
mov rbp, rsp
 
push r9 ; save because we'll use it - pop it back later
push r8 ; save because we'll use it - pop it back later
 
mov r8, 0 ; false = don't put trailing new line
mov r9, 0x3d3d3d3d3d3d3d3d ; "========"
call print8bytes
call print8bytes
call print8bytes
 
mov r9, 0x6174735f65727020 ; " pre_sta"
call print8bytes
 
cmp qword[rbp+8], 2 ; check if argc < 2
jl $+2+10+2 ; if argc < 2 then we want GUI mode
mov r9, 0x646d63202d207472 ; "rt - cmd"
jmp $+2+10 ; skip the next 10-byte instruction
mov r9, 0x495547202d207472 ; "rt - GUI"
call print8bytes
 
mov r9, 0x3d3d3d3d3d3d3d3d ; "========"
call print8bytes
call print8bytes
mov r8, 1 ; true = put trailing new line
call print8bytes
 
pop r9
pop r8
 
mov rsp, rbp
pop rbp
 
extern _start
jmp _start
 
 
If you see the last line there, I jump straight into _start. So then I build my program with a new entry point as follows:
 
g++ -o prog prog.cpp object_file_from_assembler.o -e pre_start
 
When I run it at the command line, the first thing I get is:
 
======================== pre_start - GUI========================
 
and then it continues execution as normal. No problems.
 
So then the next thing I did was I used 'patchelf' to remove the NEEDED for the graphical user interface library:
 
patchelf --remove-needed libgtk-3.so.0 ./prog
 
And then I tried to run it again, but this time around I got back:
 
./ssh: symbol lookup error: ./ssh: undefined symbol: gtk_true
 
This means that the program falls over ***before*** the entry point is reached.
 
So the part of the Linux operating system that loads executable files is not even going into the entry point for my program, it's falling over before then. I need to stop this happening some how. Perhaps I can put dummy values in the GOT table so that the loader doesn't think they're null?
"Alf P. Steinbach" <alf.p.steinbach@gmail.com>: Mar 08 06:17PM +0100

On 2023-03-08 5:34 PM, Frederick Virchanza Gotham wrote:
 
> [snip]
> So the part of the Linux operating system that loads executable files
> is not even going into the entry point for my program
So, you were not talking about Windows' console and GUI subsystems, but
about general application behavior.
 
Still the solution with two separate executables, perhaps with one
invoking the other, seems very much preferable to mucking about with
entry points and whatever, except if you're doing that for the joy of
hacking?
 
I believe in Linux the average user will have no problem relating to
separate executables.
 
---
 
In Windows you can check the executable's subsystem by inspecting the
bytes of the loaded image of the executable.
 
The start address of that image is available from `GetModuleHandle(0)`.
 
Happy hacking! :)
 
- Alf
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: