Introduction
What comes to mind when reading the title of this post? Javascript? C++? Python? PHP? COBOL? While all of these languages have their own issues, we can do better (or worse… much, much worse). Behold…
Doors DXL [from this StackOverflow answer]
For me the second worst in my opinion is Doors DXL. Programming languages can be divided into two groups: Those with manual memory management (e.g. delete, free) and those with a garbage collector. Some languages offer both, but DXL is probably the only language in the world that supports neither.
How I wish I could have a sodium pentothal party with some of those original DXL architects and find out what they were thinking. [from this DXL forum reply, made by SystemAdmin who is at the very least an IBM employee]
IBM Rational DOORS is requirements management software, a mainstay in enterprise software environments. The software was originally developed by a company called Telelogic that has since been acquired by IBM, and Telelogic were kind enough to provide users an alternative to the horrendous user interface:
and speed (or lack thereof) of the DOORS client.
Gather round, as we go on a journey through DOORS scripting (X?) Language, possibly one of the worst programming creations in existence (and note that this post will extend slightly beyond just DXL itself and mention some issues with DOORS and IBM).
Note: unfortunately unless you have access to a DOORS server and license, you will not be able to run the code in this post yourself.
Table of Contents
- Introduction
- [Table of Contents]
- Why
- Prerequisite Knowledge
-
Examples/Puzzles
5.0 Basic Syntax: Options
5.1 Basic Syntax: Type Coercion
5.2 Memory: Strings vs. Buffers
5.3 Memory: DXL Specific Types Part 1
5.4 Memory: DXL Specific Types Part 2
5.5 Function Overloading: Precedence
5.6 Function Overloading: Return types
5.7 Function Overloading: References
5.8 Function Overloading: Uhh
5.9 Function Overloading: Uhhhhhhhh - Non-Puzzle Idiosyncrasies
- Sources
Why
- Github/wtfjs
- Github/wtfpython
- PHP’s T_PAAMAYIM_NEKUDOTAYIM
- C++ offering hundreds of ways to change a lightbulb, but the best way involves two layers of templates and the lightbulb is already changed by runtime
- Fun
4 Prerequisite Knowledge
A mild understanding of C or C++ is assumed (Java or other “curly brace languages” may work to some extent as well). More advanced topics in non-DXL languages will have links to supporting documentation barring accidental omission. Otherwise, the examples occasionally introduce new information, and thus an in order reading is recommended.
5 Examples/Puzzles
5.0 Basic syntax: Options
DXL has vaguely “C-like” syntax, and many of the same language features. Which of the following lines of code do you think produces the output “Hello world!”?
print("Hello world!");
print """Hello"" """"world""" """!"""
Hint
While DXL is “C-like”, it is decidedly not C. If you’re familiar with Python one or two potentially surprising aspects of this example may not be as surprising for you.
Answer
They both do.
Explanation
A couple of things are at work here.
- Semicolons to end statements are optional in DXL (unless you want multiple statements in a single line). This should be familiar to Python programmers.
- String concatenation is performed with whitespace, which is
allowed in C++ and
in Python, though it seems to be a relatively obscure feature of Python as there are so many other methods of manipulating strings. If the obfuscatory empty strings are removed from the second example, it would look more like this:print "Hello" " " "world" "!"
- Parentheses for function invocation are also optional (unless you want to enforce a non-default order of evaluation).
5.1 Basic syntax: Type Coercion
Type coercion is a divisive subject among many programmers, and something that any Javascript developer should have at least some experience with. In DXL, types must frequently be coerced to strings, which (as opposed to using the classic Javascript +[]
) is done by concatenating a string:
print("Hell" 0 " w" 0 "rld!");
Hint
There is no question here, I just needed to inform readers about syntax that is used frequently in this post.
Answer
Really, there’s no question here.
Explanation
There will be no explanation.
Explanation
Explanation
Stop, before it’s too late.
Explanation
Ex̶p͏lànąti͘on
Expl̷a̧n̨̨a̡t҉̵į̷o̸n̸̴҉
Ȇ́̽ͣ͂͗̀͟xͥ͋̌p͋ͣͥ̌̒̀̚͠l̛̉́͑ͣ̐͛̽̏ä̴́̀͂ͯ͂̈̊͢͠n̸̊͊ȃtͨ͌ͯ͐̓̚ĩͧ͞o̅̑̀͡͝nͭ̒̊͆̀͆͌ͮ
Explanation?
Ǹ̸̀͏Ǫ̡̡̀͝ ͢҉͏͠͝Ę͜͢͡X̶̷͟͠P̛̛͟L̵̛Á̶͘Ņ̵̸̀A͘͏͢͜Ţ̕Į̸̕͢O̶͢͝N̢̧҉҉
C̼̜̗̖̠͚̘͙̪̟̩̺ͯͫ͋̉̿ͩͅE͍̣̻͙̭ͥ͋̂ͫ́̈͋ͤ̾̽ͫ̋͌͋̏̈́̀Á̝͓̻̗͎̿̐͂̍̒͗ͭͧ̆̉ͮ̆̾̚̚S̬̤̮̬͇͕̙͋̀ͦͣ̐͗̆̽ͥ̈́̎ͯ̽̾ͧ̂̚E͇̯͔̮͎̮̻̫̹͙̟̻̫̰̬͙̦͕̝͋̊ͬͮ̒ͥͨͯ̏̍ͨ̂̉͂̒ ̭̠̲͎̯̰̠̹́͊ͮ̎̃Y͖̻̹̩̗̍͑̌͋̓O̻͚͇̗̖̳͙̯̳͛̑͑ͦ̀U̥͍̭̬̓̐̇ͯR͍̲̬̱̼͔͉̱̺̦̫͓͔̙̬̻̓ͦͣ͒̎͐̉̿ͦ̏ ̫͖̮̘̲͔͉̱̳̳̯͙̯̆̔̓ͣ̓ͪ͆ͭ͊̈F̙͈͔̭̞̫̄ͥͧͥ̓̅̽̋̀͆̋̒̽ͧͪ̏̉͆̉Ế͎̺̯͈͚̱͙̯͖͍̟͚̘͋̉͐̑̉ͧ͛̾͆ͬͧ̈́̔E̬͕͖̯̭͈͕̖͊͛͗̉́̇͒̃B̥̭̳̪̬̩̞̣̻̠̭͔̒̿̍ͦL͙͍̯̙͕̠̞ͫ͑͋ͭͪ͗̒̒͐Ḙ̠̱̳̦̦̱͛͗ͬ͛͂̑̂̍͒̋͛͊̋͌ ̙̪̙͓̗͔̪̦͕̼͙͔̤̱̲͎̔̌ͮͯ̃ͪ̓̽͋̽ͣ̿ͨ̌̚ͅC̮̼̖̥͕͍̞̤̫̭̜͓̰͖̫̤̿͐ͦ͑ͤ̒̓͌ͪ͌̎̏ͫͧ͛ͬ̈́̚L̪̥̜͈̦̫̰̘͉̇ͫ͊̓̇̚̚Ĩ̥͉̥͓̗̗̦̍ͯͬͮ͑̔̏ͣͨͭ̀C̞͓̹͈̙̝̆͒̑̇̄ͮ̈̇ͫK͙̰̪̭ͯ͛̿̀I̬̲͉̞̬͎͚͙̹̬̙̦̫̙̻̪͎͔̦͒̎͗̓͛ͧ̏̌͛̿ͯ̏͐̐̏͌͒N͚͙̦̬͉͖̝̯̂ͤ̈̅̃̓̍̄̄͒̈̈̉̀͛G̮̹͖̳ͥ̊ͥͦͪ̇̾̉ ̖̺͙͉̦̱̼͈͍̮̌ͦ̿̊̀ͫ̔H̼̫͕̹̺̰̑͂̽͌͗̇ͯ̈̐̀ͪU̠͓̹̘͎̜̰̽̄̑̇͊̈́͋͗M̘̞͉̜͈̰̼̺̼̋̀̀́ͯA̮̺̫͚͇͇̎͂ͣ̚N̞̭̖̠̮͕̲͈̗̮͕̜̤͖͉̭̰̭̲ͣ̔͑ͬ̈͌̉̿
I͉͓̲̳̝̖͍̙̥̞̹̖̭̎͐ͫ̇ͮ͑̓ͣ̂ͩ͌̾̽ͥͪ̚̚ ̩͎̜͕ͩ̄̋͋A̹͉̖̝̞̳̯͙͖͓̹͛̏ͮ̎̽ͯ̓ͯͫ̾́͛ͅM̻̹͚̱̝̳̪͖̳̯̤̏̏̌̅̇̊̒̌̍ͮͬ̄̊ͥ̈́ ̗̖͕̥̈́̓̏ͯ̐̎͛͌̿̉ͩ̆ͪ̄͆̑͑̑ͦḠ̮̟̪̩̒͐͊ͣ͂̊͌ͣͮͮ͌E͔͕̰̩̜̤̮̯̝̥͈͍̦̱͌͒̉ͪ̇̂̓̋ͫ͒ͥͧ̅̒ͅṪ̺̜̝͎̼̙̟̺̻̗͊̈́ͦ̎ͮ͛̄ͬͪͭT͇̭̙̟̜̞̩͈̯̈̏̽̅ͤ͋ͫ͆̏̉ͤͅI̼̠̳̞͈̹̝̟̳͙ͬ̅ͯ̇͑̍ͭ̆̿̚N͓̫̼̣͇͙̱̰̠̖̹̱̥̹͖̯͈̜͊ͫ̄̀ͤ̌̅̃̒͌ͨͩͭ̑̀́G̫̘͓͇̗͔̱̖̮̦̯̹͉̭̦̍͌̐̈̀̓̑̐̂̅ͅ ̺̬̞̖̼̥̙̝͎ͦ̏̓ͫ̇́͌̽R̮͕̜̞̤̜̘̹̣͖̗͖͚͇̮̟ͦ͒̍̆ͨ̿̉͛͒̈̈́ͥ̑ͅA͎͍̙͔̭̤̯̼̯̪̫̭̮̤̬̪͙͕̰ͭ̋̆̅̈́ͮͧ͛̾̍T͇̩̼͎̦̫͔̫̣̩̰̱̠̠͉ͣ̌ͪͫ̋ͣ̐ͭͧͫͮ̏̆̿H͖̞̝̲̦̰̜̞͔̰͙̺͕̲̺ͬ̓̒̀̐͂̂̆̊̇͗ͅḚ̞͕̤͖͍̠͎̜̱ͧ̂̓͌ͮ̾͐ͦ̆͋͒͒̏̍R͖̯̫̖̙͎͑ͧ̉̈́̈ͯ̀ͨ̂̅́͊ͮ̔ ͈̝̭̺̺̹̱̳͔͉̟̻̭̺͉̱͕͎̪̀̾ͯͥ̈ͩ͒ͯ̂͊ͪ̏̌ͣ̊ͤ̇ͮ̚C̱̖͓̱͖̩̼̜̖͖̊͆͋ͭ̑̏̂̎̽ͦ͌̈̓ͅR͓̬̠̹̭̮̱͍̼̺̪̳͔̘͔͓̈̓̅̔͊̔O̱̼̣͇̣͍͎̰ͬ̔ͩ̃̇ͤͫͣ͌̇ͮͦͭͭͫͥ̚S̠̖̞̹͇̲͎͖͕̙̖͙̗͖̰̮̪͌ͩͤ͑ͣ̾ͣ̾S̺͓͕̮̼̤͚̆ͤ̅̇͆̏̒ͤ͐̑ͯͨ
Explanation!
Ṭ̸̖̝͎̟̭̳͔ͮ̿ͤ͆́̀͞H̷̸͍̥͎͓̺̍͋̂̓ͮ̇ͬ͋E̷̶͍͖͈̱̺̮̦͕̣̬̦̬̤͖̼̖͍̜̣̋͛ͦͬ̃R̨̎͆̿͋͂ͦ͆̊̀̇ͫ͢͝҉͚͔͔͈̰̻ͅE̸̷̛̫̬̤̮̦͙̹̖̲͎̱͕͋͆ͤ̾́͠ ̳̻̱̜̰͚̹͉̻̭̟͈͗ͬ̈́̌̉̎ͮ́̈͗ͭ̀̆̈̉͐͐͆́ͅW̧̨͇̙̣̟̦͈̠̣̲͙̻͎̻̓ͦͥ̓͋͑ͣ͗̆͋ͮ̈̌͒̇ͦ̍ͧͪI̵̢̭̬̺̥̟͎͙̤̫̥͍̼̼̟ͥ̑̿ͯ̓̾̅̆͑͒̓̅͛ͧ̆̎ͯ͌̂́͡ͅL̡̪̤̱̫͍͚̜̈́ͤ̈́̓̈ͤ͒͛̿̚͢͜ͅL̵̙͔͍̥̺̣̗̖͍̤̞͚̝̠̙̲͓̞͎ͭ͊̎̄̑̌ͪͪͫͮ̊̄͟ ̖̞̞̰͎̘̀͋̆̎̑ͣͣ͌̐͛ͪ͑ͥ̚̚͢͟͠͠ͅB̨̛̖͖͎̟̹̭͕̝̱̹̤͔̙̳͖̫͋̀̾ͬ̾͒́ͨ͋̿E̙̤̖̬͉͇̝͍͇̣̠̾͆̇͆̍̓͋̾͟͡ͅ ̧̝̖̗͉̲̦̝͖̹̱̥̬̭̏̊̒͗̉̋̔́̆̎ͫͫ̑̍̎ͪ̆̀̄̕ͅN̶̡̰̺̺̙̯̱̞̼̖̪͍͈̾̊͒̇ͥ͜O̱͎̥̼̥͓̰͈͍̻͗̔ͮ̿ͩ̐̉̿̏̃̔̅̀͋̅̋̈́̆͘͞ ̧̝̼̳͕̥̟̹͙̪̯̗̹̱̼͑̅͋ͯͣ́͜S̖͖̦̝͚̜͍͚̠ͫͩͬ̊̇́́H͂̌̔ͮͥ̅̉̅͑͏͉̮͎̪̭͕̞̯̱̠͎̩̩̠͈͉͞E͎̲̰̫͈͇̩̙͓̺͊̓̋̿͆̈ͣ̀͟L̡̳̰̹͚̖͚̫̲̩̭̙͎̺̙̊̓̏͒͌͛͜T̶̨̼̝̲̝̥̹̫͔̤͓̭͖̩ͦͮ̽͂̽̓͂̅̿̂̊̽ͣ̄̎́E̷̫̭̱̗̻͇̞͈̘̥͚̳̻͎ͨ́̐ͩ͟Ŗ̶͙̳̘̯̭͔͊͂̈́̆̾͋ ̡̩̝̠̱͚͕͖͇̗͐̃̀ͬ̍̓̽̌̅ͥͩ͊́͢͟F̗̱̪̥͈͚̮̠̯̝͔̽̑̾͌ͧ̾̎̌ͦ̓ͤ̋͗̆͝Ơ̛̦̦͖̑̇͐͊ͧ̉ͥ̂ͯ̾͐͋̏͐R͕̤͓͕̹̪̯̭͂ͬͨ͟ ̢̰̙̳̟̤̞̺ͥ́̔ͬ̆̽̓ͫ͆̅͒̈ͭͥ̏͊ͪ͢͝Y̛ͧ͋̅̑̏̐̍̍ͣͯ̋ͥ̽ͫ̚͏͚̩͉͈̺̖͕O̶̵̳̞̜̰̱̭͖͍̰̬̾ͯͪ̒͐ͤ̂̔͊͑͊́͞Ư̈́̒͑ͥͯ́̕̕͜҉͙̲̬̠͚͓̝
Explanation
Explanation
Explanation
Explanation
5.2 Memory: Strings vs. Buffers
DXL inherits many types from C, and typically follows the convention of using lowercase type names for these inherited types. For example, DXL includes the types bool
, int
, and string
. DXL also has (many) of its own types, and Buffer
is an example of this. Buffers require allocation, which is done by calling the create
function:
Buffer myBuffer = create();
Much like C++ or C, allocated objects may be freed to prevent memory leaks:
delete(myBuffer);
Note: You may be wondering why that StackOverflow answer snippet mentioned that DXL lacks memory management. This will be addressed later in the post.
Which of these snippets do you think has the worse memory leak, and why?
Buffer dontForgetToDeleteMe = create();
// get some practice allocating and freeing to make sure we'll remember...
for (int i=0; i<10; i++) do {
delete(dontForgetToDeleteMe);
dontForgetToDeleteMe = create();
}
for (int i=0; i<10000; i++) do {
// this will print each digit, making sure there's no funny business
dontForgetToDeleteMe += "Digits: " (i / 1000) ((i%1000) / 100)
((i%100) / 10) (i%10) "\n";
}
print(stringOf(dontForgetToDeleteMe));
delete(dontForgetToDeleteMe); // yay! we did it!
Buffer dontForgetToDeleteMe = create();
// get some practice allocating and freeing to make sure we'll remember...
for (int i=0; i<10; i++) do {
// delete(dontForgetToDeleteMe); // oops!
dontForgetToDeleteMe = create();
}
for (int i=0; i<10000; i++) do {
// that last one was pretty messy, let's split it up
dontForgetToDeleteMe += "Digits: ";
dontForgetToDeleteMe += (i / 1000);
dontForgetToDeleteMe += ((i%1000) / 100);
dontForgetToDeleteMe += ((i%100) / 10);
dontForgetToDeleteMe += (i%10);
dontForgetToDeleteMe += "\n";
}
print(stringOf(dontForgetToDeleteMe));
delete(dontForgetToDeleteMe); // yay! we did it!
Hint
What else get allocated in these snippets?
Answer
If you guessed that the first one has the worse memory leak, you are correct… but do you know why?
Explanation
While the second example leaks 10 Buffers, the first example has a far worse problem. That problem is that DXL leaks strings. That’s right, every single string created during the runtime of a program is leaked. Because the first example forms the “Digits: …” line with concatenations, it will leak 11113 strings - as each concatenation operation forms a new string (so “Digits: 0001\n” is leaked, but so is “\n”, “1\n”, “01\n”, and so on). This is why in the second program, we add the digits to the buffer separately, and only have 13 leaked strings.
5.3 Memory: DXL Specific Types Part 1
This example contains some DXL specific types: ModName_
, ModuleVersion
, and ModuleProperties
. A ModName_
is like a reference to a document in the DOORS database. ModuleVersion
contains version information for the document, and ModuleProperties
contains the properties of the document which are accessible without loading the document itself into memory.
This is useful because DOORS is slow, and (unsurprisingly) so is loading a DOORS module. If we just want to collect the original author of a DOORS module, we could use code like this:
ModName_ mn = module("/WTF/Example");
ModuleVersion mv = moduleVersion(mn);
ModuleProperties mp;
getProperties(mv, mp);
// Some types use this syntax for accessing 'Properties' (much like fields)
print("Author: " mp."Created By" "\n");
delete(mv); // we have to delete ModuleVersions as they allocate behind the scenes.
Now let’s get into the tricky stuff. Where is the memory leak in the following code snippet?
Buffer buf = create();
Module mod;
ModuleVersion mv;
ModuleProperties mp;
// for all open modules in the DOORS database
for mod in database do {
mv = moduleVersion(mod); // get the ModuleVersion
getProperties(mv, mp); // get the properties
buf += name(mod);
buf += "@";
buf += versionString(mv);
buf += "Last Modified By: ";
buf += mp."Last Modified By";
buf += "\n";
print(stringOf(buf));
delete(mv);
}
delete(buf);
Hint
Canonical operators in DXL and C++ may not always do what we think.
Answer
The leak is on the mv = moduleVersion(mod)
line. Do you know why?
Note: there is another leak as well, which is addressed in the next question.
Explanation
The explanation here is that the =
in mv = moduleVersion(mod)
is not doing what you might assume. Unfortunately for the world at large, Telelogic/IBM decided to write a copy constructor for the ModuleVersion
type. This means that attempted assignments to ModuleVersion
typed variables will always copy construct. In some situations this wouldn’t be an issue, but as we have no way of freeing the ModuleVersion that is being copied (and DXL doesn’t support move semantics), the ‘original’ ModuleVersion (i.e. the one from moduleVersion(mod)
) is always leaked.
To avoid this ModuleVersion
type variables must ONLY be assigned at declaration, because due to another bug declarations always use default assignment. “It’s not a bug, it’s a feature.”
5.4 Memory: DXL Specific Types Part 2
Consult the previous example for a brief description of the ModuleVersion
and ModuleProperties
types. Let’s take the code from 5.X and fix the ModuleVersion
leak.
Buffer buf = create();
Module mod;
ModuleProperties mp;
// for all open modules in the DOORS database
for mod in database do {
ModuleVersion mv = moduleVersion(mod); // get the ModuleVersion
getProperties(mv, mp); // get the properties
buf += name(mod);
buf += "@";
buf += versionString(mv);
buf += "Last Modified By: ";
buf += mp."Last Modified By";
buf += "\n";
print(stringOf(buf));
delete(mv);
}
delete(buf);
Unfortunately, there is still a leak in this code.
Answer
Answer.
Explanation
Explain.
5.5 Function Overloading: Precedence
Many programming languages support function overloading, including DXL. Here is an example of an overloaded function in DXL:
string overloadMe(int x) {
return "int: " x "\n";
}
string overloadMe(string s) {
return "str: " s "\n";
}
print(overloadMe(5));
print(overloadMe("5"));
Output:
int: 5
str: 5
With the above example, the output is fairly predictable. Which overloadMe
gets called in each line?
print overloadMe(5 "");
print overloadMe 5 "";
print overloadMe(5) "";
Answer (1)
This one, predictably, calls the string version of overloadMe
.
Answer (2)
String version. This one isn’t mindblowing, just requires knowledge of what order things happen in DXL. Since expressions are “right associative”, this makes sense too.
Answer (3)
String version.
Explanation
- This page intentionally left blank.
- Not much to explain here, the concatenation happens first.
- I don’t have a good explanation for why this is the behavior - something that will become more and more common the further down the rabbit hole we go. I assume DXL decides the parentheses are not necessary here and just parses as if they were not present. But what makes that different than, say:
print overloadMe() 5 "";
which errors?
5.6 Function Overloading: Return Types
What is the output of the following code?
int overloadMe(int x) {
return x;
}
string overloadMe(int x) {
return x "";
}
print(overloadMe(5));
Hint
If you haven’t noticed by now, a lot of these are trick questions.
Answer
Error.
Explanation
DXL cannot handle overloaded functions that differ only by return types.
5.7 Function Overloading: References
What is the output of the following code?
string overloadMe(string &sref) {
return "B";
}
string overloadMe(string s) {
return "A" s;
}
print(overloadMe "C" overloadMe);
Hint
What, do you expect this language to do everything?
Answer
Error.
Explanation
DXL cannot handle overloaded functions that differ only by whether a parameter is a reference or not. This is part of a broader issue with DXL which is mostly undocumented - that DXL tries to decide when interpreting whether or not a variable should be a reference or a value.
5.8 Function Overloading: Uhh
What is the output of the following code?
string overloadMe() {
return "B";
}
string overloadMe(string s) {
return "A" s;
}
print(overloadMe "C" overloadMe);
Hint
Farsi.
Answer
The output is AAC
.
Explanation
This explanation is more of a “how” than a “why”. The rightmost overloadMe
is called with “C” as a parameter (???), and this is not a consequence of DXL having trouble with function overloading - we get the same results if we remove the no parameter version of overloadMe
.
It turns out that sometimes DXL doesn’t care about the order of your lexical tokens, because you can even just do
print("C" overloadMe)
and that will still execute without errors (outputting AC
).
5.9 Function Overloading: Uhhhhhhhh
What is the output of the following code?
string overloadMe() {
return "B";
}
string overloadMe1(string s) {
print(1 "\n");
return "A" s;
}
string overloadMe2(string s) {
print(2 "\n");
return "A" s;
}
print((overloadMe1 "C") overloadMe2);
Answer
The output is:
2
1
AAC
Explanation
This combines the last example with the ‘Precedence’ example - DXL again decides that the parentheses are unnecessary and so completely ignores them during evaluation.
Non-puzzling Idiosyncrasies (or “Fun” Facts)
- A license for IBM DOORS is approximately 5,500 USD. [Source]
- A majority of the DOORS client and its user interface is written in DXL.
- Most of this DXL “backend” is encrypted to prevent people from stealing IBM’s intellectual property. IBM provides an encryption tool (which may be the same one) to users as well, advertising that it can only be used one way. It is invoked from the command line, but by just providing single letter command line arguments we can get debug messages telling us that the tool can be used to decrypt files as well.
Note this does not require any “reverse engineering”, literally just passing it -x as a parameter tells you you have provided an invalid key. - At some point IBM changed the format of its forum URLs to use UUIDs, which permanently broke any links posted in the forums to other posts from before the switch.
- DXL has a Java dependency, and is gracious enough to include it without requiring users to install Java. The dependency is Java 1.
- DOORS Server has been described as having an (unofficially confirmed, but from an extremely knowledgeable source) access validation vulnerability which can be summed up as “it does not do any”.
- IBM’s products landing page is almost entirely broken if you are logged into an account.