X-Recipient: archive-cygwin AT delorie DOT com DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D3F3F3861871 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cygwin.com; s=default; t=1699885041; bh=nmaJluP+m7u2RvuCWhpiv8kKbFZLHYTgL25iOhZLclw=; h=Date:To:Subject:References:In-Reply-To:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=W/P/Ln5jeOi43qKT14/lstGtb8lq2Ly3ubYX1CSNZac7KPp+Y/o57lO5IoTSGmBTZ jBz20LHed/WNjJfBh6M5ZqAs2dw0wVkh9KFhrDmAfHUVx8xUZSP+32fxkc3AOiJhCD br35tAZKWvn8Q+gWB/5IVuwO7uEL44RvVoGTeCkM= X-Original-To: cygwin AT cygwin DOT com Delivered-To: cygwin AT cygwin DOT com DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org D75DD3856962 ARC-Filter: OpenARC Filter v1.0.0 sourceware.org D75DD3856962 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1699885029; cv=none; b=cTwnSyMOKmCXsQQLKZ20A0+wrZKn7RapklW36iHfAC+4LOuIaD7kld9vGr0+sxDcAvwbtAaWabGo+s1cQE9dNe5nonwZd1hhC5IZiEfkKfMhNJa6FKSaYLnHOvvg9bi1+F2ylyoga79sW3aHxraSDH4myZ/ehbyYt/kNtkkEBV8= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1699885029; c=relaxed/simple; bh=GqPUCVKgvJPE/X6PkeABfmJftoLlf7aMR8e3Tct90S4=; h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version; b=kJhjnfYo91wKURc+AJxbmjTG0HpK1JLYT2nzAACiF27rG72DwWRIucIgIkyzRrQaGS/ZfTIYp/vnYK6i/0WdWjPD84SRK+Qul13cxTzzY821XLrK9tUmxSyoSd7eYf1BySQFZJ5NdHH4k2KELi6layBzIFVQnFF3KYP1TXQM6u8= ARC-Authentication-Results: i=1; server2.sourceware.org X-MC-Unique: u7orjdSMOJ-_QCw_NSq2Cw-1 Date: Mon, 13 Nov 2023 15:17:02 +0100 To: Bruno Haible , newlib AT sourceware DOT org Subject: Re: rand is not ISO C compliant in Cygwin Message-ID: Mail-Followup-To: Bruno Haible , newlib AT sourceware DOT org, cygwin AT cygwin DOT com References: <9938355 DOT c9vzh5UkMf AT nimes> MIME-Version: 1.0 In-Reply-To: <9938355.c9vzh5UkMf@nimes> X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.8 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline X-Spam-Status: No, score=-10.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: cygwin AT cygwin DOT com X-Mailman-Version: 2.1.30 Precedence: list List-Id: General Cygwin discussions and problem reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Corinna Vinschen via Cygwin Reply-To: newlib AT sourceware DOT org Cc: Corinna Vinschen , cygwin AT cygwin DOT com Content-Type: text/plain; charset="utf-8" Errors-To: cygwin-bounces+archive-cygwin=delorie DOT com AT cygwin DOT com Sender: "Cygwin" Content-Transfer-Encoding: 8bit X-MIME-Autoconverted: from base64 to 8bit by delorie.com id 3ADEHN0W015968 [redirecting to the newlib mailing list] This is long-standing code in newlib, not actually inside Cygwin. On Nov 10 21:19, Bruno Haible via Cygwin wrote: > ISO C 23 ยง 7.24.2.1 and 7.24.2.2 document how rand() and srand() are > expected to behave. In particular: > "The srand function uses the argument as a seed for a new sequence > of pseudo-random numbers to be returned by subsequent calls to rand. > If srand is then called with the same seed value, the sequence of > pseudo-random numbers shall be repeated. ... > The srand function is not required to avoid data races with other > calls to pseudo-random sequence generation functions. ..." > > The two attached programs call srand() in one thread and then rand() > in another thread. There is no data race, since the second thread > is only created after the call to srand() has returned. The behaviour > in Cygwin is that the values in the second thread ignore the srand() > call done in the first thread. Struct _reent is a kind of per-execution unit datastructure. This could be independent code blocks in bare-metal code, or threads in Cygwin et al. So the _reent struct also holds the seed state of the rand and rand48 generators for a good reason. But that's only half the picture, because newlib actually has two ways of storing _reent data: Either in a pre-thread struct _reent, or (if _REENT_THREAD_LOCAL is defined) as per-member thread_local storage. Theoretically, this could be easily fixed: - Either we maintain a global struct _reent which could be used from rand(). - Or, in case of _REENT_THREAD_LOCAL, by making the rand48 data globally available as static data, rather than as thread_local data. The rand() function would still not use locking but AFAICS that's not actually required by POSIX or ISO C. However, this is something I don't want to decide single-handedly, so I'm asking how to go forward on the newlib ML. As far as Cygwin alone is concerned, a patch like this one would suffice: diff --git a/newlib/libc/stdlib/rand.c b/newlib/libc/stdlib/rand.c index ba9cc80f2b21..2b48e7a725b1 100644 --- a/newlib/libc/stdlib/rand.c +++ b/newlib/libc/stdlib/rand.c @@ -58,6 +58,12 @@ on two different systems. #include #include +#ifdef __CYGWIN__ +#define _RAND_REENT _GLOBAL_REENT +#else +#define _RAND_REENT _REENT +#endif + #ifdef _REENT_THREAD_LOCAL _Thread_local unsigned long long _tls_rand_next = 1; #endif @@ -65,7 +71,7 @@ _Thread_local unsigned long long _tls_rand_next = 1; void srand (unsigned int seed) { - struct _reent *reent = _REENT; + struct _reent *reent = _RAND_REENT; _REENT_CHECK_RAND48(reent); _REENT_RAND_NEXT(reent) = seed; @@ -74,7 +80,7 @@ srand (unsigned int seed) int rand (void) { - struct _reent *reent = _REENT; + struct _reent *reent = _RAND_REENT; /* This multiplier was obtained from Knuth, D.E., "The Art of Computer Programming," Vol 2, Seminumerical Algorithms, Third > > How to reproduce the bug: > > $ x86_64-pc-cygwin-gcc -Wall rand-in-posix-thread.c > $ ./a > > or > > $ x86_64-pc-cygwin-gcc -Wall rand-in-isoc-thread.c > $ ./a > > Expected output: > > Value from main thread: 1583559764 > Value from separate thread: 1583559764 > > Actual output: > > Value from main thread: 1583559764 > Value from separate thread: 1481765933 > > #include > #include > #include > #include > > static void * > rand_invocator_thread (void *arg) > { > printf ("Value from separate thread: %d\n", rand ()); > return NULL; > } > > int > main () > { > unsigned int seed = 19891109; > > srand (seed); > printf ("Value from main thread: %d\n", rand ()); > srand (seed); > pthread_t t; > assert (pthread_create (&t, NULL, rand_invocator_thread, NULL) == 0); > assert (pthread_join (t, NULL) == 0); > > return 0; > } > #include > #include > #include > #include > > static int > rand_invocator_thread (void *arg) > { > printf ("Value from separate thread: %d\n", rand ()); > return 0; > } > > int > main () > { > unsigned int seed = 19891109; > > srand (seed); > printf ("Value from main thread: %d\n", rand ()); > srand (seed); > thrd_t t; > assert (thrd_create (&t, rand_invocator_thread, NULL) == thrd_success); > assert (thrd_join (t, NULL) == thrd_success); > > return 0; > } > > -- > Problem reports: https://cygwin.com/problems.html > FAQ: https://cygwin.com/faq/ > Documentation: https://cygwin.com/docs.html > Unsubscribe info: https://cygwin.com/ml/#unsubscribe-simple -- Problem reports: https://cygwin.com/problems.html FAQ: https://cygwin.com/faq/ Documentation: https://cygwin.com/docs.html Unsubscribe info: https://cygwin.com/ml/#unsubscribe-simple