gecko-dev/xpcom/base/nsVersionComparator.h
Dave Townsend d9a9041a7c Bug 1556832: Comparing compatibility versions goes on to check the build IDs when the version is newer. r=froydnj
When comparing compatibility versions we first compare the version part. If that
shows us to be a downgrade then we stop checking at that point. But we must also
stop checking if it shows us to be an upgrade since we don't need to check the
build IDs at that point. This also applies to the check for the app build ID.

This means that a newer version with an older build id will appear to be a
downgrade.

This is problematic for safe mode because when safe mode runs it sets the
compatibility version to "Safe Mode" (bug 1556831) to ensure that caches are
invalidated on next startup. On the next run the Firefox version is considered
as newer than "Safe Mode" so we would move on to comparing the build IDs. But
the Firefox build ID gets version compared to "" (since there isn't a build ID
part in "Safe Mode"). Since build ID's are larger than 32-bit numbers we trigger
bug 1556829 and the actual comparison depends on the value of the build ID
truncated to 32-bits. This seems to often be negative and so lower than the
apparent previous build ID causing us to think this is a downgrade.

Cue nfroydnj saying I told you so because if I'd written this as a more
traditional compare function as he suggested I probably would have caught this.

Differential Revision: https://phabricator.services.mozilla.com/D33702

--HG--
extra : rebase_source : bb506c4ba4d75a68976bb114015d53cd41b4d4c3
2019-06-04 10:44:16 -07:00

111 lines
3.3 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsVersionComparator_h__
#define nsVersionComparator_h__
#include "mozilla/Char16.h"
#include "nscore.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#if defined(XP_WIN) && !defined(UPDATER_NO_STRING_GLUE_STL)
# include <wchar.h>
# include "nsString.h"
#endif
/**
* In order to compare version numbers in Mozilla, you need to use the
* mozilla::Version class. You can construct an object of this type by passing
* in a string version number to the constructor. Objects of this type can be
* compared using the standard comparison operators.
*
* For example, let's say that you want to make sure that a given version
* number is not older than 15.a2. Here's how you would write a function to
* do that.
*
* bool IsVersionValid(const char* version) {
* return mozilla::Version("15.a2") <= mozilla::Version(version);
* }
*
* Or, since Version's constructor is implicit, you can simplify this code:
*
* bool IsVersionValid(const char* version) {
* return mozilla::Version("15.a2") <= version;
* }
*/
namespace mozilla {
/**
* Compares the version strings provided.
*
* Returns 0 if the versions match, < 0 if aStrB > aStrA and > 0 if
* aStrA > aStrB.
*/
int32_t CompareVersions(const char* aStrA, const char* aStrB);
#ifdef XP_WIN
/**
* As above but for wide character strings.
*/
int32_t CompareVersions(const char16_t* aStrA, const char16_t* aStrB);
#endif
struct Version {
explicit Version(const char* aVersionString) {
versionContent = strdup(aVersionString);
}
const char* ReadContent() const { return versionContent; }
~Version() { free(versionContent); }
bool operator<(const Version& aRhs) const {
return CompareVersions(versionContent, aRhs.ReadContent()) < 0;
}
bool operator<=(const Version& aRhs) const {
return CompareVersions(versionContent, aRhs.ReadContent()) < 1;
}
bool operator>(const Version& aRhs) const {
return CompareVersions(versionContent, aRhs.ReadContent()) > 0;
}
bool operator>=(const Version& aRhs) const {
return CompareVersions(versionContent, aRhs.ReadContent()) > -1;
}
bool operator==(const Version& aRhs) const {
return CompareVersions(versionContent, aRhs.ReadContent()) == 0;
}
bool operator!=(const Version& aRhs) const {
return CompareVersions(versionContent, aRhs.ReadContent()) != 0;
}
bool operator<(const char* aRhs) const {
return CompareVersions(versionContent, aRhs) < 0;
}
bool operator<=(const char* aRhs) const {
return CompareVersions(versionContent, aRhs) < 1;
}
bool operator>(const char* aRhs) const {
return CompareVersions(versionContent, aRhs) > 0;
}
bool operator>=(const char* aRhs) const {
return CompareVersions(versionContent, aRhs) > -1;
}
bool operator==(const char* aRhs) const {
return CompareVersions(versionContent, aRhs) == 0;
}
bool operator!=(const char* aRhs) const {
return CompareVersions(versionContent, aRhs) != 0;
}
private:
char* versionContent;
};
} // namespace mozilla
#endif // nsVersionComparator_h__