0

Say I have C++ project which has been working for years well. Say also this project might (need to verify) contain undefined behaviour. So maybe compiler was kind to us and doesn't make program misbehave even though there is UB. Now imagine I want to add some features to the project. e.g. add Crypto ++ library to it. But the actual code I add to it say from Crypto++ is legitimate. Here I read:

Your code, if part of a larger project, could conditionally call some 3rd party code (say, a shell extension that previews an image type in a file open dialog) that changes the state of some flags (floating point precision, locale, integer overflow flags, division by zero behavior, etc). Your code, which worked fine before, now exhibits completely different behavior.

But I can't gauge exactly what author means. Does he say even by adding say Crypto ++ library to my project, despite the code from Crypto++ I add is legitimate, my project can suddenly start working incorrectly?

Is this realistic? Any links which can confirm this?

It is hard for me to explain to people involved that just adding library might increase risks. Maybe someone can help me formulate how to explain this?

Community
  • 1
  • 1
  • 2
    Isn't that all explained in the link you posted? If you have UB in your code, it can break pretty much at any moment for pretty much any reason. – juanchopanza Nov 19 '15 at 07:38
  • Yes, it's realistic. – nvoigt Nov 19 '15 at 07:38
  • @nvoigt So that link says SIMPLY adding new library - even though stable, and even though the code I add from library is correct, my program can misbehave? Did I correctly understand?? Why would that happen? –  Nov 19 '15 at 07:40
  • Yes. That's UB. UB is bad. UB is a mistake. Don't rely on it in any way, not even if it worked the last 100 times. It might explode in your face the 101st time you do it. – nvoigt Nov 19 '15 at 07:42
  • 1
    Technically, adding a library could (and most likely will) change the memory layout of your running application. Dynamic memory might be allocated at different addresses than before, and code might be mapped to different locations than before. Lets assume you are writing out of bounds by 100 bytes - if you do that at the beginning of a memory page, nothing might happen, but if you do it at the end of a memory page you might get a segmentation fault. – Andreas Fester Nov 19 '15 at 07:42
  • @nvoigt Yes I understand but I have software which has been functioning correctly for say 10 years. Now I need to explain to people that JUST adding new library might make this code not working. Do you see my situation? So I am thinking how to explain this to people? Just sending the link I showed, that should be enough?? –  Nov 19 '15 at 07:42
  • @AndreasFester please see my comment to nvoigt –  Nov 19 '15 at 07:47
  • 2
    Just tell the people that the code had serious bugs that went undetected for many years due to bad development practices, but now the chickens have finally come home to roost. – juanchopanza Nov 19 '15 at 07:50
  • @juanchopanza really I am not in situation for joke :) Anyway I need to explain that despite their code works for 10 years correctly, JUST ADDING new library might introduce risks in case their existing code contains UB. Am I right? –  Nov 19 '15 at 07:52
  • 4
    I wasn't joking. It is the situation. You can dress it up with nicer words, but it is what it is. – juanchopanza Nov 19 '15 at 08:13
  • 2
    @user200312 If their code contains UB, they are at risk *right now* even *without* adding this new library. – nvoigt Nov 19 '15 at 08:17
  • @nvoigt Yes but when software works for 10 years correctly it is hard to convince them to fix something - plus by fixing you may introduce additional bugs. (also I didn't find UB in the project yet, I assume there might be because I found in other project of theirs). So I need to explain that using new library is risky am I right? –  Nov 19 '15 at 08:24
  • @juanchopanza maybe you can explain to me with nicer words ? (please see my above comment to nvoigt too) –  Nov 19 '15 at 08:44
  • Use [valgrind](http://valgrind.org/) and `-fsanitize=` option to recent [GCC](http://gcc.gnu.org/) – Basile Starynkevitch Nov 19 '15 at 09:14
  • It is all explained in the link you posted. – juanchopanza Nov 19 '15 at 09:29
  • @juanchopanza Just since English is not my first language maybe I could not understand it well –  Nov 19 '15 at 10:37

2 Answers2

1

When source code invokes undefined behaviour, it means that the standard gives no guarantee on what could happen. It can work perfectly in one compilation run, but simply compiling it again with a newer version of the compiler or of a library could make it break. Or changing the optimisation level on the compiler can have same effect.

A common example for that is reading one element past end of an array. Suppose you expect it to be null and by chance next memory location contains a 0 on normal conditions (say it is an error flag). It will work without problem. But suppose now that on another compilation run after changing something totally unrelated, the memory organization is slightly changed and next memory location after the array is no longer that flag (that kept a constant value) but a variable taking other values. You program will break and will be hard to debug, because if that variable is used as a pointer, you could overwrite memory on random places.

TL/DR: If one version works but you suspect UB in it, the only correct way is to consistently remove all possible UB from the code before any change. Alternatively, you can keep the working version untouched, but beware, you could have to change it later...

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • @user200312: All above comment and my answer say same thing: YES, as soon as UB is involved any change could make it break. – Serge Ballesta Nov 19 '15 at 09:20
  • @user200312: to paraphrase Jacques Coeur's motto: *for a brave heart nothing is impossible* (heart is coeur in french). But you should estimate the cost and time for it first... – Serge Ballesta Nov 19 '15 at 12:57
  • 1
    Any change (including a compiler update) can suddenly make evident long hidden problems; either your project remains fixed forever, or you have to deal with the problem. Crank up the compilation warnings; run debug builds; enable the debug STL; run under valgrind; compile with the address sanitizer. Replace fixed-size buffers with STL structures (more easily instrumentable and less error prone). This stuff seriously helped to solve lots of bugs in a big old project I work on, and yes adding new code, adding big libraries, changing timings and the like did expose hidden bugs too. – Matteo Italia Nov 19 '15 at 17:59
  • (also: building under a completely different compiler does help) – Matteo Italia Nov 19 '15 at 18:05
  • The other options are 1: pray for all goes as nicely as possible or 2: consistently review and test all the code. None of them are nice... – Serge Ballesta Nov 24 '15 at 12:51
0

Over the years, C has mutated into a weird hybrid of a low-level language and a high-level language, where code provides a low-level description of a way of performing a task, and modern compilers then try to convert that into a high-level description of what the task is and then implement efficient code to perform that task (possibly in a way very different from what was specified). In order to facilitate the translation from the low-level sequence of steps into the higher-level description of the operations being performed, the compiler needs to make certain assumptions about the conditions under which those low-level steps will be performed. If those assumptions do not hold, the compiler may generate code which malfunctions in very weird and bizarre ways.

Complicating the situation is the fact that there are many common programming constructs which might be legal if certain parts of the rules were a little better thought-out, but which as the rules are written would authorize compilers to do anything they want. Identifying all the places where code does things which arguably should be legal, and which have historically worked correctly 99.999% of the time, but might break for arbitrary reasons can be very difficult.

Thus, one may wish for the addition of a new library not to break anything, and most of the time one's wish might come true, but unfortunately it's very difficult to know whether any code may have lurking time bombs within it.

supercat
  • 77,689
  • 9
  • 166
  • 211
  • I assumed the library I include is stable –  Nov 26 '15 at 06:55
  • @user200312: My point was that it's possible that your code, which seams 100% stable, might fall afoul of one of some weird corner case in the Standard, and adding any significant quantity of new code to the system might change things so that what something which used to work ceases to do so. – supercat Nov 26 '15 at 19:41