-Поиск по дневнику

Поиск сообщений в rss_thedaily_wtf

 -Подписка по e-mail

 

 -Постоянные читатели

 -Статистика

Статистика LiveInternet.ru: показано количество хитов и посетителей
Создан: 06.04.2008
Записей:
Комментариев:
Написано: 0

The Daily WTF





Curious Perversions in Information Technology


Добавить любой RSS - источник (включая журнал LiveJournal) в свою ленту друзей вы можете на странице синдикации.

Исходная информация - http://thedailywtf.com/.
Данный дневник сформирован из открытого RSS-источника по адресу http://syndication.thedailywtf.com/thedailywtf, и дополняется в соответствии с дополнением данного источника. Он может не соответствовать содержимому оригинальной страницы. Трансляция создана автоматически по запросу читателей этой RSS ленты.
По всем вопросам о работе данного сервиса обращаться со страницы контактной информации.

[Обновить трансляцию]

CodeSOD: The DOM Checker

Среда, 01 Февраля 2023 г. 09:30 + в цитатник

Dave does a little work on a website when the core developers are in over their heads on maintenance. Which is a thing that happens a lot.

Let's see if we can get a sense of why, starting with this little method here:

function check(cssclass, csschange)
{
	if($(cssclass).length)
	{
		console.log(cssclass + " does exist ");
		csschange();
	}
	else
	{
		console.log(cssclass + " does not exist, waiting...");
		setTimeout(function()
		{
			check(cssclass, csschange);
		}, 250);
	}
}

