1
1
/*
2
- * Copyright (c) 2020, 2023 , Oracle and/or its affiliates. All rights reserved.
2
+ * Copyright (c) 2020, 2024 , Oracle and/or its affiliates. All rights reserved.
3
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
4
*
5
5
* The Universal Permissive License (UPL), Version 1.0
41
41
// skip GIL
42
42
package com .oracle .graal .python .runtime ;
43
43
44
+ import static com .oracle .graal .python .nodes .StringLiterals .J_DEFAULT ;
44
45
import static com .oracle .graal .python .nodes .StringLiterals .J_NATIVE ;
45
46
import static com .oracle .graal .python .nodes .StringLiterals .J_NFI_LANGUAGE ;
46
47
import static com .oracle .graal .python .nodes .StringLiterals .T_LLVM_LANGUAGE ;
91
92
import org .graalvm .nativeimage .ImageInfo ;
92
93
93
94
import com .oracle .graal .python .PythonLanguage ;
95
+ import com .oracle .graal .python .builtins .PythonBuiltinClassType ;
94
96
import com .oracle .graal .python .builtins .PythonOS ;
95
97
import com .oracle .graal .python .builtins .objects .exception .OSErrorEnum ;
98
+ import com .oracle .graal .python .nodes .ErrorMessages ;
99
+ import com .oracle .graal .python .nodes .PRaiseNode ;
96
100
import com .oracle .graal .python .runtime .PosixSupportLibrary .AcceptResult ;
97
101
import com .oracle .graal .python .runtime .PosixSupportLibrary .AddrInfoCursor ;
98
102
import com .oracle .graal .python .runtime .PosixSupportLibrary .AddrInfoCursorLibrary ;
@@ -297,7 +301,7 @@ private enum PosixNativeFunction {
297
301
call_sem_trywait ("(pointer):sint32" ),
298
302
call_sem_timedwait ("(pointer, sint64):sint32" ),
299
303
300
- call_crypt ("([sint8], [sint8], [sint32 ]):sint64" );
304
+ crypt ("([sint8], [sint8]):sint64" );
301
305
302
306
private final String signature ;
303
307
@@ -377,20 +381,8 @@ private static String getLibPath(PythonContext context) {
377
381
@ TruffleBoundary
378
382
private static void loadLibrary (NFIPosixSupport posix ) {
379
383
String path = getLibPath (posix .context );
380
- String backend = posix .nfiBackend .toJavaStringUncached ();
381
- Env env = posix .context .getEnv ();
382
-
383
- posix .context .ensureNFILanguage (null , "PosixModuleBackend" , "native" );
384
-
385
- String withClause = backend .equals (J_NATIVE ) ? "" : "with " + backend ;
386
- String src = String .format ("%sload (RTLD_LOCAL) \" %s\" " , withClause , path );
387
- Source loadSrc = Source .newBuilder (J_NFI_LANGUAGE , src , "load:" + SUPPORTING_NATIVE_LIB_NAME ).internal (true ).build ();
388
-
389
- if (LOGGER .isLoggable (Level .FINE )) {
390
- LOGGER .fine (String .format ("Loading native library: %s" , src ));
391
- }
392
384
try {
393
- posix .nfiLibrary = env . parseInternal ( loadSrc ). call ( );
385
+ posix .nfiLibrary = loadLibrary ( posix , path );
394
386
} catch (Throwable e ) {
395
387
throw new UnsupportedOperationException (String .format ("""
396
388
Could not load posix support library from path '%s'. Troubleshooting:\s
@@ -400,6 +392,28 @@ private static void loadLibrary(NFIPosixSupport posix) {
400
392
}
401
393
}
402
394
395
+ @ TruffleBoundary
396
+ private static Object loadLibrary (NFIPosixSupport posix , String path ) {
397
+ String backend = posix .nfiBackend .toJavaStringUncached ();
398
+ Env env = posix .context .getEnv ();
399
+
400
+ posix .context .ensureNFILanguage (null , "PosixModuleBackend" , "native" );
401
+
402
+ Source loadSrc ;
403
+ if (path != null ) {
404
+ String withClause = backend .equals (J_NATIVE ) ? "" : "with " + backend ;
405
+ String src = String .format ("%sload (RTLD_LOCAL) \" %s\" " , withClause , path );
406
+ if (LOGGER .isLoggable (Level .FINE )) {
407
+ LOGGER .fine (String .format ("Loading native library: %s" , src ));
408
+ }
409
+ loadSrc = Source .newBuilder (J_NFI_LANGUAGE , src , "load:" + SUPPORTING_NATIVE_LIB_NAME ).internal (true ).build ();
410
+ } else {
411
+ loadSrc = Source .newBuilder (J_NFI_LANGUAGE , J_DEFAULT , J_DEFAULT ).internal (true ).build ();
412
+ }
413
+
414
+ return env .parseInternal (loadSrc ).call ();
415
+ }
416
+
403
417
@ TruffleBoundary
404
418
private static void loadFunction (NFIPosixSupport posix , Object library , PosixNativeFunction function ) {
405
419
Object unbound ;
@@ -430,6 +444,7 @@ public InteropLibrary getResultInterop() {
430
444
private final PythonContext context ;
431
445
private final TruffleString nfiBackend ;
432
446
private volatile Object nfiLibrary ;
447
+ private volatile Object cryptLibrary ;
433
448
private final AtomicReferenceArray <Object > cachedFunctions ;
434
449
@ CompilationFinal (dimensions = 1 ) private long [] constantValues ;
435
450
@@ -1848,7 +1863,24 @@ public TruffleString crypt(TruffleString word, TruffleString salt,
1848
1863
@ Shared ("tsCopyBytes" ) @ Cached TruffleString .CopyToByteArrayNode copyToByteArrayNode ,
1849
1864
@ Shared ("tsFromBytes" ) @ Cached TruffleString .FromByteArrayNode fromByteArrayNode ,
1850
1865
@ Shared ("fromUtf8" ) @ Cached TruffleString .SwitchEncodingNode switchEncodingFromUtf8Node ) throws PosixException {
1851
- int [] lenArray = new int [1 ];
1866
+ /*
1867
+ * We don't want to link the posix library with libcrypt, because it might not be available
1868
+ * on the target system and would make the whole posix library fail to load. So we load it
1869
+ * dynamically on demand.
1870
+ */
1871
+ if (injectBranchProbability (SLOWPATH_PROBABILITY , cryptLibrary == null )) {
1872
+ try {
1873
+ cryptLibrary = InvokeNativeFunction .loadLibrary (this , PythonOS .getPythonOS () != PythonOS .PLATFORM_DARWIN ? "libcrypt.so" : null );
1874
+ } catch (Throwable e ) {
1875
+ CompilerDirectives .transferToInterpreterAndInvalidate ();
1876
+ throw PRaiseNode .raiseUncached (invokeNode , PythonBuiltinClassType .SystemError , ErrorMessages .UNABLE_TO_LOAD_LIBCRYPT );
1877
+ }
1878
+ }
1879
+ PosixNativeFunction function = PosixNativeFunction .crypt ;
1880
+ if (injectBranchProbability (SLOWPATH_PROBABILITY , cachedFunctions .get (function .ordinal ()) == null )) {
1881
+ InvokeNativeFunction .loadFunction (this , cryptLibrary , function );
1882
+ }
1883
+ Object funObject = cachedFunctions .get (function .ordinal ());
1852
1884
/*
1853
1885
* From the manpage: Upon successful completion, crypt returns a pointer to a string which
1854
1886
* encodes both the hashed passphrase, and the settings that were used to encode it. See
@@ -1857,15 +1889,26 @@ public TruffleString crypt(TruffleString word, TruffleString salt,
1857
1889
* safe to call crypt from multiple threads simultaneously. Upon error, it may return a NULL
1858
1890
* pointer or a pointer to an invalid hash, depending on the implementation.
1859
1891
*/
1860
- // Note GIL is not enough as crypt is using global memory so we need a really global lock
1892
+ // Note GIL is not enough as crypt is using global memory, so we need a really global lock
1861
1893
synchronized (CRYPT_LOCK ) {
1862
- long resultPtr = invokeNode .callLong (this , PosixNativeFunction .call_crypt , stringToUTF8CString (word , switchEncodingToUtf8Node , copyToByteArrayNode ),
1863
- stringToUTF8CString (salt , switchEncodingToUtf8Node , copyToByteArrayNode ), wrap (lenArray ));
1894
+ long resultPtr ;
1895
+ Object [] args = new Object []{
1896
+ stringToUTF8CString (word , switchEncodingToUtf8Node , copyToByteArrayNode ),
1897
+ stringToUTF8CString (salt , switchEncodingToUtf8Node , copyToByteArrayNode )};
1898
+ try {
1899
+ Object interopResult = invokeNode .functionInterop .execute (funObject , args );
1900
+ resultPtr = invokeNode .getResultInterop ().asLong (interopResult );
1901
+ } catch (UnsupportedTypeException | ArityException | UnsupportedMessageException e ) {
1902
+ throw CompilerDirectives .shouldNotReachHere (e );
1903
+ }
1864
1904
// CPython doesn't handle the case of "invalid hash" return specially and neither do we
1865
1905
if (resultPtr == 0 ) {
1866
1906
throw getErrnoAndThrowPosixException (invokeNode );
1867
1907
}
1868
- int len = lenArray [0 ];
1908
+ int len = 0 ;
1909
+ while (UNSAFE .getByte (resultPtr + len ) != 0 ) {
1910
+ len ++;
1911
+ }
1869
1912
byte [] resultBytes = new byte [len ];
1870
1913
UNSAFE .copyMemory (null , resultPtr , resultBytes , Unsafe .ARRAY_BYTE_BASE_OFFSET , len );
1871
1914
return createString (resultBytes , 0 , resultBytes .length , false , fromByteArrayNode , switchEncodingFromUtf8Node );
0 commit comments