On Fri, 3 Jan 2014, Martin Storsjö wrote:

From: Michael Niedermayer <[email protected]>

The new code is faster and reuses the previous state in case of
multiple calls.

The previous code could easily end up in near-infinite loops,
if the difference between two clock() calls never was larger than
1.

This makes fate-parseutils finish in finite time when run in wine,
if CryptGenRandom isn't available (which e.g. isn't available if
targeting Windows RT/metro).
---
This is a revived patch, earlier discussion at
http://patches.libav.org/patch/28570/ and
http://patches.libav.org/patch/28568/.

Using a dynamically allocated SHA context now (with some sort of
fallback for the case if allocation fails), avoiding reading outside
of the buffer, and not allocating a too large digest buffer.
---
libavutil/random_seed.c |   51 ++++++++++++++++++++++++++++-------------------
1 file changed, 30 insertions(+), 21 deletions(-)

diff --git a/libavutil/random_seed.c b/libavutil/random_seed.c
index 4680081..26884cb 100644
--- a/libavutil/random_seed.c
+++ b/libavutil/random_seed.c
@@ -31,8 +31,11 @@
#include <math.h>
#include <time.h>
#include "internal.h"
+#include "intreadwrite.h"
+#include "mem.h"
#include "timer.h"
#include "random_seed.h"
+#include "sha.h"

static int read_random(uint32_t *dst, const char *file)
{
@@ -53,34 +56,40 @@ static int read_random(uint32_t *dst, const char *file)

static uint32_t get_generic_seed(void)
{
+    struct AVSHA *sha = av_sha_alloc();
    clock_t last_t  = 0;
-    int bits        = 0;
-    uint64_t random = 0;
-    unsigned i;
-    float s = 0.000000000001;
+    static uint64_t i = 0;
+    static uint32_t buffer[512] = { 0 };
+    unsigned char digest[20];
+    uint64_t last_i = i;

-    for (i = 0; bits < 64; i++) {
+    for (;;) {
        clock_t t = clock();
-        if (last_t && fabs(t - last_t) > s || t == (clock_t) -1) {
-            if (i < 10000 && s < (1 << 24)) {
-                s += s;
-                i = t = 0;
-            } else {
-                random = 2 * random + (i & 1);
-                bits++;
-            }
+
+        if (last_t == t) {
+            buffer[i & 511]++;
+        } else {
+            buffer[++i & 511] += (t - last_t) % 3294638521U;
+            if (last_i && i - last_i > 4 || i - last_i > 64)
+                break;
        }
        last_t = t;
    }
-#ifdef AV_READ_TIME
-    random ^= AV_READ_TIME();
-#else
-    random ^= clock();
-#endif

-    random += random >> 32;
-
-    return random;
+    if (!sha) {
+        uint32_t seed = 0;
+        int j;
+        // Unable to allocate an sha context, just xor the buffer together
+        // to create something hopefully unique.
+        for (j = 0; j < 512; j++)
+            seed ^= buffer[j];
+        return seed;

So I guess the seeds produced in this case won't be all that strong - is that acceptable for the odd case that we run out of memory here?

We've deprecated av_sha_size and the struct itself is opaque so we can't easily place it on the stack (and even if we'd use av_sha_size, we'd have to get the struct aligned properly). OTOH since both of these are within lavu we could expose the actual struct definition here, but that's not good practice either...

// Martin
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to