Thursday, March 9, 2023

Digest for comp.lang.c++@googlegroups.com - 13 updates in 4 topics

David Brown <david.brown@hesbynett.no>: Mar 09 08:32PM +0100

On 09/03/2023 16:14, Malcolm McLean wrote:
 
> In which case you can say that signed integer arithmetic has undefined behaviour,
> because you catch the overflow before you do the calculation. Which is in fact
> the current situation.
 
No, signed integer arithmetic has /defined/ behaviour - it is only
/overflow/ that has undefined behaviour.
 
> One benefit of defining the behaviour is so that you can do
> it post mortem. The other benefit is that if overflow isn''t handled correctly, the bug
> is consistent.
 
Consistent bugs are not necessarily better (or rather, less bad) than
inconsistent bugs. It can be helpful if a bug gives a consistent
detectable issue that point to the cause - but equally a consistent bug
could consistently hide the issue and lead you to look elsewhere for the
problem. The idea that consistent incorrect behaviour is better than
undefined behaviour is no more than a myth.
 
> it may be more or less difficult to understand than doing the test after the increment.
> Defining the behaviour on overflow doesn't prevent you doing it your way, but it gives
> you another option.
 
It gives a /worse/ option that encourages bad programming habits. Do
not write code that is broken, and gets things wrong - no matter what
happens afterwards. (Note that this is very different from exceptions
in C++, where throwing an exception is part of the defined and
intentional behaviour of the code.)
 
But no, the snippet above is /not/ the way you want to handle things
normally. If you are checking for overflow like this, the chances are
that your code is badly designed in the first place. (There are always
exceptions and unusual cases.) You've got to ask yourself /why/ someone
might be trying to add a marble to a full jar in the first place, and
work backwards - somewhere in the earlier code there is likely to be
poorly designed code. Maybe there are too many marbles involved, or the
jar should be bigger, but something is probably wrong.
 
At the very least, the code should be :
 
if (marbles < jar_size) {
marbles++;
} else {
// The jar is full - maybe it is time to empty it
}
 
In real code, the jar would never be INT_MAX in size - thus post-mortem
checks for wrapping overflow cannot be used even if the language defined
integer arithmetic that way. Overflows are bugs - but not necessarily
in the bit of code they appear to be in.
Keith Thompson <Keith.S.Thompson+u@gmail.com>: Mar 09 12:12PM -0800

> a copy as an argument for an I/O function invokes unspecified behavior."
> Such situation made sense maybe at 1998 ... at 2023 can require that
> copying std::FILE is compiling error.
 
FILE is defined in the C standard library. The C standard says:
 
The address of the FILE object used to control a stream may be
significant; a copy of a FILE object need not serve in place of the
original.
 
which means that the behavior of passing a pointer to a copied FILE
object to a library function is implicitly undefined. (I'm not sure why
cppreference says the behavior is unspecified.)
 
C *can't* make copying a FILE object illegal. A C++ library
implementation could implement its own FILE type as a wrapper around the
C FILE type and prohibit copying it, but then passing a C++ FILE*
pointer to a C function that expects a C FILE* pointer would be awkward
at best. Maybe you could define implicit conversions (I'm not sure
whether that's even possible), but covering all the cases would be
difficult.
 
And I don't think it would even be worth the effort. FILE is treated as
an opaque type. That opacity isn't enforced, but I've never seen C or
C++ code that copies or even defines a FILE object. Real code just uses
FILE* pointers. It's a very minor corner case. If I wanted to provide
definitions for as much undefined behavior as possible, copying FILE
objects would be very low on my list.
 
>> defining it would require runtime checks.
 
> Ideally such run-time checks will cost something only at hardware level
> or when failing.
 
Ideally, sure.
 
> I would just add something for example "_Unsafe int" and
> "_Wrapping int" for those who want signed int to have undefined
> behavior or wrap around.
 
First you have to define what you mean by "failure". Do you want
evaluating INT_MAX+1 to abort the program? Throw an exception? Emit
nasal demons?
 
We're stuck with hardware with wraparound behavior for the foreseeable
future. Conceivably if C and C++ started requiring trapping on signed
overflow, hardware would gradually be updated to make that more
efficient, but we wouldn't see the effects for decades.
 
--
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 */
Michael S <already5chosen@yahoo.com>: Mar 09 12:42PM -0800

On Thursday, March 9, 2023 at 2:09:04 AM UTC+2, David Brown wrote:
 
> I think that still counts as "not likely to be useful". Yes, two's
> complement wrapping on overflow is /occasionally/ useful, but only very
> occasionally.
 
 
And CIC filters are just one example of very common pattern
where even number of integer overflows compensate each other,
producing correct final result. What is special in the case of CIC is that
the number of overflows can be quite large. In more common case there
are exactly two overflows compensating each other, most typically in
expression like y1 = y0 + x1 - x0.
 
> And for many DSP algorithms, saturation would be much
> more helpful than wrapping.
 
I did quite a lot of fix-point digital signal processing in the past.
In my personal experience saturated arithmeticis pretty much never useful.
What is useful, occasionally, is saturating conversion of wider signed type
into narrower signed type.
 
> for any "x") than defined behaviours.
 
