Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/xpcom/base/nsUUIDGenerator.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#if defined(XP_WIN)
8
#include <windows.h>
9
#include <objbase.h>
10
#elif defined(XP_MACOSX)
11
#include <CoreFoundation/CoreFoundation.h>
12
#else
13
#include <stdlib.h>
14
#include "prrng.h"
15
#endif
16
17
#include "nsUUIDGenerator.h"
18
19
#ifdef ANDROID
20
extern "C" NS_EXPORT void arc4random_buf(void*, size_t);
21
#endif
22
23
using namespace mozilla;
24
25
NS_IMPL_ISUPPORTS(nsUUIDGenerator, nsIUUIDGenerator)
26
27
nsUUIDGenerator::nsUUIDGenerator()
28
  : mLock("nsUUIDGenerator.mLock")
29
3
{
30
3
}
31
32
nsUUIDGenerator::~nsUUIDGenerator()
33
0
{
34
0
}
35
36
nsresult
37
nsUUIDGenerator::Init()
38
3
{
39
3
  // We're a service, so we're guaranteed that Init() is not going
40
3
  // to be reentered while we're inside Init().
41
3
42
3
#if !defined(XP_WIN) && !defined(XP_MACOSX) && !defined(HAVE_ARC4RANDOM)
43
3
  /* initialize random number generator using NSPR random noise */
44
3
  unsigned int seed;
45
3
46
3
  size_t bytes = 0;
47
6
  while (bytes < sizeof(seed)) {
48
3
    size_t nbytes = PR_GetRandomNoise(((unsigned char*)&seed) + bytes,
49
3
                                      sizeof(seed) - bytes);
50
3
    if (nbytes == 0) {
51
0
      return NS_ERROR_FAILURE;
52
0
    }
53
3
    bytes += nbytes;
54
3
  }
55
3
56
3
  /* Initialize a new RNG state, and immediately switch
57
3
   * back to the previous one -- we want to use mState
58
3
   * only for our own calls to random().
59
3
   */
60
3
  mSavedState = initstate(seed, mState, sizeof(mState));
61
3
  setstate(mSavedState);
62
3
63
3
  mRBytes = 4;
64
3
#ifdef RAND_MAX
65
3
  if ((unsigned long)RAND_MAX < 0xffffffffUL) {
66
3
    mRBytes = 3;
67
3
  }
68
3
  if ((unsigned long)RAND_MAX < 0x00ffffffUL) {
69
0
    mRBytes = 2;
70
0
  }
71
3
  if ((unsigned long)RAND_MAX < 0x0000ffffUL) {
72
0
    mRBytes = 1;
73
0
  }
74
3
  if ((unsigned long)RAND_MAX < 0x000000ffUL) {
75
0
    return NS_ERROR_FAILURE;
76
0
  }
77
3
#endif
78
3
79
3
#endif /* non XP_WIN and non XP_MACOSX and non ARC4RANDOM */
80
3
81
3
  return NS_OK;
82
3
}
83
84
NS_IMETHODIMP
85
nsUUIDGenerator::GenerateUUID(nsID** aRet)
86
0
{
87
0
  nsID* id = static_cast<nsID*>(moz_xmalloc(sizeof(nsID)));
88
0
89
0
  nsresult rv = GenerateUUIDInPlace(id);
90
0
  if (NS_FAILED(rv)) {
91
0
    free(id);
92
0
    return rv;
93
0
  }
94
0
95
0
  *aRet = id;
96
0
  return rv;
97
0
}
98
99
NS_IMETHODIMP
100
nsUUIDGenerator::GenerateUUIDInPlace(nsID* aId)
101
12
{
102
12
  // The various code in this method is probably not threadsafe, so lock
103
12
  // across the whole method.
104
12
  MutexAutoLock lock(mLock);
105
12
106
#if defined(XP_WIN)
107
  HRESULT hr = CoCreateGuid((GUID*)aId);
108
  if (FAILED(hr)) {
109
    return NS_ERROR_FAILURE;
110
  }
111
#elif defined(XP_MACOSX)
112
  CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
113
  if (!uuid) {
114
    return NS_ERROR_FAILURE;
115
  }
116
117
  CFUUIDBytes bytes = CFUUIDGetUUIDBytes(uuid);
118
  memcpy(aId, &bytes, sizeof(nsID));
119
120
  CFRelease(uuid);
121
#else /* not windows or OS X; generate randomness using random(). */
122
  /* XXX we should be saving the return of setstate here and switching
123
12
   * back to it; instead, we use the value returned when we called
124
12
   * initstate, since older glibc's have broken setstate() return values
125
12
   */
126
12
#ifndef HAVE_ARC4RANDOM
127
12
  setstate(mState);
128
12
#endif
129
12
130
#ifdef HAVE_ARC4RANDOM_BUF
131
  arc4random_buf(aId, sizeof(nsID));
132
#else /* HAVE_ARC4RANDOM_BUF */
133
  size_t bytesLeft = sizeof(nsID);
134
84
  while (bytesLeft > 0) {
135
#ifdef HAVE_ARC4RANDOM
136
    long rval = arc4random();
137
    const size_t mRBytes = 4;
138
#else
139
    long rval = random();
140
72
#endif
141
72
142
72
143
72
    uint8_t* src = (uint8_t*)&rval;
144
72
    // We want to grab the mRBytes least significant bytes of rval, since
145
72
    // mRBytes less than sizeof(rval) means the high bytes are 0.
146
#ifdef IS_BIG_ENDIAN
147
    src += sizeof(rval) - mRBytes;
148
#endif
149
    uint8_t* dst = ((uint8_t*)aId) + (sizeof(nsID) - bytesLeft);
150
72
    size_t toWrite = (bytesLeft < mRBytes ? bytesLeft : mRBytes);
151
264
    for (size_t i = 0; i < toWrite; i++) {
152
192
      dst[i] = src[i];
153
192
    }
154
72
155
72
    bytesLeft -= toWrite;
156
72
  }
157
12
#endif /* HAVE_ARC4RANDOM_BUF */
158
12
159
12
  /* Put in the version */
160
12
  aId->m2 &= 0x0fff;
161
12
  aId->m2 |= 0x4000;
162
12
163
12
  /* Put in the variant */
164
12
  aId->m3[0] &= 0x3f;
165
12
  aId->m3[0] |= 0x80;
166
12
167
12
#ifndef HAVE_ARC4RANDOM
168
12
  /* Restore the previous RNG state */
169
12
  setstate(mSavedState);
170
12
#endif
171
12
#endif
172
12
173
12
  return NS_OK;
174
12
}