The check function accepts a query selector (it's called cssclass but any DOM query selector would work here), and csschange, which is a callback function. If that selector finds one or more elements, we log that it exists and invoke the callback. If it doesn't, we set a timeout and check again, four times a second.

Presumably, the purpose of this is to fire an event after a certain set of DOM elements are available on the page. All of that seems like a bad idea, but maybe there was a really good reason why this needed to get bolted in.

Let's check how it's used:

check("input.gsc-search-button",changeSearchButton);
check(".siteSearchButton",changeNewSearchButton);  
check("input.siteSearchButton[value='Search']",changeInputValue);    

Well, let's take a look at those callbacks.

function changeSearchButton()
{
	$("input.gsc-search-button").addClass("siteSearchButton");
	$("input.gsc-search-button").removeClass("gsc-search-button");
}

Okay, so we find the thing with the class gsc-search-button, then twiddle its classes. It's not clear why we need to do that, or what they hope to accomplish, but sure.

function changeNewSearchButton()
{
	$(".siteSearchButton").css({"background": "url(/euf/assets/images/go.png) no-repeat  scroll 0 0 rgba(0, 0, 0, 0)", "width": "35px", "height": "26px", "margin-top": "3px", "margin-bottom": "-5px", "border": "none"});
}    

Ah, once there's an element with the class siteSearchButton, we apply a bunch of styling to it. If only there were some other way to attach stylesheet rules to CSS classes. If only.

function changeInputValue()
{
	$("input.siteSearchButton").val("");
}

And this one goes and finds the input which used to have the value of "Search" and clears out its value.

At the end of the day, this creates a bunch of asynchronous operations where they probably don't need to be. Theoretically, your client side code should know when the DOM gets updated. If you need to execute code after DOM changes, just do that. The poll for an element in the DOM every 250ms is a bad, bad, bad choice.

But it's actually worse than that. Let's take a look at this line again:

check("input.gsc-search-button",changeSearchButton);

The thing you don't see in this code block is that the CSS class gsc-search-button doesn't exist and is never used in the DOM. gsc-search-button-V2 is, but this class is never used. So this selector never finds an element. Which means it polls endlessly for an element that's never going to exist. The callback here changes the class to siteSearchButton, which guess what- also isn't used in the DOM. So the other two calls to check also never find the element they're looking for.

The people who wrote this code must be big U2 fans, because they still haven't found what they're looking for.

[Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.

https://thedailywtf.com/articles/the-dom-checker


Метки:  

CodeSOD: How To Ruin a Long Weekend

Вторник, 31 Января 2023 г. 09:30 + в цитатник

GRH inherited an application written by someone who is no longer employed with the company, as part of a project managed by someone who is no longer at the company, requested by an executive who is also no longer at the company. There are no documented requirements, very few tests, and a lot of "don't touch this, it works".

Well, it worked until it didn't. On a Friday before a long weekend, the application broke. As you might expect, it has a relatively small user pool, but is absolutely vital to the company's operations- if it fails, widgets don't get shipped and invoices don't get paid. So GRH got to spend that long weekend fixing the application.

In this case, the application is a Microsoft ClickOnce deployment (essentially "install without showing the user an installer") distributed through a shared network drive.

The specific section that broke was some code responsible for converting a PDF file into plain text.

    ' GRH 2021-08-25 This is bad.  Probably need to revise this, depending on new deployment strategy.
    ' GRH 2022-01-19 Yep, bit us on the *** in Friday's deployment.
    Public strConverterPath As String = System.IO.Path.GetFullPath(My.Resources.ResourceManager.BaseName).Replace("bin\Debug\net6.0-windows", "").Replace("REDACTED.", "")

    Public Function myPDFtoTXT(ByVal strInFN As String, ByVal strOpt As String, Optional ByVal encoding As String = "") As String
        Dim strComm As String
        Dim started As Boolean

        myPDFtoTXT = strInFN.Replace(".pdf", ".txt")

        strComm = "/c """"" & strConverterPath & "\pdftotext""" & strOpt & """" & strInFN & """"""
        If encoding <> "" Then
            strComm = strComm & " -enc " & encoding
        End If

        started = myCMDprc(strComm)
        If Not started Then
            ErrMessage("conversion failed to start")
            endStatus = runStatus.parse_fail
        End If

        If Not System.IO.File.Exists(myPDFtoTXT) Then
            ErrMessage("Converstion from pdf to text failed.")
        End If
    End Function

Thanks to the comments, it's easy to see where things went wrong. The code does some string mangling on the path, expecting to remove bin\Debug\net6.0-windows and some other substring from the string. Which betrays a lot of faith in the consistency of those path names- in this case, simply building in Release mode, instead of Debug would break the application. It's also important to note that this is using the resource manager- an object whose job it is to load resource files for localization, not intended to return paths for where the application is installed (according to the docs, it doesn't even return a path, but instead the namespace of the resource file). This is emphatically the wrong tool for the job.

Based on the comments, something about the assumed paths returned by the method that isn't meant to look up paths broke. And that's the core WTF, but there's so many more things I can complain about here.

Instead of using one of the many libraries available for this task, they instead shell out to a command line tool for it. Not the worst choice, but also not my favorite thing to see. I have no idea how the implementation of myCMDprc is done, but it clearly swallows the return codes from the program being executed- instead of checking if the program exited successfully, we instead check to see if a TXT file exists, and assume that's success. Which again, puts a lot of faith in that external tool that creating the file means it succeeded, because I can imagine a lot of scenarios where it starts flushing the buffers but also doesn't successfully generate correct output.

Finally, this also uses a perfectly valid VB.Net idiom, but also one I hate- it treats the function name itself as a variable. myPDFtoTXT is assigned a value, which will be the return value of the function. Later on, for checking that the output file exists, it uses the function's return value as a variable. This isn't technically wrong, I just hate it.

And I lied about that being the last WTF- it's the last WTF the programmer put there, but the final WTF is just VB's approach to escaping the " character in strings- three double quote characters in a row is a single double quote character in the output: `""""Hello world,""" they said."

[Advertisement] Continuously monitor your servers for configuration changes, and report when there's configuration drift. Get started with Otter today!

https://thedailywtf.com/articles/how-to-ruin-a-long-weekend


Метки:  

CodeSOD: Height of the Accordion

Понедельник, 30 Января 2023 г. 09:30 + в цитатник

In the bad old days of web development, you had to deal with the fact that there weren't really any standards, and you had to customize your code for different browsers. The "right" way was to sniff for which features were available, but the most commonly used way was to check the user-agent string and guess based on the browser name. Because of this, browsers started to keyword spam their user-agent, to pass these checks, which is why my browser reports as Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36. My browser of choice is a Chrome fork, and I'm running on an M1 Mac, so basically none of those things are true.

But let's look back at some code Lucas found, still lingering in a web app he maintains.

if (navigator.appName == 'Microsoft Internet Explorer')
{
        $("##accordion").accordion({
                        autoHeight: false
                });
}
else
{
        $("##accordion").accordion({
                        autoHeight: false
                });
}

Maybe once, this was useful, but clearly the last time anyone touched it, it became vestigial. This is a "just in case" branch: it remains just in case you need to change the behavior for non IE browsers, and forget how to reconstruct the branch when you actually need it. Maybe someday it'll need to be changed, we don't know.

We do know: it should be changed, and the whole thing made to go away. With a bonus of the recognition that this is calling into JQuery UI components, components you use specifically because the JQuery UI developers are doing the hard work of managing browser compatibility for you. Now, I can't guarantee that there was never a need to hack in some of your own cross-browser compatibility, but at this point, it looks like clearly not.

[Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!

https://thedailywtf.com/articles/height-of-the-accordion


Метки:  

Error'd: Or Else

Пятница, 27 Января 2023 г. 09:30 + в цитатник

This week I read an article which asserted that the AI singularity is still several years away. Maybe they should wait until then before they start threatening us?

The first of the last of the humans, Greg took the time to wonder about the meaning of this warning. Or is it a threat? "One of our in-house web applications implements an automatic logout, but also lets you get a warning when you have a few minutes left before it does this. Their warning leaves me a bit puzzled, though, since it seems to imply that it's a manual session timeout, and perhaps if I don't close the session in 5 minutes, I'll stay logged in? Or will the world just end?" Run, Greg. Run.

orelse

 

Literate Totty invokes Heller, calling this a Google-22. "I'm sure Captain Yosarian would sympathize with my attempt to quit Google AdSense" I'd be crazy to disagree.

adsense

 

Speedy Stewart snickered "Apparently Waze thought we were driving at over 400mph down the English M1 motorway (highway). If only. Would have stopped us being late."

speed

 

Anterogradian Andreas averred "My DSL line will be up in two weeks. Can't wait!" Or else it has been down for the last two weeks.

uptime

 

Finally this week, a testy testee attested anonymously "Pressing either the ' Test ' or 'Test' buttons does nothing. Does this mean I failed?" I'm afraid you're going to need to repeat the survey.

test

 

[Advertisement] Keep the plebs out of prod. Restrict NuGet feed privileges with ProGet. Learn more.

https://thedailywtf.com/articles/or-else


Метки:  

CodeSOD: Literal Type Checking

Четверг, 26 Января 2023 г. 09:30 + в цитатник

Validating your inputs is important, even when the sender is an API- in the land of JSON-based data exchange, we can't guarantee which keys exist without checking.

Philipp's team uses the "Runtypes" library to solve this problem. It lets them write code like this:

r.Array(r.Record({ id: r.Number, name: r.String })).check(inputData)

This verifies that inputData is an array of objects with id fields (containing numbers), and a name field (containing strings).

For more complex validation, Runtypes lets you use add constraint functions to your types. So, for example, if you wanted to ensure a number is in the range of 0-52, you could do:

const YearIndexes = r.Number.withConstraint((n) => n >= 0 && n <= 52);

You could do that. But Phillip's co-worker wanted to find a more declarative approach that doesn't have any of those pesky function calls in it.

const YearIndexes = Union(
  Literal('0'),
  Literal('1'),
  Literal('2'),
  Literal('3'),
  Literal('4'),
  Literal('5'),
  Literal('6'),
  Literal('7'),
  Literal('8'),
  Literal('9'),
  Literal('10'),
  Literal('11'),
  Literal('12'),
  Literal('13'),
  Literal('14'),
  Literal('15'),
  Literal('16'),
  Literal('17'),
  Literal('18'),
  Literal('19'),
  Literal('20'),
  Literal('21'),
  Literal('22'),
  Literal('23'),
  Literal('24'),
  Literal('25'),
  Literal('26'),
  Literal('27'),
  Literal('28'),
  Literal('29'),
  Literal('30'),
  Literal('31'),
  Literal('32'),
  Literal('33'),
  Literal('34'),
  Literal('35'),
  Literal('36'),
  Literal('37'),
  Literal('38'),
  Literal('39'),
  Literal('40'),
  Literal('41'),
  Literal('42'),
  Literal('43'),
  Literal('44'),
  Literal('45'),
  Literal('46'),
  Literal('47'),
  Literal('48'),
  Literal('49'),
  Literal('50'),
  Literal('51'),
  Literal('52'),
  // this is the maximal amount of years prospect can be insured for in the range 18-70 years.
);
[Advertisement] Keep the plebs out of prod. Restrict NuGet feed privileges with ProGet. Learn more.

https://thedailywtf.com/articles/literal-type-checking


Метки:  

CodeSOD: Magic Math

Среда, 25 Января 2023 г. 09:30 + в цитатник

LK was browsing a local job site for a new position. The site was flaky, which lead LK to look into the code, and it looks like if anything, this job site should be hiring a new web developer.

function startSWBanner()
{
   browserType = "new";

   timenow = new Date();
   secs = timenow.getTime () / 1000;
   modnum = 2 * 10;
   range = secs % modnum;
   n = Math.floor(range / 10);
   urlArray = new Array(2);
   banArray = new Array(2);
   altArray = new Array(2);
   popupArray = new Array(2);
   urlArray[0] = '/cgi-bin/banner_track.cgi?banner_id=2627';
   banArray[0] = '/rot_ban/v2lbanner.gif';
   urlArray[1] = '/cgi-bin/banner_track.cgi?banner_id=4245';
   banArray[1] = '/rot_ban/ir35_banner.gif';

   if (browserType == "new")
   {
        document.swbanner.src = banArray[n];

      startThread = setTimeout("rotateSWBanner()", 10000);
   }
}

For starters, we have a nice big pile of global variables. We do a bunch of odd datetime operations, to populate the variable n. We have to give a special shoutout to modnum, which is set to 20, but um, as 2 * 10, because… we don't want to use any magic numbers, I guess?

n, by the time we're done, is the number of seconds, mod 20, divided by 10.

Speaking of unused values, altArray and popupArray are also never used in the code.

After all that, if browserType == "new" (which it definitely does, since we set it equal to "new" up above), we start a timeout to rotateSWBanner().

function rotateSWBanner()
{
   if (browserType == "new")
   {
      if (n < (2 - 1))
      {
         n++;
      }
      else
      {
         n = 0;
      }

      imageSource = banArray[n];
      thread = setTimeout("rotateSWBanner()", 10000);
      window.document.swbanner.src = imageSource;
   }
}

Once again, we play with n, and implement the most awkward modulus operation. Once again, we're doing arithmetic instead of using magic numbers, because magic math is clearly a better option? But the core of the if is to make sure n rotates through the entire range of items in banArray, which again, we could just do a mod to accomplish that.

In any case, "magic numbers" are now supplanted by "magic math" as the new anti-pattern you should absolutely never use.

[Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!

https://thedailywtf.com/articles/magic-math


Метки:  

CodeSOD: Multiline Properties

Вторник, 24 Января 2023 г. 09:30 + в цитатник

If you want to configure a Java application, the standard way to do it is to use the Java Properties class. This class wraps around a simple, text-based file format (or an XML file, if you're into that) that allows you to store key/value pairs. It helpfully inherits from the HashMap class, letting you interact with those key/value pairs using a well understood API. The file format handles all the details of encoding and managing things like multiline strings.

So you could just do that. Or, you could do what this senior dev with over a decade of experience did.

// We start with a String called reason containing text like:
// "It seemed like a good idea\\nIt was cheaper\\nI didn't expect to get caught"
String[] reasons = reason.split("\\\\n");
StringBuilder builder = new StringBuilder();
for (int i = 0; i < reasons.length; i++) {
  if (i == reasons.length - 1) {
    builder.append(reasons[i]);
  } else {
    builder.append(reasons[i] );
    builder.append(System.lineSeparator());
  }
}

// And now the reasons are on separate lines.
String formattedReason = builder.toString();

This code handles multiline strings. The config file this developer invented simply stores its values on a single line, so to imitate multiline strings, it stores them with \\n in the file (as opposed to \n to represent a newline). So this code splits on \\n (which, of course, needs to be escaped, to \\\\n), and then iterates across that split, joining the lines with a System.lineSeparator().

The only good idea in this entire block is the use of System.lineSeparator(), and I'm honestly shocked that they used the platform independent value, and not a hard-coded \n.

I suppose the comment does justify and explain the code: It seemed like a good idea, it was cheaper, and they didn't expect to get caught.

[Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.

https://thedailywtf.com/articles/multiline-properties


Метки:  

CodeSOD: The 13 Month Bughunt

Понедельник, 23 Января 2023 г. 09:30 + в цитатник

Code reviews are an important part of development processes, but sometimes, some developers manage to sneak around the process. That was the case with Orien's team, where most of the team were constantly checking in with each other, doing peer reviews, and trying to collaborate on a rather gigantic Perl codebase. One team member, on the other hand… didn't. Management wasn't interested in pushing the issue, so this developer got to do their own thing.

And then the developer left. Over the next thirteen months, bug after bug started cropping up. Minor changes that should have been easy would unleash a ball of spaghettified nonsense that was impossible to debug but also emphatically didn't work. Things got so bad that the entire team needed to stop doing any new development for three months, and just fix bugs and refactor.

In those three months, they mostly fixed things up. Mostly. There are still moments where someone is trawling through the code and finds something that just leaves them scratching their heads.

This is one of those finds:

if ($#errors == -1) { 
  $group_name = $group_name; 
  $group_name = "$group_name"; 
}

This code first checks the last index of the errors array- if it's empty, we want to update the $group_name variable… by setting it equal to itself, then setting it equal to a string of it's value. And yes, that does do string interpolation, so the actual result is that $group_name is converted into a string. Given that the variable is named group name, I suspect it contained a string in the first place, which means this code effectively does nothing useful.

The only thing worse would be if $group_name didn't contain a string.

The good news is that the 13 months of disaster got the entire team, including management, on board with strict code reviews, coding style guides, and pair programming.

[Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.

https://thedailywtf.com/articles/the-13-month-bughunt


Метки:  

Error'd: Pure Poetry

Пятница, 20 Января 2023 г. 09:30 + в цитатник

Abandoning alliteration, the column this week is experimenting with consonance. Next week, perhaps we'll see how everyone feels about assonance.

Job-hunter Despreately Looking for Internship shared this job posting, writing "AMD Job Lsiting forgot to add in the deatils". Seems like a pretty easy job to perform; Mx. Des should apply.

job

 

Rosti fan Stefan Pletosu (and who isn't?) uncovers a subtler substitution error that Mx. Despreately missed. "Why would they call me a lead? I'm just a junior" he humbly demurs.

eamil

 

Dislocated Lincoln figures "Someone needs to go back to school and study maths."

half

 

Nanoscale philanthropist Adam R. references my favorite derived unit in this headscratcher. "I made a $50 donation plus fees, and in fact that's what my credit card was charged, but my PayPal activity statement seems to think I only made a 5 millicent donation."

paypal

 

Time Lord Daniel D. conjured up this Slovakian incantation, explaining: "Large office supply chain says this product will be delivered between September 9, 2021 and February 8, 2023. I choose the 2021 and hope it will just materialize in front of me on pressing the Confirm order button."

yesterday

 

[Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.

https://thedailywtf.com/articles/pure-poetry


Метки:  

CodeSOD: Advanced Programming Resources

Четверг, 19 Января 2023 г. 09:30 + в цитатник

Denilson was doing some appliance shopping, and upon submitting a form, it errored out. Denilson was sure the form was correct, and did what any of us would do: pop open the developer console and check the code.

The console dumped out a huge number of errors. And to no one's shock, the code had all sorts of home-made validation methods, like validateNumber. And, much to my surprise, they found new ways to make the simple task of validating a number horrible.

function validateNumber(value) 
{
      var digit, tam, dif;
  
   for (i=0;ilength;i++)
  {
          digit = value.substring(i,i+1);
           /* Advanced Programming Resources -> Must be improved... */
         if(digit != 0)
         if(digit != 1)
         if(digit != 2)
         if(digit != 3)
         if(digit != 4)
         if(digit != 5)
         if(digit != 6)
         if(digit != 7)
         if(digit != 8)
         if(digit != 9)
         if(digit != ".")
               if(digit != "-")
             {
                     return 2;
               }
       }
       if(value == "")
             return 1;
}

At it's core, this is a pretty basic "verify the string doesn't contain non-numeric characters for our locale", one character at a time. But there are a few special twists on this one, like the pile of nested if's used to accomplish this. Then, of course, there's the cryptic return codes: 1 if the string is empty, 2 if it contains invalid characters, and… no value at all if it's a "valid" number?

But, of course, the real star of this block in the unusually honest comment: this code "must be improved", presumably by "advanced programming resources". It's an unusual cry for help, but it is clearly a cry for help.

[Advertisement] Continuously monitor your servers for configuration changes, and report when there's configuration drift. Get started with Otter today!

https://thedailywtf.com/articles/advanced-programming-resources


Метки:  

CodeSOD: Rounding Percentages

Среда, 18 Января 2023 г. 09:30 + в цитатник

Метки:  

CodeSOD: The Email Process

Вторник, 17 Января 2023 г. 09:30 + в цитатник

Today's submission comes from Florian, and it starts with "this app processes important business transaction by email", which is always a good way to start a WTF. I've seen a depressing number of applications in my life that use email as a means of data exchange. It's common enough that even the industry standard EDI protocol supports email as one of its transports, but hoo boy is that a terrible abuse of email systems.

Let's start in HtmlResponseParser.cs, which reads in HTML and "parses" it for certain structures so it can extract data.

   public static Response createFromAscii(string r)
        {
            string regEx = "^"
                + RegExpMgr.getRegularExpression("requestRefNum")
                + RegExpMgr.getRegularExpression("spaceTabSeparator")
                + RegExpMgr.getRegularExpression("bbTickerAndName")
              // snip: 10 more lines
                + ").*?";

            Match m = Regex.Match(r, regEx);

            if(m.Success)
            {
                // Let caller handle exceptions
                bool status = true;
                int id = parseID(m.Groups[1].Value);
                int type = parseType(m.Groups[1].Value);
                string ticker = m.Groups[2].Value;
                double quantity = parseQuantity(m.Groups[3].Value);
                DateTime date = parseDate
                    (
                    m.Groups[5].Value,
                    m.Groups[6].Value,
                    m.Groups[7].Value
                    );

Oh yeah, you know we're parsing HTML with regexes. What could go wrong with that? What's extra great about this version is that the regexes are clearly splitting on characters contained within some of the data- note the way they have to reconstruct the date by reading out of the groups. And also note how they don't take advantage of named groups at all- so we always have to access the group by the position, instead of some meaningful name.

But that's not the WTF. Why don't we take a look at the implementation of the RegExpMgr class.

   public class RegExpMgr
   {
      public const string RegExprDefsFile = "RegExpDefs.xml";

       public static string getRegularExpression(string name)
      {
         XmlDocument doc   = new XmlDocument();
         doc.Load(RegExprDefsFile);
         XmlNode root = doc.DocumentElement;   
         XmlNode node = root.SelectSingleNode("descendant::regularExpression[@name='" + name + "']");
         if (node != null)
            return node.InnerText.Trim();
         else
            return null;
      }
   }

The bad news is that they store all the regexes they want to use in an XML file. The good news is that they don't use regexes for parsing that XML file. The other bad news is that there's no caching of the contents of the file- every time you want a regex, we open the file, construct the DOM tree, and then use a query selector to find the one entry we want. Extra bonus points for returning null when a key can't be found, because why would we want to capture that as an exception?

And yet, that's still not the WTF, because Florian also gave us a big picture view of the business process.

First, a database stored procedure fetches a list of fields that will get exchanged with external parties and some text-based guidelines for how they need to validate. An application runs and reads that data, and uses it to construct an HTML table. It then connects to an instance of the Outlook application- yes really- to send that email out to the external parties. Once the email goes out, still through the Outlook application, the app monitors a specific folder in the inbox. When the third parties reply, an Outlook rule filters their email into that folder, which triggers the next step of the app. The app loads the email, parses the HTML table contents (which were edited by the external parties) and attempts to parse them (via regexes) back into data. This step fails 75% of the time, since it relies on the sender to get the table structured very specifically. It also can't really tell the difference between the header rows (because they're just regular table cells formatted in bold- there's no th tag here).

So it loads all of the data in the table, probably, and dumps it into a database table. The structure it dumps it in, however, is just as a set of space-separated substrings. So "this string of text" becomes the table (this,string,of,text). As you can imagine, this "temporary" table has a lot of columns. The app then reads this data back out of the database into an array of arrays of strings. Then for each string, it tries to determine if that string is a valid row, or not. And the way it does this is, well, it has a regex that tells it what a valid row should look like, as text. So what it does is it joins all of those cells back together and checks if it passes the regex.

Once that's done, it tries to save that data back in the original database table, thus allowing the third party the ability to "update" the data, all via email.

Florian closes:

That's it, I am offically going to the pub, it's been a long day

[Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!

https://thedailywtf.com/articles/the-email-process


Метки:  

CodeSOD: No Percentage In It

Понедельник, 16 Января 2023 г. 09:30 + в цитатник

James was asked to investigate some legacy code for the sole purpose of figuring out how to replace it. There were all sorts of bad blocks in there, but this one caught James's eye as being notable.

And it is. This code has a simple job: given an old value and a new value, tell us the difference as a percentage of the old value. You or I might write this as a one-liner, but this clever developer is on an entirely different level:

private decimal GetPercentChange(decimal oldValue, decimal newValue)
{
    // Enforcing negative and positive to emphasize direction of percent change.
    if (newValue > oldValue)
        return Math.Abs((newValue - oldValue) / oldValue);
    else if (newValue < oldValue)
        return -1 * Math.Abs((oldValue - newValue) / oldValue);
    else return 0m;
}

James showed this to a co-worker, who responded: "You've heard of long division, but have you ever heard of long subtraction?"

"Enforcing negative and positive to emphasize direction of percent change", indeed. If only there were some way to subtract two numbers and get a negative result if the second operand was larger. Pity that's not how subtraction works.

Wait, no, that's exactly how subtraction works. James replaced this all with a single line: return (newValue - oldValue) / Math.Abs(oldValue).

[Advertisement] Continuously monitor your servers for configuration changes, and report when there's configuration drift. Get started with Otter today!

https://thedailywtf.com/articles/no-percentage-in-it


Метки:  

Error'd: Speedy Delivery

Пятница, 13 Января 2023 г. 09:30 + в цитатник

Boxing Day was weeks ago, but the packages are still coming.

Before Enterprise, Captain John Archer had a brief career in body-snatching. Here we see him possessing the person of a housewife, delivering a succinct eulogy for a parrot named Earl. A surprised David K. exclaims "I didn't see this plot twist coming!"

quantum

 

Everyone has their price, and for Clint, that price is 0%. "This is from an email enticing me to re-subscribe by offering me a discount."

fresh

 

An anonymous psychic blew this post from the past straight into our inbox: "Clairvoyance is real, and here's proof!"

see

 

"Distributed Computing is Hard," reminds Brett N. , joking that "USPS's new delivery vehicles are really really fast!" Somehow, this package arrived at Issaquah before it left Redmond.

distribute

 

Also thanks to the reliable USPS, we get this little chuckle to end the week. The Beast In Black [I know, but he says that's his name] acknowledges "This isn't really Error'd but it's still a WTF, albeit in a mostly-harmless way (I'm a tolerant man). Isn't it nice that the US Postal Service provides doorstep delivery for everything the wife orders, including...uh...this?" Just as long as it's not C.O.D., Mr. Black.

usps

 

[Advertisement] Keep the plebs out of prod. Restrict NuGet feed privileges with ProGet. Learn more.

https://thedailywtf.com/articles/speedy-delivery


Метки:  

CodeSOD: Else To

Четверг, 12 Января 2023 г. 09:30 + в цитатник

David inherited a codebase that's a few decades old. As each developer has taken it over, they've done their best to follow the code standards that the previous developers used, to at least keep the codebase consistent. A few rebels may have gone a different route, like the right one, but too many just followed the patterns that were already there.

This means that there are a lot of variables named things like a and aa and aaa. There are 4,000 line functions and loads of copy/pasted code.

In other words, all the usual markers of bad code are there. But the special feature that David inherited is that in the code, this is a common way to express an if/then/else:

if (someCondition)
{
	DoTheThings();
	goto skipIt;
}
DoTheElseThings();
skipIt:
//program continues

Not every conditional is written this way. There are a few developers who, as they modified the code, tried to whip it up into some sort of sane shape. But not enough did that. So these kinds of blocks are just scattered everywhere.

[Advertisement] Continuously monitor your servers for configuration changes, and report when there's configuration drift. Get started with Otter today!

https://thedailywtf.com/articles/else-to


Метки:  

CodeSOD: Catch By Yourself

Среда, 11 Января 2023 г. 09:30 + в цитатник

We've all seen the empty catch block, the "swallow errors and ignore them". David sends us a "superior" example of that anti-pattern, with several bonuses to make it even more of a WTF.

/**
 * Insert the method's description here.
 * @param bean java.lang.Object
 * @param bean_template java.lang.StringBuffer
 * @param bufXML java.lang.StringBuffer
 */
protected static void appendBeanTemplate(Object bean, StringBuffer bufXML) {

      int                                            iEndTag;
     StringBuffer  xmlTemplate = new StringBuffer();
        
 try {
               iEndTag = bufXML.toString().lastIndexOf("span> + getClassName(bean) + ">");
           writeChildBeanDescription(bean, xmlTemplate);
         bufXML.insert(iEndTag, xmlTemplate.toString());     
      }
      catch (Exception e) {
                try {
                      throw new Exception("Error creating xml bean description.");
               }
               catch (Exception ex) {
                }
        } 
}

Taking it from the top, we start with an incomplete JavaDoc comment. "Insert the method's description here". Then we accept a parameter called bufXML, but it's a StringBuffer, not an actual XML object, which sets us up for the ugly, hideous, "please don't" string mangling approach to interacting with the XML. The class name of the bean object is used to as a tag, we track the last index of that tag, and then insert some more stringly-generated XML into that position.

Everything about that is bad and terrible. Working with XML isn't nice, but using the actual XML classes in Java makes it easier and safer. I guess we can say, "at least it's not regexes".

But the real star of the show is the exception handling. We catch any exceptions this string mangling generates. Then we try… to throw a new exception. Which we catch, only to do nothing with. This code is like a lonely child on the playground, throwing a ball up in the air and catching it themselves because no one else will play with them.

It'd be sad, if it weren't so awful.

[Advertisement] Continuously monitor your servers for configuration changes, and report when there's configuration drift. Get started with Otter today!

https://thedailywtf.com/articles/catch-by-yourself


Метки:  

CodeSOD: String Formatting

Вторник, 10 Января 2023 г. 09:30 + в цитатник

There are certain things I can't remember for the life of me. For example, as per yesterday, the number of nanoseconds in a millisecond.

One of the other is the specific little formatting tokens for printf. I use it all the time, but the various riffs on %d escape my brain faster than I can put them in. Even just getting the hex values dumped for debugging requires a search. But I at least do that search, unlike Mike's co-worker.

#if defined COMPILER_GCC
    printf("configuration: " CONFIG_STRING "\n");
#elif defined COMPILER_XYZ
    /* XYZ doesn't seem to support concatenation like that */
    printf("configuration: ");
    printf( CONFIG_STRING );
    printf( "\n");
#endif

Now, an interesting quirk of C's translation process is that, at least in most compilers, adjacent string literals get concatenated into a single string. So the first branch here makes sense, though you have to be used to C idioms. That COMPILER_XYZ doesn't support it is odd and suspicious, but hardly shocking.

But the WTF, of course, is that printf already does what the developer wants in a way that the compilers don't care about. This whole block could be replaced with: printf("configuration: %s\n", CONFIG_STRING). It's what the f in printf stands for: format! It's the entire reason the function exists. Based on the comments, it seems like the developer wrote the GCC branch as the only branch, discovered a compiler error, and instead of spending the five seconds thinking about what printf does, they just sorta hacked around it. Arguably, the GCC version "formats" at compile time, so is probably faster, but we're looking at dumping configuration info for what I suspect is debugging/logging purposes- performance isn't a concern.

It's like watching this video in microcosm.

[Advertisement] Continuously monitor your servers for configuration changes, and report when there's configuration drift. Get started with Otter today!

https://thedailywtf.com/articles/string-formatting


Метки:  

CodeSOD: Yesterday and Today

Понедельник, 09 Января 2023 г. 09:30 + в цитатник

There's bad date handling, which frequently involves reinventing date handling yourself, frequently using strings or integers along the way. Then there's the bad date handling which uses the date handling framework, and still manages to be bad.

This C# comes from TheColonial.

public static void ToStartofCurrDay(ref DateTime dt)
{
      dt = dt.Subtract(dt.TimeOfDay);
}

Now, this isn't terrible. And certainly, if you go searching on the Internet for "how to round/truncate a datetime in C#" you're going to see answers that solve the arbitrary problem of rounding to any interval, and the code is complicated and ugly, like dates.

But that's only if you go searching. If you actually read the docs, the DateTime type has a Date property, which you guessed it- returns the date with the time set to midnight, the same exact thing that this code does.

I don't like it, but that's not the WTF. What we have here is a function that turns the current DateTime into a DateTime at midnight of the same day.

So what functions does this developer implement next?

public static void ToEndofPrevDay(ref DateTime dt)
{
  dt = dt.Subtract(dt.TimeOfDay);
        TimeSpan ts = new TimeSpan(1);
   dt = dt.Subtract(ts);
}

public static void ToEndofCurrDay(ref DateTime dt)
{
 dt = dt - dt.TimeOfDay;
   dt = dt.AddHours(23);
   dt = dt.AddMinutes(59);
 dt = dt.AddSeconds(59);
       dt = dt.AddMilliseconds(999);                               
}

So, right off the bat, we don't use the handy function we implemented, we just redo the same operation: dt.Subtract(dt.TimeOfDay). Then we create a TimeSpan and subtract that, which puts us at the latest possible time on the previous day- exactly one tick before midnight.

And yes, that's one tick, where each tick is 100ns. So, ToEndofPrevDay returns a datetime that is one tick before midnight of today.

Then we have ToEndofCurrDay, which uses the overloaded - operator instead of the Subtract function, which sure: consistency is the hobgoblin of tiny minds and programmers. Clearly they're not consistent with indentation, so why be consistent with style? Then they add 23 hours, 59 minutes, 59 seconds, and 999 milliseconds.

Which is to say, the end of the current day is one millisecond before midnight of the next day. The end of yesterday however, is 100 nanoseconds before midnight.

Now, does this gap actually matter? Almost certainly not. Hell, it might even help the sort order or something. But does this gap bother me? Oh you better believe it does. The end of yesterday and the end of today are not anchored against the same time- tomorrow, today will "end" a full 9,900 nanoseconds earlier than it did today. That sentence might not make a huge amount of sense, but that's what happens when you deal with date handling code.

[Advertisement] Otter - Provision your servers automatically without ever needing to log-in to a command prompt. Get started today!

https://thedailywtf.com/articles/yesterday-and-today


Метки:  

Error'd: Quel p'enible

Пятница, 06 Января 2023 г. 09:30 + в цитатник

I have been collecting submissions for a set of themed columns to appear later. This week we received several submissions that will fit nicely in those themes and have been placed into stasis pending $whenIfeellikeit. If you haven't seen your submission appear, be strong; it may show up eventually. What remains here are entries that don't fit the available themes. Enjoy.

Number-loving Rick was counting on better sense at the census. "I went to check out recent data, and ran into this site where the main statistic is only available with lexical sorting! I looked at the downloadable csv and json, and sure enough, even there it is quoted text."

pop

 

A myopic anonymous poster squints "I'm not the only one who needs glasses." A minor WTF, to be sure. But it is, at the very least, ironic.

2022

 

Gourmand Joel C. found a tasty coincidence, gushing "I was really looking forward to buying some of Milk Street's Liquid Error too." What is this product, really? Just sugar+cardamom, maybe a little cinnamon?

liquid

 

Regular reader Argle Bargle reminds us "I have a girlfriend in Thailand. From her phone she got a strange message. She sent it to me. I told her not to worry, but I was definitely sending it to the Daily WTF."

hbogo

 

Finally, Francophone Azerty11235 forwarded the following (featuring my translation) "It says that you don't need to fill in your name (for privacy reasons). And yet, as shown by that bright red error'd message, it won't work if you don't fill it in. If only this was the only thing not working as intended on the French Railroad Systems..."

wtf2

 

[Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!

https://thedailywtf.com/articles/quel-p-nible


Метки:  

CodeSOD: Exclusive Threads

Четверг, 05 Января 2023 г. 09:30 + в цитатник

When looking at code which juggles threads, there are definitely a few red flags. sleeps spammed through the code is an obvious one- either wait on a shared resource or block on another thread or something, but spurious sleeps are suspicious.

Until today, I would not have included "atomic operations" as a code smell in multi-threaded code, but we all learn new things.

This one comes from Mike J. We'll break this function up into two sections, because I've got a lot to say.

os_uint32 initCount;

/* in case multiple participants are created at the same time only 1 can start spliced */
initCount = pa_inc32_nv(&_ospl_SplicedInitCount);
if (initCount == 1) {
	result = startSplicedWithinProcess(&spliced_thread, domainCfg->uri);
	if (result == U_RESULT_OK) {
		/* wait for up to 10 seconds for the domain to be available in this process */
		while ((domain = u_userLookupDomain(domainCfg->id)) == NULL && (++sleepCounter < 100)) {
			ospl_os_sleep(delay_100ms);
		}
		if (domain) {
			domain->spliced_thread = spliced_thread;
		}
	}
	pa_dec32(&_ospl_SplicedInitCount);
//I'm skipping over a bit here so the flow of the code is clear- we'll come back to this in a moment
} else {
	pa_dec32(&_ospl_SplicedInitCount);
	/* wait for up to 30 seconds for the spliced to be available in this process */
	while ((domain = u_userLookupDomain(domainCfg->id)) == NULL && (++sleepCounter < 300)) {
		ospl_os_sleep(delay_100ms);
	}
}

This code starts a worker thread. In the middle, you can see one of those very fun suspicious sleep calls, where we poll a u_userLookupDomain which can take up to 10 seconds to interact with the thread we just started. That's almost certainly bad, or at least hinting at something bad.

But the start of this block is the special one. For some reason, this code doesn't use mutexes to avoid two threads from entering the block. Instead it increments an integer using an atomic operation. This works, but it's definitely not the correct way to do this.

Once we've got our thread spun up, we decrement that counter release the mutex. If there was another thread trying to access this block, it just falls through into decrementing and then doing another sleep, this time for up to 30 seconds.

Now, this is all ugly and makes me unhappy, but I skipped over a bit. So this is the block that goes in the elided section.

#if 1
{
    /* This piece of code is black magic, without it durability sometimes fail to become complete.
     * This code replaces historical code which was already in without a clear description.
     * Must be replaced to avoid unwanted delays and possible failures by a proper synchronisation.
     */
    int n;
    for (n=0; n<10; n++) {
        ospl_os_sleep(delay_100ms);
    }
}
#endif

The code is just a sleep, but the comment is perhaps the perfect comment for bad code. In three lines, we have so much story.

"This piece of code is black magic but major features break without it" is one of my favorite kinds of comments to see. You can see the #if guard- the developer who put this here didn't want it here, they wanted to be able to easily disable the code. But they couldn't. And it's easy to guess why: it's some sort of threading race condition or synchronization problem that we can avoid by just waiting long enough.

The second line of the comment is the one that really elevates things, though. This mysterious sleep that fixes a problem is just a replacement for an even more mysterious synchronization attempt that we didn't understand.

And then finally, we admit we know this code has to go away. We don't know how, we don't know when, we have no plan to do it- but we know it must be replaced. We even know what to replace it with- proper synchronization.

Now, there is good news: this code is in a product that is largely deceased. The code was donated to a FOSS foundation, and after a few releases, the foundation in question rightly junked the code and replaced it with code that does thread management properly. That's good news for us, anyway. Poor Mike is still stuck using it, for legacy reasons.

[Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.

https://thedailywtf.com/articles/exclusive-threads


Метки:  

CodeSOD: Customer Needs

Среда, 04 Января 2023 г. 09:30 + в цитатник

Code changes over time. As business requirements change, you need to update your code to reflect that, and the best way to do that is to structure your code and plan for changes before you even know what changes you need to make. Making your code flexible and changeable without making it meaninglessly abstract is the real art of software development.

Unless you're the document management provider that Daef works with. They have a very different approach for how they integrate new features and custom code paths.

if(CustomerID == 15531) {
    //That Customer pays for red cells - 
    // - he should get them
    cell.Backgroundcolor=Color.Red;
} else {
    cell.Backgroundcolor=Color.White;
}

This is just an example. The code base is littered with these sorts of branches, with hard-coded customer IDs creating custom features which apply for only one customer. For now, anyway, because eventually, another customer also wants the same features, and these branches get longer and more complicated, and they frequently gate extremely complex and important business logic. The result is a spaghettified mess.

And don't worry, this is just the most widely used document management software vendor in Daef's geography, so it's not like a lot of companies depend on this software for their daily operations.

[Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!

https://thedailywtf.com/articles/customer-needs


Метки:  

CodeSOD: Testing Your Date

Вторник, 03 Января 2023 г. 09:30 + в цитатник

"Don't unit test the library/framework code," is a good piece of advice. And yet, it's so often ignored.

Kaylee's co-worker certainly ignored it. They also ignored the basic principle of "ensure the test will work tomorrow."

[Test]
public void TestNewDate()
{
   String date = DateTime.Now.ToShortDateString();
   Assert.IsTrue(date == "26/08/2016");
}

Now, this test has been in the code base since 2016, as you might guess. It was not disabled or otherwise commented out. "But surely, their CI job would choke on it?" you might wonder. That assumes there is a CI job, and not a batch of tests that developers run manually, 70% of which pass and the remaining 30% have tickets in their ticketing software to get fixed "eventually".

[Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!

https://thedailywtf.com/articles/testing-your-date


Метки:  

CodeSOD: Attestation

Понедельник, 02 Января 2023 г. 09:30 + в цитатник

Good commit messages make a codebase a lot easier to understand. In fact, maybe writing good commit messages could be everyone's New Year's Resolution. You can imagine that Kleyguerth was annoyed when browsing recent changes and saw a pair of commits: "do some stuff", followed by "fixed automated tests".

The "do some stuff" commit looked like this:

if (user) {
    //do some stuff
}

The code has been elided, but it doesn't really matter. This is TypeScript, so the check is "if user is truthy, do some things". The following commit, which "fixed automated tests", changed the code to this:

if (user && !('test' in user)) {
    //do some stuff
}

So yes, something about do some stuff broke the tests. Our intrepid developer saw failing tests and figured out how to fix them: by ensuring that the code which breaks them doesn't run if we're in testing.

And while yes, the automated tests use a user named "test" to run most of their tasks, there is no rule preventing an actual user from using "test" in their name, and since it's a simple in check, you don't have to be the alertest or astutest to see a need to protest this change, and to detest that it was ever made.

[Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!

https://thedailywtf.com/articles/attestation


Метки:  

Error'd: For Auld Lang Syne

Пятница, 30 Декабря 2022 г. 09:30 + в цитатник

Instead of replaying a "best of" moment from 2022 for this final column of the year, I thought I'd dig through the barrel of submissions this week and see what the readers have to offer. Turns out, we got TWO winning entries from someone who appears to be a brand-new poster. Joel Jakubovic sent in his vacation snapshots and it looks like this might also be his last submission ever. The candle shines twice as bright that only burns half so long.

Whiling away his time in line, Joel snapped a shot of an instructional display, explaining "I saw this error in the airport security queue. Its official name is ERROR_INVALID_OPLOCK_PROTOCOL, which sounds like just the sort of excuse you'd get from the TSA as to why they had to saw your suitcase in half."

tsa

 

Sometime later that week, having survived the queue and the crush and the gates, finally aboard his flight (evidently not Southwest or he'd still be waiting) Joel delivered a farewell message. "Apparently I'm on a trip to nowhere, which is precisely 2398 miles away. I don't know what that means, but tell my family I love them." Godspeed, Joel. It was nice knowing you, however briefly.

null

 

After a brief but tasteful silent pause in Joel's memory, consider this anonymous submission of a package tracking page. Our reader mused "I have NaN% confidence my package will arrive on time." I hope it did, Mx Anon.

tracking

 

Excited Boxer Ric K. crowed "I'm getting a WTF submission for Christmas! Thanks, Santa"

oops

 

While for Christmas proper, most of us in the States got delivered a doozy of a Canadian cold shoulder, our friends in the UK managed to escape that. They've got their own heating woes to contend with, however, but fortunately the utilities are on top of things, with a plan to help. Mostly. Michael R. highlights a slight inconsistency. It's no big deal though. What's a measly quid between friends?

eon

 


On behalf of the rest of the crew here at tdwtf, bidding adieu to '22, here's an imaginary toast to this occasion of an arbitrary interval of two rocks spinning around an uncontrolled fusion reaction. May you all find ease and hope in the new year. Cheers.
[Advertisement] Keep the plebs out of prod. Restrict NuGet feed privileges with ProGet. Learn more.

https://thedailywtf.com/articles/for-auld-lang-syne


Метки:  

Best of…: Best of 2022: Special Validation

Четверг, 29 Декабря 2022 г. 09:30 + в цитатник
Ah, password validation, how can that possibly go wrong? Original --Remy

Wireless Router (50841204223)

Ah, routers. The one piece of networking hardware that seems inescapable; even the most tech-illiterate among us needs to interface with their router at least once, to set up their home network so they can access the internet. Router technology has changed a lot over the years, including how you interface with the admin portal: instead of having to navigate to a specific IP address, some of them have you navigate to a URL that is intercepted by the router and redirected to the admin interface, making it easier for laymen to recall. But routers have their share of odd problems. I recently had to buy a new one because the one I was using was incompatible with my company's VPN for cryptic reasons even helpdesk had no real understanding of.

Today's submission concerns a Vodafone router. Our submitter was setting up a network for a friend, and to make things easier, they set up a low-security password initially so they could type it repeatedly without worrying about messing it up. Once the network was set up, however, they wanted to change it to something long and cryptic to prevent against brute-force attacks. They generated a password like 6Y9^}Ky.SK50ZR84.p,5u$380(G;m;bI%NZG%zHd?lOStqRzS}Z?t;8qSg;[gy@ and plugged it in, only to be told it was a "weak" password.

What? Length and variance both seem quite sufficient for the task—after all, it's not like there's roving bands of street gangs hacking into everyone's wifi routers and mucking about with the settings. There's no need for 300-character passwords.

Curious, our submitter opened the Javascript source for the change password page to see what checks they failed, since the UI wasn't helping much:

function CheckPasswordStrength(password) { var password_strength = document.getElementById("password_strength"); var flag = 0; var len = password.length; var arr = []; var sum = 0; var cnt = 0; //TextBox left blank. if (password.length == 0) { password_strength.innerHTML = ""; } var passwordComplexity = $.validator.methods.passwordAtleast.call(); var passwordLength = $.validator.methods.passwordLength.call(); //rule a var passwordAuhtorizedCharacter = $.validator.methods.PasswordAuhtorizedCharacter.call(); for (var i=0; i < len; i++) { if ((password.split(password[i]).length-1) > 1) cnt++; if (i == 0) arr.push({pasChar:password[0],val:4}); else if (i < 8) arr.push({pasChar:password[i],val:2}); else if (i < 21) arr.push({pasChar:password[i],val:1.5}); else if (i > 20) arr.push({pasChar:password[i],val:1}); } if (passwordComplexity == true && len > 8) { arr.push({pasChar:password[i],val:6}); } for (var i=0; iif ((sum < 18) || (passwordAuhtorizedCharacter == false) || (cnt >= (len/2))) flag = 1; else if ((sum >= 18) && (sum <= 30)) flag = 2; else if (sum > 30) flag = 3; //Display status. var strength = ""; var appliedClass = ""; switch (flag) { case 0: case 1: strength = translator.getTranslate("PAGE_DEVICE_PASSWORD_POPUP_PASSWORD_STRENGTH_WEAK"); $(".weak").show(); $(".good").hide(); $(".strong").hide(); appliedClass = "passwordWeak"; break; case 2: strength = translator.getTranslate("PAGE_DEVICE_PASSWORD_POPUP_PASSWORD_STRENGTH_STRONG"); $(".good").show(); $(".weak").hide(); $(".strong").hide(); appliedClass = "passwordGood"; break; case 3: strength = translator.getTranslate("PAGE_DEVICE_PASSWORD_POPUP_PASSWORD_STRENGTH_VERY_STRONG"); $(".strong").show(); $(".weak").hide(); $(".good").hide(); appliedClass = "passwordStrong"; break; } password_strength.innerHTML = strength; $("#password_level").removeClass("passwordWeak passwordGood passwordStrong"); $("#password_level").addClass(appliedClass); }```

So this code is combining the input, output, and algorithm all in one place: easy to write, easy to read. Each character in the password adds a given weight to the total, with earlier characters having a heavier weight than later ones. The sum of the weights is transformed into a classification flag: 1 is bad (does not pass the UI), 2 is okay-ish and 3 (meaning a sum of 20 or higher) is great.

The password our submitter entered has a weight of over 80, so it ought to pass—and yet, it does not. (cnt >= (len/2)) is the condition that's failing. cnt is incremented every time it sees a character more than once in a password, meaning if there's too many repeated characters, the password will fail. This is probably meant to stop passwords like aaaaaaaaaaaaaaaaaaaa from passing muster just based on length alone. And yet, given that the only valid characters are the Latin alphabet, Arabic numerals, and some few special characters, the chance to randomly hit the same character more than once goes up dramatically the longer the password is. So the longer your password is, the more likely it fails this check.

The submitter looked at the code and considered setting cnt to 1 in the debugger just to pass the check. The temptation was strong, but ultimately, they just cut the password in half and submitted it that way. After all, we're not yet in a post-apocalyptic cyberpunk universe where the aforementioned street gangs are looking to pick off easy targets. It's probably fine.

Probably.

[Advertisement] Otter - Provision your servers automatically without ever needing to log-in to a command prompt. Get started today!

https://thedailywtf.com/articles/best-of-2022-special-validation


Метки:  

Best of…: Best of 2022: Padded Mailers

Среда, 28 Декабря 2022 г. 09:30 + в цитатник
Managing whitespace is one of those things that feels harder than it should be. It gets even harder when you do it wrong… Original. --Remy

Veteran developer and frequent contributor, Argle, once worked for a company which handled shipping. On April 3rd, 1988, a C function which used to work stopped working. What's so special about April 3rd of that year? Why, that's when the United States Post Office changed their rates.

The post office changed their rates on a fairly regular cadence, of course. The previous change had been in 1985. Thus the developers had planned ahead, and decided that they wanted to make the rates easy to change. Now, this was mid-80s C code, so they weren't quite thinking in terms like "store it in a database", but instead took what felt like the path of least resistance: they created a lookup table. The function accepted the weight of a piece of postage, checked it against a lookup table, and returned the shipping price.

Clearly, whoever had updated the table had made a mistake somewhere. The developer tasked with tracking down the bug printed out a code listing and pored over it. They couldn't spot the bug. They passed it off to another developer. And another. Each traced through the code, looking for some sort of obvious logical bug. They were all competent developers, this organization wasn't a WTF factory, so it ended up being quite a puzzle to each of them.

Finally, the listing landed in Argle's hands.

I'm making this code up, but the old version of the lookup table might have looked something like:

const int weightInOzToPriceInCents[] = { 0, //you can't mail something at zero weight 22, 39, 56, 73, 90, 107, … 1042//60oz package };

Again, I'm making this code up for illustrative purposes, I'm sure they included much nicer conveniences. The core logic was the same, though: take a weight, and return the price in cents. But what I want to draw your attention to is that this particular code layout doesn't align significant figures. And, given that this was the 80s and nobody had auto-indenting tools, some of the indenting was inconsistent. Some developers had tried to align their updates in the past, some hadn't.

So, whichever developer was tasked with updating the table decided to fix that indenting. But they had a brain-fart moment. So when they fixed it, they fixed it thus:

const int weightInOzToPriceInCents[] = { 0, //you can't mail something at zero weight 0025, 0045, 0065, 85, 0105, 125, … 1225 //60oz package };

Argle looked at the code listing for about two seconds before saying, "Hey, aren't a bunch of these numbers in octal?" Every number with a leading zero was in octal.

The developer responsible snatched the listing back out of Argle's hands in disbelief. "I didn't. I did. UGH."

In making the change, they had decided to take every number than wasn't already padded out and pad it… with zeroes. It seemed like a good idea at the time. Through pure luck of postal rates and previous indenting, they didn't end up padding any lines which weren't valid octal numbers, otherwise they'd have gotten a compile time exception. Everyone else looking at the code had been looking for a bug in the logic of the code itself, and ended up with "zero blindness", completely missing the octal numbers.

The developer walked away, muttering curses. It didn't take them very long to fix the code, but it did take them quite some time to recover from the embarrassment. They weren't alone, though, as everyone who had tried to trace through the code had missed it, and earned their own facepalm moment when they understood what they'd overlooked.

[Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!

https://thedailywtf.com/articles/best-of-2022-padded-mailers


Метки:  

Best of…: Best of 2022: Crappy Wiring

Вторник, 27 Декабря 2022 г. 09:30 + в цитатник
The Daily WTF would like to take this chance to remind you: wash your hands. Original. --Remy

Ellen had just finished washing her hands when her phone buzzed. It vibrated itself off the sink, so there was a clumsy moment when it clattered to the restroom floor, and Ellen tried to pick it up with wet hands.

After retrieving it and having another round of hand washing, Ellen read the alert: the UPS was in overload.

That wasn't good. Their power supply was scaled for future growth- there was more than enough capacity to run all their servers off the UPS. So that meant something was very wrong. Ellen dashed out of the bathroom, conveniently located just off the server room, expecting to see something shorting out and sparking and an ugly cloud of smoke.

But everything was fine. Everything in the server room continued to hum along nicely. Barry, the other server room tech, had already checked the UPS management console: something was drawing 2000W above the baseline load. "Something in here must be drawing extra power," Ellen said. Barry agreed, and they went off searching.

While they searched, their phones pinged again: the UPS was no longer in overload.

"Weird," Barry said. "Do you think it's the health monitoring going off?"

"I mean, it could be," Ellen admitted. "But reporting an overload? I suppose we should open a ticket with the manufacturer."

So Ellen did that, while Barry trotted off to make his trip to the restroom. A few hours later, the UPS manufacturer sent their reply, which in short was something like: "You clearly have misconfigured it. Check this wiki article on how to set alert thresholds. Closing this ticket."

Frustrated, and full of coffee, Ellen traipsed back to the restroom to relieve herself. This time, she was halfway out the restroom door when her phone buzzed. The UPS was in overload again.

Once again, there was nothing obvious going wrong, but the management console reported that something was drawing 2000W above the normal load. "Some device in here has to be going wildly wrong," Ellen said. "Did somebody plug in a fridge, or a space heater or something?"

"I dunno," Barry said. "Do you think we're going to need to do an inventory?"

"I suppose so," Ellen said. She checked her phone. "There are a few hours left in the day, let's see if there's some device we don't expect, or something."

"Sure, but ah, gotta hit the head first," Barry said. He went to the restroom while Ellen pulled up the inventory of the server room and started walking the racks, looking for anything out of place.

That's how they spent the rest of the day, searching through the server room, trying to figure out what might be drawing a whopping 2000W of power off the UPS. There was nothing unusual or out of place, however.

Frustrated and annoyed, Ellen took one last trip through the restroom before she left for the day. And, like clockwork, she was just drying her hands on a paper towel when her phone pinged. The UPS was in overload again.

Once is chance. Twice is coincidence. Three times is a pattern. When Ellen used the bathroom, the alert went off. When Barry used it, it didn't.

Ellen looked around the bathroom. It was a spartan, functional room, without much in it. Lights. Exhaust fan. Sink. Sink. The sink used hot water. On the wall, under the sink, was a petite five liter instant-on hot water heater.

"Oh, they didn't."

The next morning, they got an electrician in. Within a few minutes, Ellen was able to confirm that they, in fact, had: they had wired the bathroom circuit to the server room UPS, not building mains. Every time Ellen washed her hands, the UPS went into overload.

The electrician was able to rewire the bathroom, which lifted that additional load off the UPS. That solved the obvious problem, and made everyone happy.

Nothing could fix the other problem, however. Ellen couldn't bring herself to shake Barry's hands anymore. Maybe he just used cold water… maybe.

[Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!

https://thedailywtf.com/articles/best-of-2022-crappy-wiring


Метки:  

Best of…: Best of 2022: The Biased Bug

Понедельник, 26 Декабря 2022 г. 12:30 + в цитатник
As per usual, we're looking back at some of the best articles of the year. This one's so good, we need to quote it twice. Original --Remy

2018-09-22 Royal typewriter keyboard

Back in the 90s, Steve was the head (i.e. only) programmer and CEO of a small company. His pride and joy was a software package employed by many large businesses. One day, a client of Steve's named Winston called him concerning a critical, show-stopping bug.

CEO Head Programmer Steve was also the Technical Support Lead, and thus he faithfully took up the issue. Over the phone, Winston carefully described the steps needed to reproduce the crash, and Steve walked through them. At a certain point, entering data and hitting Return rendered the program unusable for Winston—but not so for Steve. Much back-and-forth ensued as Steve tried to figure out what Winston was doing differently, and the frustration in Winston's voice mounted every time he had to reboot the system. It was as if the program had something against the poor man.

Since they weren't getting anywhere over the phone, Steve decided he had no choice but to drive out to Winston's office to continue troubleshooting in person. They made arrangements to meet up the next morning.

Once they got together, Winston was easily able to demonstrate the problem. Then Steve sat down at the very same computer, typed exactly the same things ... and everything was fine. They tried again several times, and it really seemed as if the program could sense who was sitting before it. Poor Winston could never catch a break.

Just as Steve despaired of ever figuring out the issue, he happened to get a good look at Winston's hands as he typed.

"Hang on!" Steve cried as the solution hit him. "I see the problem here. The parser is expecting a double quote there. You're typing in two single quotes."

Winston glanced to him with confusion. "Well, how else do you make a double quote?"

Steve was dumbfounded at first. Nevertheless, he patiently walked Winston through the difference between typing two single quotes and one double quote using the Shift key.

"Huh!" Winston said. "The typewriter I learned to type on didn't have anything like that."

Steve frowned. "It didn't have double quotes?"

"There was no key for that. You had to type two single quotes," Winston replied with an authoritative nod.

That must've been quite the old typewriter, Steve thought. He'd had experience with typewriting in his own youth, and remembered Shift keys and double quotes on the models he'd used. It was true, though, that the earliest typewriters only typed capital letters, and thus had no Shift keys.

When writing documentation, Steve had never imagined needing to explain something so regularly taken for granted among computer users. Thankfully, Winston was quite pleased with the lesson. As Steve drove home, he knew he still had to come up with a means of handling bad input in a more elegant fashion, but at least he knew his program wasn't malevolently sentient, just picky.

[Advertisement] Otter - Provision your servers automatically without ever needing to log-in to a command prompt. Get started today!

https://thedailywtf.com/articles/best-of-2022-the-biased-bug


Метки:  

O Holy Night

Понедельник, 26 Декабря 2022 г. 09:30 + в цитатник

It's the holiday week here at the Daily WTF, and we'll be spending the week reviewing the best moments of the year. But as we usually like to do a special post on Christmas, which fell on a weekend this year, we're doing something a little different. This has no real IT or programming related content, it's just a Christmas music video I directed. A more traditional selection will come later today.



A Christmas Carol from Remy Porter on Vimeo.

By Remy Porter and Sarah Allen

[Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!

https://thedailywtf.com/articles/o-holy-night


Метки:  

Error'd: Something Doesn't Add Up

Пятница, 23 Декабря 2022 г. 09:30 + в цитатник

As we grind towards closing out this year, we have a roundup of a variety of the usual sorts of bugs, including some regular old just plain bad labelling. The penultimate submission is particularly puzzling.

Starting us off, Kevin B. has found an example of "new Date(0)" or its equivalent. Says Kevin "I noticed Anonymous is among the top 10 posters of all time on the AT&T Community Forums. Too bad he or she hasn't posted anything since their time at Bell Labs."

att

 

Error'd Regler Argle Bargle offered us a rushed job from MSN. "In their defense, I'll say that they create a lot of little quickie polls to go with articles, so things like this were bound to show up."

decision

 

Malhar S. tries to tempt us with Protected Health Information but it's well-redacted. "Trying to pay bill for Quest lab. The date input clearly has a label 'Patient Date of Birth'. After submitting, error message pops up telling NOT to use patient's DoB."

quest

 

The shortcoming of the Error'd model is that we are implicitly trusting our audience to send us bona fide free-range errors, not factory-made or farm-grown. But every so often someone sneaks in a clever construction (I'm saving some for a special column). And then there are items that you have to wonder "how could a bug like this ever happen?" Some weird application cache? In any event, here's the details from Antonio: "This is from Microsoft Teams. I pasted a link to the Italian article (https://it.wikipedia.org/wiki/Combinazione) of Combination, which basically describes the binomial coefficient (n over k).
But it looks like Microsoft Teams is more interested in a TV presenter." Any ideas?

teams

 

Summing up, Joel C. figures "This is one of the lesser bugs in the McDonald's Android app." It seems like one of the most inexcusable, though.

mcds

 

And now I'm hungry. Off to raid the pantry.
[Advertisement] Continuously monitor your servers for configuration changes, and report when there's configuration drift. Get started with Otter today!

https://thedailywtf.com/articles/something-doesn-t-add-up


Метки:  

Поиск сообщений в rss_thedaily_wtf
Страницы: [124] 123 122 ..
.. 1 Календарь