> If there had to be one single defined behaviour, then saturation is the
> only reasonable one.
 
Absolutely not!
Saturation is non-associative, that's enough to take it out of consideration
for default behavior.
 
> same number of marbles in the jar (and more on the floor). It would be
> mind-bogglingly insane to suggest that adding one more marble to a full
> jar would give you a negative jarful of marbles.
 
Somehow, you don't consider almost the same case insane for unsigned integers.
Michael S <already5chosen@yahoo.com>: Mar 09 12:47PM -0800

On Thursday, March 9, 2023 at 2:52:42 PM UTC+2, David Brown wrote:
 
> > Or, perhaps more likely, nobody who had a Windows 95 system crash after
> > 49 days ever figured out why it had crashed.
 
> You are spoiling a good legend with realism! :-)
 
Your story was unrealistic to begin with.
 
Win95 was hardly used by anybody 5 years after its introduction, much less
so 10 years after introduction.
Win98, esp. Win98 SE, was simply better choice in almost any imaginable
situation.
Lynn McGuire <lynnmcguire5@gmail.com>: Mar 09 04:59PM -0600

On 3/9/2023 8:26 AM, Bonita Montero wrote:
 
>> Lynn
 
> Read this:
> https://mega.nz/file/ehcR1S5B#5YcRMdcJ0WArshD0szI2bckaqVmk2jC59XmOZh_GXgM
 
No freaking way. Looks like a ransomware file to me.
 
Lynn
olcott <polcott2@gmail.com>: Mar 09 02:31PM -0600

On 10/24/2022 1:19 PM, Mr Flibble wrote:
> 3) Decider rejects pathological input as invalid by signaling sNaP.
 
> https://github.com/i42output/halting-problem#readme
 
> /Flibble
 
I created the notion of a simulating halt decider in this forum
On 3/14/2017 at 9:05 AM
 
Message-ID: <e18ff0a9-7f9d-4799-9d13-55d021afaa82@googlegroups.com>
 
--
Copyright 2023 Olcott "Talent hits a target no one else can hit; Genius
hits a target no one else can see." Arthur Schopenhauer
Jivanmukta <jivanmukta@poczta.onet.pl>: Mar 09 06:41PM +0100

W dniu 9.03.2023 o 18:35, Jivanmukta pisze:
> Could it be hardware problem, not with my application?
 
Probably not, because I can run my C++ program with different arguments.
Jivanmukta <jivanmukta@poczta.onet.pl>: Mar 09 07:03PM +0100

W dniu 9.03.2023 o 18:12, Jivanmukta pisze:
> undepending where I have set a breakpoint.
> I also have SIGSEGV after TRACE when I run my application from command
> prompt, not VSCode.
Question: how to TRACE values: identifiers[what].end(), ids.begin(),
ids.end()? I failed to cast them to unsigned long.
scott@slp53.sl.home (Scott Lurndal): Mar 09 06:05PM

>undepending where I have set a breakpoint.
>I also have SIGSEGV after TRACE when I run my application from command
>prompt, not VSCode.
 
Well, there's your problem. VScode is a POS.
 
From the command line, prefix your application execution command
with the string 'gdb -q --args '.
 
When the sigsegv occurs, type
'bt'
 
which will produce a stack traceback.
 
'info registers'
 
will show the current register state at the time of the SIGSEGV
 
'x/i $pc'
 
will show the machine instruction that caused the SIGSEGV.
 
Look at the instruction to determine which register contains
the address, then check the 'info registers' output to see
what the address value is that caused the fault.
scott@slp53.sl.home (Scott Lurndal): Mar 09 06:05PM

>> I also have SIGSEGV after TRACE when I run my application from command
>> prompt, not VSCode.
 
>Could it be hardware problem, not with my application?
 
No.
Jivanmukta <jivanmukta@poczta.onet.pl>: Mar 09 08:33PM +0100

W dniu 9.03.2023 o 19:05, Scott Lurndal pisze:
 
> Look at the instruction to determine which register contains
> the address, then check the 'info registers' output to see
> what the address value is that caused the fault.
 
(gdb) bt
 
