草庐IT

java - 什么会导致 Java native 函数(在 C 中)在进入时出现段错误?

coder 2023-05-17 原文

该项目

我正在使用 Java native 接口(interface)为内部网络和网络测试工具的 C 库编写 Java 命令行接口(interface)。 C 代码(不是我写的)复杂且低级,通常在位级别操作内存,并且专门使用原始套接字。该应用程序从 C 端(在后台运行的 pthreads)和 Java 端(ScheduledThreadPoolExecutors 运行调用 native 代码的线程)是多线程的。也就是说,C 库应该大部分是稳定的。事实证明,Java 和 JNI 接口(interface)代码导致了问题。

问题

应用程序在进入 native C 函数时因段错误而崩溃。这仅在程序处于特定状态时发生(即成功运行特定 native 函数导致对另一个特定 native 函数的下一次调用发生段错误)。此外,当 quit 出现时,应用程序会因类似的段错误而崩溃。命令发出,但同样,只有在成功运行相同的特定 native 函数之后。

我是一个没有经验的 C 开发人员和一个有经验的 Java 开发人员——我习惯于崩溃给我一个特定的原因和一个特定的行号。在这种情况下,我所要做的就是 hs_err_pid*.log输出和核心转储。我已经在这个问题的末尾包括了我能做的。

我目前的工作

  • 自然,我想找到发生崩溃的特定代码行。我放置了一个 System.out.println()就在 Java 端的 native 调用和 printf() 之前作为程序崩溃的 native 函数的第一行,请务必使用 fflush(stdout)直接之后。 System.out打电话跑了,printf电话没有。这告诉我段错误发生在进入函数时——这是我以前从未见过的。
  • 我三次检查了函数的参数,以确保它们不会起作用。但是,我只传递了一个参数(类型 jint)。另外两个( JNIEnv *env, jobject j_object )是 JNI 结构,不受我控制。
  • 我注释掉了函数中的每一行,只留下一个 return 0;在末尾。段错误仍然发生。这让我相信问题不在于这个函数。
  • 我以不同的顺序运行命令(有效地以不同的顺序运行 native 功能)。只有在崩溃函数调用之前运行了一个特定的 native 函数时,才会发生段错误。此特定函数在运行时似乎表现正常。
  • 我打印了 env 的值指针和 &j_object 的值在其他功能接近尾声时,以确保我没有以某种方式破坏它们。我不知道我是否损坏了它们,但是在退出函数时它们都具有非零值。
  • 编辑 1:通常,同一个函数在多个线程中运行(通常不是并发的,但它应该是线程安全的)。我从主线程运行该函数,没有任何其他线程处于 Activity 状态,以确保 Java 端的多线程不会导致问题。事实并非如此,我也遇到了同样的段错误。

  • 所有这些都让我感到困惑。为什么我把整个函数都注释掉了,除了return语句还是segfault?如果问题出在另一个函数中,为什么它不在那里失败?如果是第一个函数弄乱了内存而第二个函数非法访问损坏的内存的问题,为什么在非法访问时失败,而不是在进入函数时失败?

    如果您看到有人解释了与我类似的问题的互联网文章,请发表评论。有很多段错误文章,但似乎没有一篇包含这个特定的问题。 SO 问题同上。问题也可能是我没有足够的经验来对这个问题应用抽象的解决方案。

    我的问题

    什么会导致 Java native 函数(在 C 中)在像这样进入时出现段错误?我可以寻找哪些特定的东西来帮助我解决这个错误?我将来如何编写代码来帮助我避免这个问题?

    有用的信息

    为了记录,我实际上无法发布代码。如果您认为代码的描述会有所帮助,请发表评论,我将对其进行编辑。

    错误信息
    #
    # A fatal error has been detected by the Java Runtime Environment:
    #
    #  SIGSEGV (0xb) at pc=0x00002aaaaaf6d9c3, pid=2185, tid=1086892352
    #
    # JRE version: 6.0_21-b06
    # Java VM: Java HotSpot(TM) 64-Bit Server VM (17.0-b16 mixed mode linux-amd64 )
    # Problematic frame:
    # j  path.to.my.Object.native_function_name(I)I+0
    #
    # An error report file with more information is saved as:
    # /path/to/hs_err_pid2185.log
    #
    # If you would like to submit a bug report, please visit:
    #   http://java.sun.com/webapps/bugreport/crash.jsp
    # The crash happened outside the Java Virtual Machine in native code.
    # See problematic frame for where to report the bug.
    #
    
    hs_err_pid*.log 的重要部分文件
    ---------------  T H R E A D  ---------------
    
    Current thread (0x000000004fd13800):  JavaThread "pool-1-thread-1" [_thread_in_native, id=2198, stack(0x0000000040b8a000,0x0000000040c8b000)]
    
    siginfo:si_signo=SIGSEGV: si_errno=0, si_code=128 (), si_addr=0x0000000000000000
    
    Registers:
    RAX=0x34372e302e3095e1, RBX=0x00002aaaae39dcd0, RCX=0x0000000000000000, RDX=0x0000000000000000
    RSP=0x0000000040c89870, RBP=0x0000000040c898c0, RSI=0x0000000040c898e8, RDI=0x000000004fd139c8
    R8 =0x000000004fb631f0, R9 =0x000000004faf5d30, R10=0x00002aaaaaf6d999, R11=0x00002b1243b39580
    R12=0x00002aaaae3706d0, R13=0x00002aaaae39dcd0, R14=0x0000000040c898e8, R15=0x000000004fd13800
    RIP=0x00002aaaaaf6d9c3, EFL=0x0000000000010202, CSGSFS=0x0000000000000033, ERR=0x0000000000000000
      TRAPNO=0x000000000000000d
    
    
    
    Stack: [0x0000000040b8a000,0x0000000040c8b000],  sp=0x0000000040c89870,  free space=3fe0000000000000018k
    Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
    j  path.to.my.Object.native_function_name(I)I+0
    j  path.to.my.Object$CustomThread.fire()V+18
    j  path.to.my.CustomThreadSuperClass.run()V+1
    j  java.util.concurrent.Executors$RunnableAdapter.call()Ljava/lang/Object;+4
    j  java.util.concurrent.FutureTask$Sync.innerRun()V+30
    j  java.util.concurrent.FutureTask.run()V+4
    j  java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(Ljava/util/concurrent/ScheduledThreadPoolExecutor$ScheduledFutureTask;)V+1
    j  java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run()V+15
    j  java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Ljava/lang/Runnable;)V+59
    j  java.util.concurrent.ThreadPoolExecutor$Worker.run()V+28
    j  java.lang.Thread.run()V+11
    v  ~StubRoutines::call_stub
    V  [libjvm.so+0x3e756d]
    V  [libjvm.so+0x5f6f59]
    V  [libjvm.so+0x3e6e39]
    V  [libjvm.so+0x3e6eeb]
    V  [libjvm.so+0x476387]
    V  [libjvm.so+0x6ee452]
    V  [libjvm.so+0x5f80df]
    
    Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
    j  path.to.my.Object.native_function_name(I)I+0
    j  path.to.my.Object$CustomThread.fire()V+18
    j  path.to.my.CustomThreadSuperClass.run()V+1
    j  java.util.concurrent.Executors$RunnableAdapter.call()Ljava/lang/Object;+4
    j  java.util.concurrent.FutureTask$Sync.innerRun()V+30
    j  java.util.concurrent.FutureTask.run()V+4
    j  java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(Ljava/util/concurrent/ScheduledThreadPoolExecutor$ScheduledFutureTask;)V+1
    j  java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run()V+15
    j  java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Ljava/lang/Runnable;)V+59
    j  java.util.concurrent.ThreadPoolExecutor$Worker.run()V+28
    j  java.lang.Thread.run()V+11
    v  ~StubRoutines::call_stub
    
    
    
    ---------------  P R O C E S S  ---------------
    
    Java Threads: ( => current thread )
      0x000000004fabc800 JavaThread "pool-1-thread-6" [_thread_new, id=2203, stack(0x0000000000000000,0x0000000000000000)]
      0x000000004fbcb000 JavaThread "pool-1-thread-5" [_thread_blocked, id=2202, stack(0x0000000042c13000,0x0000000042d14000)]
      0x000000004fbc9800 JavaThread "pool-1-thread-4" [_thread_blocked, id=2201, stack(0x0000000042b12000,0x0000000042c13000)]
      0x000000004fbc7800 JavaThread "pool-1-thread-3" [_thread_blocked, id=2200, stack(0x0000000042a11000,0x0000000042b12000)]
      0x000000004fc54800 JavaThread "pool-1-thread-2" [_thread_blocked, id=2199, stack(0x0000000042910000,0x0000000042a11000)]
    =>0x000000004fd13800 JavaThread "pool-1-thread-1" [_thread_in_native, id=2198, stack(0x0000000040b8a000,0x0000000040c8b000)]
      0x000000004fb04800 JavaThread "Low Memory Detector" daemon [_thread_blocked, id=2194, stack(0x0000000041d0d000,0x0000000041e0e000)]
      0x000000004fb02000 JavaThread "CompilerThread1" daemon [_thread_blocked, id=2193, stack(0x0000000041c0c000,0x0000000041d0d000)]
      0x000000004fafc800 JavaThread "CompilerThread0" daemon [_thread_blocked, id=2192, stack(0x0000000040572000,0x0000000040673000)]
      0x000000004fafa800 JavaThread "Signal Dispatcher" daemon [_thread_blocked, id=2191, stack(0x0000000040471000,0x0000000040572000)]
      0x000000004fad6000 JavaThread "Finalizer" daemon [_thread_blocked, id=2190, stack(0x0000000041119000,0x000000004121a000)]
      0x000000004fad4000 JavaThread "Reference Handler" daemon [_thread_blocked, id=2189, stack(0x0000000041018000,0x0000000041119000)]
      0x000000004fa51000 JavaThread "main" [_thread_in_vm, id=2186, stack(0x00000000418cc000,0x00000000419cd000)]
    
    Other Threads:
      0x000000004facf800 VMThread [stack: 0x0000000040f17000,0x0000000041018000] [id=2188]
      0x000000004fb0f000 WatcherThread [stack: 0x0000000041e0e000,0x0000000041f0f000] [id=2195]
    
    VM state:not at safepoint (normal execution)
    
    VM Mutex/Monitor currently owned by a thread: None
    
    Heap
     PSYoungGen      total 305856K, used 31465K [0x00002aaadded0000, 0x00002aaaf3420000, 0x00002aaaf3420000)
      eden space 262208K, 12% used [0x00002aaadded0000,0x00002aaadfd8a6a8,0x00002aaaedee0000)
      from space 43648K, 0% used [0x00002aaaf0980000,0x00002aaaf0980000,0x00002aaaf3420000)
      to   space 43648K, 0% used [0x00002aaaedee0000,0x00002aaaedee0000,0x00002aaaf0980000)
     PSOldGen        total 699072K, used 0K [0x00002aaab3420000, 0x00002aaadded0000, 0x00002aaadded0000)
      object space 699072K, 0% used [0x00002aaab3420000,0x00002aaab3420000,0x00002aaadded0000)
     PSPermGen       total 21248K, used 3741K [0x00002aaaae020000, 0x00002aaaaf4e0000, 0x00002aaab3420000)
      object space 21248K, 17% used [0x00002aaaae020000,0x00002aaaae3c77c0,0x00002aaaaf4e0000)
    
    
    VM Arguments:
    jvm_args: -Xms1024m -Xmx1024m -XX:+UseParallelGC
    
    
    ---------------  S Y S T E M  ---------------
    
    OS:Red Hat Enterprise Linux Client release 5.5 (Tikanga)
    
    uname:Linux 2.6.18-194.8.1.el5 #1 SMP Wed Jun 23 10:52:51 EDT 2010 x86_64
    libc:glibc 2.5 NPTL 2.5
    rlimit: STACK 10240k, CORE 102400k, NPROC 10000, NOFILE 1024, AS infinity
    load average:0.21 0.08 0.05
    
    CPU:total 1 (1 cores per cpu, 1 threads per core) family 6 model 26 stepping 4, cmov, cx8, fxsr, mmx, sse, sse2, sse3, ssse3, sse4.1, sse4.2, popcnt
    
    Memory: 4k page, physical 3913532k(1537020k free), swap 1494004k(1494004k free)
    
    vm_info: Java HotSpot(TM) 64-Bit Server VM (17.0-b16) for linux-amd64 JRE (1.6.0_21-b06), built on Jun 22 2010 01:10:00 by "java_re" with gcc 3.2.2 (SuSE Linux)
    
    time: Tue Oct 15 15:08:13 2013
    elapsed time: 13 seconds
    

    Valgrind 输出

    我真的不知道如何正确使用 Valgrind。这是运行 valgrind app arg1 时出现的情况
    ==2184== 
    ==2184== HEAP SUMMARY:
    ==2184==     in use at exit: 16,914 bytes in 444 blocks
    ==2184==   total heap usage: 673 allocs, 229 frees, 32,931 bytes allocated
    ==2184== 
    ==2184== LEAK SUMMARY:
    ==2184==    definitely lost: 0 bytes in 0 blocks
    ==2184==    indirectly lost: 0 bytes in 0 blocks
    ==2184==      possibly lost: 0 bytes in 0 blocks
    ==2184==    still reachable: 16,914 bytes in 444 blocks
    ==2184==         suppressed: 0 bytes in 0 blocks
    ==2184== Rerun with --leak-check=full to see details of leaked memory
    ==2184== 
    ==2184== For counts of detected and suppressed errors, rerun with: -v
    ==2184== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 7 from 7)
    

    编辑2:

    GDB 输出和回溯

    我用 GDB 运行了它。我确保 C 库是用 -g 编译的。旗帜。
    $ gdb `which java`
    GNU gdb (GDB) Red Hat Enterprise Linux (7.0.1-23.el5)
    Copyright (C) 2009 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
    and "show warranty" for details.
    This GDB was configured as "x86_64-redhat-linux-gnu".
    For bug reporting instructions, please see:
    <http://www.gnu.org/software/gdb/bugs/>...
    Reading symbols from /usr/bin/java...(no debugging symbols found)...done.
    (gdb) run -jar /opt/scts/scts.jar test.config
    Starting program: /usr/bin/java -jar /opt/scts/scts.jar test.config
    [Thread debugging using libthread_db enabled]
    Executing new program: /usr/lib/jvm/java-1.6.0-sun-1.6.0.21.x86_64/jre/bin/java
    [Thread debugging using libthread_db enabled]
    [New Thread 0x4022c940 (LWP 3241)]
    [New Thread 0x4032d940 (LWP 3242)]
    [New Thread 0x4042e940 (LWP 3243)]
    [New Thread 0x4052f940 (LWP 3244)]
    [New Thread 0x40630940 (LWP 3245)]
    [New Thread 0x40731940 (LWP 3246)]
    [New Thread 0x40832940 (LWP 3247)]
    [New Thread 0x40933940 (LWP 3248)]
    [New Thread 0x40a34940 (LWP 3249)]
    

    ...我的程序做了一些工作,并启动了一个后台线程......
    [New Thread 0x41435940 (LWP 3250)]
    

    ...我在下一个命令中键入似乎导致段错误的命令;预计新线程......
    [New Thread 0x41536940 (LWP 3252)]
    [New Thread 0x41637940 (LWP 3253)]
    [New Thread 0x41738940 (LWP 3254)]
    [New Thread 0x41839940 (LWP 3255)]
    [New Thread 0x4193a940 (LWP 3256)]
    

    ...我输入了实际触发段错误的命令。新线程是预期的,因为该函数在其自己的线程中运行。如果它没有段错误,它将创建与前一个命令相同数量的线程......
    [New Thread 0x41a3b940 (LWP 3257)]
    
    Program received signal SIGSEGV, Segmentation fault.
    [Switching to Thread 0x41839940 (LWP 3255)]
    0x00002aaaabcaec45 in ?? ()
    

    ...我疯狂地阅读了 gdb 帮助,然后运行了回溯 ...
    (gdb) bt
    #0  0x00002aaaabcaec45 in ?? ()
    #1  0x00002aaaf3ad7800 in ?? ()
    #2  0x00002aaaf3ad81e8 in ?? ()
    #3  0x0000000041838600 in ?? ()
    #4  0x00002aaaeacddcd0 in ?? ()
    #5  0x0000000041838668 in ?? ()
    #6  0x00002aaaeace23f0 in ?? ()
    #7  0x0000000000000000 in ?? ()
    

    ...如果我用 -g 编译,那不应该有符号吗? ?我做了,根据 make 的输出中的行:
    gcc -g -Wall -fPIC -c -I ...
    gcc -g -shared -W1,soname, ...
    

    最佳答案

    看起来我已经解决了这个问题,为了其他人的利益,我将在这里概述。

    发生了什么

    段错误的原因是我使用了sprintf()char * 赋值尚未赋值的指针。这是错误的代码:

    char* ip_to_string(uint32_t ip)
    {
        unsigned char bytes[4];
        bytes[0] = ip & 0xFF;
        bytes[1] = (ip >> 8) & 0xFF;
        bytes[2] = (ip >> 16) & 0xFF;
        bytes[3] = (ip >> 24) & 0xFF;
    
        char *ip_string;
        sprintf(ip_string, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]);
        return ip_string;
    }
    

    指针ip_string此处没有值,这意味着它不指向任何内容。除此之外,这并不完全正确。它指向的是未定义的。它可以指向任何地方。所以在给它赋值时 sprintf() ,我无意中覆盖了一段随机的内存。我相信奇怪行为的原因(尽管我从未证实过这一点)是未定义的指针指向堆栈上的某个地方。这导致计算机在调用某些功能时感到困惑。

    解决此问题的一种方法是分配内存,然后将指针指向该内存,这可以通过 malloc() 完成。 .该解决方案看起来与此类似:
    char* ip_to_string(uint32_t ip)
    {
        unsigned char bytes[4];
        bytes[0] = ip & 0xFF;
        bytes[1] = (ip >> 8) & 0xFF;
        bytes[2] = (ip >> 16) & 0xFF;
        bytes[3] = (ip >> 24) & 0xFF;
    
        char *ip_string = malloc(16);
        sprintf(ip_string, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]);
        return ip_string;
    }
    

    问题在于每个 malloc()需要通过拨打 free() 来匹配,或者你有内存泄漏。如果我打电话free(ip_string)在这个函数内部,返回的指针将是无用的,如果我不这样做,我就必须依靠调用这个函数的代码来释放内存,这是非常危险的。

    据我所知,对此的“正确”解决方案是将一个已经分配的指针传递给函数,这样函数就有责任填充指向内存。这样,拨打 malloc()free()可以在代码块中进行。安全多了。这是新功能:
    char* ip_to_string(uint32_t ip, char *ip_string)
    {
        unsigned char bytes[4];
        bytes[0] = ip & 0xFF;
        bytes[1] = (ip >> 8) & 0xFF;
        bytes[2] = (ip >> 16) & 0xFF;
        bytes[3] = (ip >> 24) & 0xFF;
    
        sprintf(ip_string, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]);
        return ip_string;
    }
    

    问题的答案

    什么会导致 Java native 函数(在 C 中)在像这样进入时出现段错误?

    如果为尚未分配内存的指针赋值,可能会意外覆盖堆栈上的内存。这可能不会导致立即失败,但可能会在您稍后调用其他函数时导致问题。

    我可以寻找哪些特定的东西来帮助我解决这个错误?

    寻找任何其他段错误。诸如将值分配给未分配的内存或取消引用空指针之类的事情。我不是这方面的专家,但我敢打赌 many web resources为了这。

    我将来如何编写代码来帮助我避免这个问题?

    小心使用指针,尤其是当您负责创建它们时。如果您看到如下所示的一行代码:
    type *variable;
    

    ......然后寻找一条看起来像......
    variable = ...;
    

    ...并确保此行在写入指向内存之前出现。

    关于java - 什么会导致 Java native 函数(在 C 中)在进入时出现段错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19390136/

    有关java - 什么会导致 Java native 函数(在 C 中)在进入时出现段错误?的更多相关文章

    1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

      类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

    2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

      我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

    3. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

      我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

    4. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

      我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

    5. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

      为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

    6. ruby - ruby 中的 TOPLEVEL_BINDING 是什么? - 2

      它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput

    7. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

      我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

    8. ruby - Infinity 和 NaN 的类型是什么? - 2

      我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

    9. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

      如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

    10. ruby - 为什么 SecureRandom.uuid 创建一个唯一的字符串? - 2

      关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?

    随机推荐