#0 0x000000000043d68e in
__gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char> >*,
std::__cxx1998::vector<std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char> >,
std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>,
std::allocator<char> > > > >::__normal_iterator (this=0x7fffffffc1b0,
__i=<error reading variable>) at
/usr/include/c++/9/bits/stl_iterator.h:804
#1 0x000000000043a2aa in
std::__cxx1998::vector<std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char> >,
std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>,
std::allocator<char> > > >::end (this=0x50) at
/usr/include/c++/9/bits/stl_vector.h:827
#2 0x0000000000436c09 in
std::__debug::vector<std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char> >,
std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>,
std::allocator<char> > > >::end (this=0x38) at
/usr/include/c++/9/debug/vector:306
#3 0x00000000004488c3 in load_cache
(cache_filename="dirtyphp_cache_frameworks.xml",
parent_node_name=0x52f916 "frameworks", nodes_name=0x52f90c "framework",
dir=L"/home/robert/Projekty/laravel-lodash/vendor/laravel",
result_dir=L"/", options="", delim="~#@%_", cached=@0x7fffffffdd00:
true, identifiers=0x0, strings=0x0) at src/cache.cpp:97
#4 0x000000000044982e in cache::load_framework_cache
(this=0x7fffffffdd00,
framework_dir=L"/home/robert/Projekty/laravel-lodash/vendor/laravel",
delim="~#@%_", framework_identifiers=0x0)
at src/cache.cpp:133
#5 0x000000000044a0c3 in cache::load_vendor_cache (this=0x7fffffffdd00,
vendor_dir=L"/home/robert/Projekty/laravel-lodash/vendor",
delim="~#@%_", dir_separator=L"/",
framework_identifiers=std::__debug::unordered_map with 2 elements =
{...}, third_party_identifiers=std::__debug::unordered_map with 48
elements = {...}) at src/cache.cpp:189
#6 0x000000000046c361 in obfuscator::get_cmdline_options
(this=0x7fffffffd550, argc=8, argv=0x7fffffffdee8) at src/obfuscator.cpp:754
#7 0x00000000004240ba in main (argc=8, argv=0x7fffffffdee8) at
src/dirtyphp.cpp:148
 
(gdb) info registers
rax 0x58 88
rbx 0x38 56
rcx 0x7fffffffc390 140737488339856
rdx 0x58 88
rsi 0x58 88
rdi 0x7fffffffc1b0 140737488339376
rbp 0x7fffffffc190 0x7fffffffc190
rsp 0x7fffffffc190 0x7fffffffc190
r8 0x0 0
r9 0x7fffffffc0f0 140737488339184
r10 0x1 1
r11 0x246 582
r12 0x1 1
r13 0x0 0
r14 0x0 0
r15 0x0 0
rip 0x43d68e 0x43d68e
<__gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char> >*,
std::__cxx1998::vector<std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char> >,
std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>,
std::allocator<char> > > >
>::__normal_iterator(std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char> >* const&)+20>
eflags 0x10246 [ PF ZF IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
 
(gdb) x/i $pc
=> 0x43d68e
<__gnu_cxx::__normal_iterator<std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char> >*,
std::__cxx1998::vector<std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char> >,
std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>,
std::allocator<char> > > >
>::__normal_iterator(std::__cxx11::basic_string<char,
std::char_traits<char>, std::allocator<char> >* const&)+20>: mov
(%rax),%rdx
scott@slp53.sl.home (Scott Lurndal): Mar 09 07:55PM

> >::__normal_iterator(std::__cxx11::basic_string<char,
>std::char_traits<char>, std::allocator<char> >* const&)+20>: mov
>(%rax),%rdx
 
So, RAX is the register that contains the address from which
the data is being loaded. A virtual address less than 0x1000 is
generally invalid on most operating systems in order to fault on
NULL pointer dereferences.
 
It likely means that your objects were not correctly initialized
or have been overwritten inadvertantly by other code in your application.
 
Next thing to try is to insert the following instead of 'gdb -q --args '
in front of your command on the command line.
 
valgrind --leak-check=full --show-leak-kinds=all -v --log-file=/tmp/vg%p.log
 
Then look at the generated log file to identify where things started to go wrong.
Daniel <danielaparker@gmail.com>: Mar 09 11:38AM -0800


> catch(auto &[str,val])
> {
> }
 
Others have answered the question about your catch statement. I would also
note that throwing a pair<string,int> isn't best practice, because a std:string
can throw during copying. We don't want to throw in an
exception copy constructor, lest we throw the wrong exception type.
 
You may want to consider inheriting from std::runtime_error, and store
the string part of your error message in it. std::runtime_error is guaranteed
not to throw exceptions during copying, typically it stores the string internally
as a separately-allocated reference-counted string.
 
Daniel
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: