使你的软件守规矩----防止缓存泄漏

用 scanf 系列函数实现简单的 email 地址合法性检查功能 对于 scanf 家族系列函数( scanf, fscanf, sscanf, vscanf, vsscanf, vfscanf),相信大家对它们常见的格式化输入已十分熟悉。 但是, scanf 系列函数,还有一个特殊的用法,该用法能够实现简单的字符过滤功能,类似正则表达式,您是否知道呢? scanf 函数还能实现正则表达式?让我们往下看吧^_^ 这个特殊的格式,就是“[ ]”,一对中括号,支持 阅读详情

使你的软件守规矩----防止缓存泄漏(查看原文)


通过防御性编程保护你的代码

Gary McGraw, 可靠软件技术
John Viega, 可靠软件技术

   在我们前一个栏目中,我们描述缓存溢出攻击处在很高的水平,并且讨论为什么缓存溢出有如此巨大的安全问题。通过防御型编程保护你的代码免受缓存溢出攻击是本栏目的主题。我们将覆盖C编程语言中主要的安全陷阱,显示为什么你需要避免特定的结构并展示优先的编程实践。最后,我们讨论可以帮助你有效停止缓存溢出的其它技术。

    C中绝大部分的缓存溢出问题可以直接追溯到标准C库。最差的肇事者是有问题的不带任何参数检查的字符串操作(strcpy、strcat、sprintf、gets)。通常来讲,类似“避免strcpy()”与”绝不使用gets()“的硬性快速的规则接近该目标。

    今天写的程序依旧使用这些调用,因为开发者从不考虑避免它们。一些人从这里与那里获得一些提示,不过只有优秀的开发者可以扭紧心弦。他们或许使用自己的方法对传递给危险函数的参数进行检查,或者不正确地推理使用一个潜在危险的函数在一些特定情况是”安全的“。

    公共敌人一号是gets()。绝不使用gets()。该函数从标准输入中读取一行用户输入的文本,并且在遇到EOF字符或换行符之前并不停止读取文本。那是正确的:gets()根本不进行边界检测。它总是可能溢出使用gets()的任何缓存。作为替换,使用方法fgets()。它所做的与gets()所做的一样,不过它接受一个大小参数去限制读入的字符数量,因此给你提供一个防止缓存溢出的方法。例如,替换下面的代码:

void main()
{
  char buf[1024];
  gets(buf);
}

使用下面的:

#define BUFSIZE 1024
void main()
{
  char buf[BUFSIZE];
  fgets(buf, BUFSIZE, stdin);
}

C编程中的主要陷阱

   C语言中标准函数的数量具有使你陷入困境的巨大潜能。不过并不是所有它们的使用是糟糕的。通常,使用这些函数需要一个随意输入传给该函数。这个列表包括:

    • strcpy()
    • strcat()
    • sprintf()
    • scanf()
    • sscanf()
    • fscanf()
    • vfscanf()
    • vsprintf()
    • vscanf()
    • vsscanf()
    • streadd()
    • strecpy()
    • strtrns()

    坏消息是我们建议你如果可能避免使用这些函数。好消息是在很多情况存在合理的可供选择的函数。我们将会讲述它们每一个,因此你可以看到是什么构成它们的错误使用与如何避免它。

    strcpy()函数拷贝源字符串到一个缓存。没有指定将要拷贝的字符数量。拷贝的字符数量直接依赖于源字符串有多少字符。如果源字符串碰巧来自于用户输入并且你没有显示限制大小,你就潜在陷入一个大问题!

如果你知道目标缓存的大小,你可以增加一个显式检查:

if(strlen(src) >= dst_size) { 
  /*Do something appropriate, such as throw an error. */
else {
  strcpy(dst, src);
}

一个更简单的实现相同目标的方式是使用strncpy()运行时库:

strncpy(dst, src, dst_size-1);
dst[dst_size-1] = '\0'; /* Always do this to besafe! */

如果src比dst大,该函数并不抛出错误;它只是在当到达最大尺寸时停止拷贝字符。注意,前面调用strncpy()的-1。如果src比dst大,它给我们添加null字符的空间。

当然,使用strcpy()而没有任何潜在安全问题也是有可能的,就像我们下面例子中看到的:

strcpy(buf, "Hello!");

即使该操作没有溢出buf,它也只在少量字符的时候才这样。因为,我们知道这些字符是静态的,并且因为它们十分明显无害的,在此没有任何东西需要担心。当然,直到字符串”Hello”的静态存储可以被其它途径重写。

另一个确保你的strcpy()不会溢出的方法是当需要它的时候重新分配空间,通过对源字符串使用strlen()函数确保分配足够多的空间。例如:

dst = (char *)malloc(strlen(src));
strcpy(dst, src);
strcat()函数与strcpy()相似,除了它将一个字符串添加到一个缓存后面。它也具有一个相似的更安全可供选择的strncat()。如果你可能,使用strncat()替换strcat()。

    函数sprintf()与vsprintf()是为格式化文本并且保存到缓存的多功能函数。他们可以直接用于模拟strcpy()的行为。换句话说,就和使用strcpy()一样,它容易给你的程序添加缓存溢出。例如,考虑下面的代码:

void main(int argc, char **argv)
{
  char usage[1024];
  sprintf(usage, "USAGE: %s -f flag [arg1]\n", argv[0]);
}

   我们尝尝看到代码像这个一样优美。它看上去足够无害。它产生知道程序如何调用的字符串。那种方式,二进制程序的名称可以改变,程序的输出会自动反应该改变。虽然如此,代码有非常严重的错误。文件系统趋向于限制任何文件的名字在特定数量的字符。因此,你最好考虑如果你的缓存足够大以至于能够容纳最长的可能名字,你的程序会是安全地,正确吗?只要改变1024为我们操作系统适合的数字我们就完成了吗?不过并不是这样的,我们可以简单地通过书写启动上面程序的我们自己的小程序来打乱该限制:

void main()
{
  execl("/path/to/above/program", 
    <<insert really long string here>>,
    NULL);
}

函数execl()启动第一个参数中命名的程序。第二个参数作为argv[0]传递为调用的参数。我们可以使该字符串像我们想要的一样长。

因此,我们如何绕开该{v}sprint()的问题?不幸的是,并没有完全可移植的方式。一些体系结构提供snprintf()方法,它准许程序员指定从每个源中拷贝多少字符。例如,如果snprintf在你的系统上有效,我们可以修复前面例子:

void main(int argc, char **argv)
{
  char usage[1024];
  char format_string = "USAGE: %s -f flag [arg1]\n";
  snprintf(usage, format_string, argv[0], 
    1024-strlen(format_string) + 1);
}
    注意,直到第四个参数,snprintf()都和sprintf()一样。第四个参数指定从将要拷贝到缓冲usage的第三个参数的最大字符数。注意1024是个错误的数字!我们必须确保我们拷贝到usage中的字符串总长度没有超出缓存的大小。因此,我们必须考虑null字符,加上所有在格式字符串中的字符,减去格式指示符%s。该数字结果是1000,不过前面的代码是可维护的,因为如果格式字符串改变的时候,它不会出错。

    {v}sprint()的很多(并不是所有)版本都产生比使用这两个函数的更安全方式。你可以为格式字符串自身的每个参数指定一个精度。例如,另一个修复前面出错的sprintf()的方式是:

void main(int argc, char **argv)
{
  sprintf(usage, "USAGE: %.1000s -f flag [arg1]\n", argv[0]);
}
注意.1000在百分号之后,且在s之前。该语法表名不大于1000个字符会从相关变量(在这个例子中,argv[0])拷贝出来。

    如果两个解决方案在你程序必须运行的系统上都不可用,你最好的解决方案是打包snprintf()的工作版本与你的代码。一个免费的可用方式可以在sh存档格式中找到,参考Resources。

继续,scanf函数家族设计也很差劲。在这个例子中,目标缓存会溢出。考虑下面代码:

void main(int argc, char **argv)
{
  char buf[256];
  sscanf(argv[0], "%s", &buf);
}

    如果扫描的单子大于buf的大小,我们就拥有溢出情况。幸运的是,有解决该问题的简单方式。考虑下面的代码,它没有安全弱点:

void main(int argc, char **argv)
{
  char buf[256];
  sscanf(argv[0], "%255s", &buf);
}

在百分号与s之前的255指明argv[0]中的不多于255个字符会实际保存在变量buf中。相匹配的字符的其它部分不会被拷贝。

    接着我们转到streadd()与strecpy()。虽然并不是每一台机器都具有这些调用,具有有效的这些函数的程序员在使用它们的时候需要十分小心。这些函数将一个可能具有不可读字符的字符串转换为可打印表现。例如,考虑下面的程序:

void main(int argc, char **argv)
{
  char buf[20];
  streadd(buf, "\t\n", "");
  printf(%s\n", buf);
}

该程序打印:

\t\n

而不是打印空格空白。如果程序员没有过早预见无溢出地处理输入的输出缓存需要多大,streadd()函数会是有问题的。如果输入缓存包含单独的字符,如ASCII001(ctrl-A),它将打印成四个字符,“\001”。这是字符串增长的最坏情况。如果你不能分配足够多的空间,而输出缓存总是四倍于输入缓存的大小,缓存溢出是可能的。

    另一个很少用的函数是strtrns(),因为很多机器并不拥有它。该函数strtrns()拥有3个字符串与一个保存结束字符串的缓存作为参数。第一个字符串是基本都拷贝到该缓存。从第一个字符串拷贝到该缓存的字符,除了在第二个字符串中出现的。如果确实存在,在第三个字符串中相同索引的字符将作为替换。这听起来很令人困惑。让我们看一个将argv[1]中所有小写字母字符转换为大写字母字符的例子:

#include <libgen.h>
void main(int argc, char **argv)
{
  char lower[] = "abcdefghijklmnopqrstuvwxyz";
  char upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  char *buf;
  if(argc < 2) {
    printf("USAGE: %s arg\n", argv[0]);
    exit(0);
  }
  buf = (char *)malloc(strlen(argv[1]));
  strtrns(argv[1], lower, upper, buf);
  printf("%s\n", buf);
}

    前面的代码实际上并没有包含缓存溢出。但是如果我们使用固定大小静态缓存而不是使用malloc()去分配拷贝argv[1]的足够空间,或许会产生缓存溢出。

避免内部缓存溢出

    realpath()函数拥有一个可以潜在包含相对路径的字符串,并且将它转换为引用相同文件不过通过绝对路径的字符串。当它这样做的时候,它扩展所有符号链接。

    这个函数拥有两个参数,第一个是要被规范化的字符串,第二个是将要保存结果的缓存。当然,你需要确保结果缓存足够大以至于能够处理任何大小的路径。分配MAXPATHLEN大小的缓存应该是足够的。然而,realpath()有另外一个问题。如果你传递一个大于MAXPATHLEN的将要规范化的路径,realpath()实现内部的静态缓存就溢出了!事实上,你不能访问已经溢出的缓存,不过无论如何它伤害了你。作为结果,你需要明确不实用realpath(),除非你确保你尝试规范化的路径长度不大于MAXPATHLEN。

    其它普遍可用调用拥有相同的问题。非常常见的调用syslog()在注意到并且在不久前修复之前具有相同的问题。这个问题在大部分机器上都是正确的,不过你不应该依赖正确的行为。最好总是假设你的代码可能运行在大部分不利的环境下,仅仅万一某一天确实出现了。getopt()家族调用的多种实现,与getpass()函数一样,也异常内部静态缓存溢出的影响。如果你必须使用这些函数,最好的解决方法是总是限定你传递给它们的输入长度。

你自己去模拟gets()、安全问题等等是非常简单的。例如,下面的代码:

char buf[1024];
int i = 0;
char ch;
while((ch = getchar()) != '\n')
{
  if(ch == -1) break;
  buf[i++] = ch;
}

    哎哟!任何你可以用于读入字符的函数都在这个问题上崩溃,包括getchar()、fgetc()、getc()与read()。

缓存溢出问题的教训是:总是确保进行边界检测。

    C与C++都没有自动边界检测,这是非常糟糕的,不过事实上有一个非常好的原因它们为什么不那样做。边界检测的代价是效率。通常,C在多种权衡时更热衷效率。然而,效率成本增长了,C程序员必须忙个不停了,并且极具安全意识保证他们的程序没有问题,即使这样保证代码没有问题并不是容易的事。

    在这一天与这个时代,参数检查并不组成程序效率的最大消耗。绝大多数应用从不注意这个区别。因此总是进行边界检测。在你拷贝到你自己的缓存之前,检查数据的长度。也要检查确保你没有传递很大的数据到另一个库,因为你也不能相信别人的代码!(回忆一下我们前面讨论的内部缓存溢出。)

什么是其它危险?

    不幸的是,即使系统调用的”安全“版本----就像相对strcpy()而言的strncpy()----也不是完全安全的。也有可能把事情搞砸。即使”安全”调用有时也会保留字符串不确定的或遇到微妙的大小差异(off-by-one)bug。当然,如果你碰巧使用一个小于源缓存结果缓存,你也会在十分困难的地方发现自己。

    这些错误比迄今为止讨论到的每一个都难域构造,不过你还要意识到它们。当你使用这类调用时仔细考虑。如果你没有十分注意缓存大小,很多函数会行为不端,包括bcopy()、memcpy()、snprintf()、strncpy()、strcadd()与vsnprintf()。

    其它避免的系统调用是getenv()。getenv()的最大问题是你可能从没假设一个特殊的环境变量可以是任何特定长度的。我们将要在下一个栏目中讨论环境变量的各种各样问题。

    迄今为止,我们为你提供了一个大的洗衣房式的通用的易受缓存溢出问题影响的C函数列表。肯定还有更多的具有相同问题的函数。实际上,注意第三方检测设备(COTS)软件。不要假设关于其它人的软件的行为。也要注意我们并没有仔细检查每一个平台上的所有通用库(我们不希望那样的工作),其它问题调用很可能存在。

即使我们检查任何地方的每一个通用函数,你也应该十分、十分怀疑我们是否尝试声明我们列出所有你曾经遇到的问题。我们只是希望给你一个良好的开端。其余的取决与你。

静态与动态测试工具

    我们将在后面的栏目详细介绍脆弱的检测工具,不过现在值得一体的是两种类型的扫描工具会检测效率,帮助查找与去除缓存溢出问题。两个主要的分析工具类别是静态工具(代码被考虑但从不运行)与动态工具(代码被执行去判断行为)。

    许多静态工具可以用于查找潜在的缓存溢出问题。糟糕的是它们中没有对通用公众有效的工具。该工具类的许多并没有比自动通过运行grep命令去查找源代码中每一个问题函数实例做的更多。虽然存在更好的技术,这依旧是一个高效率的缩小成千上万行大程序为仅仅几百行“潜在问题”的方式。(在下一栏目,我们将展示给你基于该技术的快餐式的扫描工具,同时给你提供它如何构造的思想。)

    更好的静态工具以一些放些使用数据流信息去合计哪个变量影响其它哪些变量。这种方式,一些基于grep的分析的”假阳性”可以被丢弃。David Wagner已经在他的工作中实现了该方法(描述在“Learning the basics of buffer overflows”,查看资源),就像对高可靠技术的研究。数据流相关方法的问题是刚刚介绍的假阳性(即,并没有标识真正问题的一些调用)。

    第二类方法引入动态分析的应用。动态工具通常关注代码的运行,去查找潜在的问题。一种在实验中的方法是错误注入。思想是以可以实验它的方式编写指令程序,运行”要是…怎么样“的游戏并且观察发生了什么。一个相关错误注入工具,FIST(查看资源),已经用于定位潜在缓存溢出脆弱性。

最终,动态与静态方法的一些结合可以为你的投入提供最大的反馈。更多判断最好结合的工作等着去做。

Java与堆栈保护会有帮助

    像我们前一栏目(参考资源)提到的,堆栈粉碎是缓存溢出攻击的最坏种类,尤其当将要粉碎的堆栈在特权模式下运行。该问题的一个简洁的解决方法是不运行堆栈。通常,溢出的代码写在程序堆栈上,并且执行它们。(我们将会在下一栏目中解释这是如何实现的。)很能去为包括Linux与Solaris的许多操作系统获取非运行堆栈补丁。(一些操作系统并不需要该补丁;它们就是那样做的。)

    非执行堆栈具有一些隐含的性能问题。(没有免费的午餐。)此外,它们在程序中有堆栈溢出与堆溢出两者的时候很容易失败。堆栈溢出优先引起程序跳到溢出代码,它们存放在堆中。在堆栈中的代码没有实际执行,只是堆中的代码。这些功能型顾虑足够重要,我们把下一栏目奉献给它们。

    当然,另一个选项是使用类型安全型语言,如Java。一个非极端的措施是为C语言获取执行数组边界检测的编译器。如为GCC存在的工具。该技术具有预防所有缓存溢出(堆与堆栈)的优势。消极的一面是对于性能关键的指针密集型语言,该技术会束缚适当的性能。不过在大多数情况,该技术会异常出色。

    堆栈防御工具实现了比通用边界检测更具性能的技术。他在堆栈分配的数据后面添加少量数据,并且随后在缓存溢出可能发生之前查看该数据是否还在。这个模式称作”金丝雀“。(Welsh矿工在煤矿中防止一只金丝雀以告知有危险的情况。当空气变得有毒时,这个金丝雀会衰弱,帮助给予矿工足够的时间去注意与逃离。)

    堆栈防御方法不像通用边界检测那样安全,不过依然很有用。与通用边界检测相比,堆栈防御的主要不足是它不能防止堆溢出攻击。通常,最好使用该工具保护你的整个操作系统,否则你程序中的非保护的库调用(如标准库)依然能够开启基于堆栈溢出代码威胁的大门。

    与堆栈防御相似的工具是内存完整性检测包,如Rational的Purify。该类工具甚至可以防止堆溢出,不过通常不用于由于性能瓶颈原因产生的代码。

总结

    在该栏目的前两部分,我们给你介绍了缓存溢出,并且针对如何写出避免这些问题的代码给以指引。我们也讨论了一些工具,它们可以帮助使你的代码保持安全于令人畏惧的缓存溢出。表1总结我们推荐你小心或避免使用的程序结构。如果你有其它你你认为我们应该添加到该列表中的函数,请告知我们,我们将更新该列表。

函数

安全性

解决方法

gets

最危险

使用fgets(buf, size, stdin)。这几乎总是个大问题!

strcpy

很危险

使用strncpy作为替换

strcat

很危险

使用strncat作为替换

sprint

很危险

使用snprintf作为替换,或者使用精度指示符

scanf

很危险

使用精度指示符,或做你自己的解析

sscanf

很危险

使用精度指示符,或做你自己的解析

fscanf

很危险

使用精度指示符,或做你自己的解析

vfscanf

很危险

使用精度指示符,或做你自己的解析

vsprintf

很危险

使用vsnprintf作为替换,或做你自己的解析

vscanf

很危险

使用精度指示符,或做你自己的解析

vsscanf

很危险

使用精度指示符,或做你自己的解析

streadd

很危险

确保你分配源参数的4倍大小作为目标的尺寸

strecpy

很危险

确保你分配源参数的4倍大小作为目标的尺寸

strtrns

危险

手动检查目标至少与源字符相同大小

realpath

很危险(或少,依赖于实现

分配给你的缓存MAXPATHLEN大小。也要手动检查参数确保输入参数不长于MAXPATHLEN。

syslog

很危险(或少,依赖于实现

在传递给该函数之前,截断所有的输入字符在一个合理的大小。

getopt

很危险(或少,依赖于实现

在传递给该函数之前,截断所有的输入字符在一个合理的大小。

getopt_long

很危险(或少,依赖于实现

在传递给该函数之前,截断所有的输入字符在一个合理的大小。

getpass

很危险(或少,依赖于实现

在传递给该函数之前,截断所有的输入字符在一个合理的大小。

getchar

中等危险

如果在循环中使用该函数,确保检查缓存边界。

fgetc

中等危险

如果在循环中使用该函数,确保检查缓存边界。

getc

中等危险

如果在循环中使用该函数,确保检查缓存边界。

read

中等危险

如果在循环中使用该函数,确保检查缓存边界。

bcopy

低危险

确保你的缓存和你说的那么大

fgets

低危险

确保你的缓存和你说的那么大

memcpy

低危险

确保你的缓存和你说的那么大

snprintf

低危险

确保你的缓存和你说的那么大

strccpy

低危险

确保你的缓存和你说的那么大

strcadd

低危险

确保你的缓存和你说的那么大

strncpy

低危险

确保你的缓存和你说的那么大

vsnprintf

低危险

确保你的缓存和你说的那么大

    在我们匆忙完成工作的过程中,至今,我们还遗漏缓存溢出之外的一些详细信息。在我们下一个栏目中,我们将引擎的更深一层工作,并得到油腻。我们将更深入缓存溢出如何工作,甚至展示一些溢出代码。

资源

    • sh档案格式的snprintf()的免费工作版本
    • FIST,定位潜在缓存溢出脆弱性的错误注入工具。
    • DeveloperWorks上的“使你的软件守规矩:学习缓存溢出基础”(Make your software behave: Learning the basics of buffer overflows),Gary与John在高水平描述缓存溢出攻击并且讨论为什么缓存溢出是唯一最大的软件安全威胁
    • DeveloperWorker上的“使你的软件守规矩:确保你的软件是安全的”(Make your software behave: Assuring you software is secure),Gary与John展示它们为安全设计的第五步
    • DeveloperWorker第一个“使你的软件守规矩”栏目,Gary与John解释它们的安全哲学,并且解释他们为什么关注开发展面临的软件安全问题
    • Gary与John的DeveloperWorks栏目已经更新与出版成书《构建安全软件》,它引入丰富的新材料。现在捡起一个拷贝,你的使用者会谢谢你。

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

 


用火绒安全自定义规则解决微信WeChatAppEx内存泄漏问题 内存泄漏是软件开发中常见的性能问题,指程序未能释放不再使用的内存,导致可用内存逐渐减少,最终引发系统卡顿或崩溃。其原理通常是程序在堆内存分配后,由于逻辑错误丢失了对该内存区域的引用,致使垃圾回收机制无法生效。解决内存泄漏对保障系统稳定性和用户体验至关重要,尤其在长期运行的后台进程和服务中。在桌面应用场景下,用户常遇到第三方软件(如即时通讯工具)因内存管理不当导致资源占用过高的情况。本文针对微信WeChatAppEx进程的典型内存泄漏问题,提供了一套基于火绒安全软件自定义防护规则的工程实践解决方案,通过精细化 阅读详情

相关推荐

自回归分布滞后模型 (ARDL)及 Stata 具体操作步骤

例如,Bahmani-Oskooee 和 Brooks(1999)研究了汇率波动与贸易收支之间的关系,发现汇率的变动在长期和短期内对贸易收支的影响存在差异,ARDL 模型能够有效地捕捉这种复杂的关系。它结合了自回归(Autoregressive,AR)模型和分布滞后(Distributed Lag,DL)模型的特点,能够同时考察变量之间的短期和长期关系。假设我们收集了一段时间内的居民消费和可支配收入数据,通过对这些数据进行分析和估计,可以得到模型的参数估计值,从而揭示消费与收入之间的短期和长期关系。

a519573917的博客 6093

C中不安全函数

C 中大多数缓冲区溢出问题可以直接追溯到标准 C 库。最有害的罪魁祸首是不进行自变量检查的、有问题的字符串操作(strcpy、strcat、sprintf 和 gets)。一般来讲,象“避免使用 strcpy()”和“永远不使用 gets()”这样严格的规则接近于这个要求。 今天,编写的程序仍然利用这些调用,因为从来没有人教开发人员避免使用它们。某些人从各处获得某个提示,但即使是...

weixin_33968104的博客 777

多普勒频移测速与FMCW测距

文章目录时域与频域基于多普勒频移估计速度基于传统的FMCW测距什么是FMCWFMCW测距原理参考论文 时域与频域 时域 — 自变量是时间,即横轴是时间,纵轴是信号振幅的变化。表示振幅随时间的变化。 频域 — 自变量是频率,即横轴是频率,纵轴是该频率信号幅度的峰值。表示振幅峰值随频率的变化。 基于多普勒频移估计速度 当发送端静止而接收端相对运动时,有: v=FsFcv=\frac{F^s}{F}cv=FFs​c 其中,F是信号的原始频率;FsF^sFs 是接收信号频率与发送信号频率之差,即多普勒频移;c是

dsaaf21的博客 9186

C标准库源码解剖(13):输入输出函数stdio.h

    C标准中的I/O库是一个比较庞大的库,实现也比较复杂。显然I/O库的实现是依赖于操作系统的,不同的系统上I/O库的实现机理是不一样的。glibc中,I/O库的核心实现在libio目录下。有4个头文件libio.h, iolibio.h, libioP.h, strfile.h, stdio.h,其中stdio.h是导出的标准C头文件,其余都是内部实现。这里并不打算解剖整个I/O库的源代码(

Jack Zhou的专栏 3838

详解最大似然估计(MLE)、最大后验概率估计(MAP),以及贝叶斯公式的理解

声明:本文为原创文章,发表于nebulaf91的csdn博客。欢迎转载,但请务必保留本信息,注明文章出处。 本文作者: nebulaf91 本文原始地址:最大似然估计(Maximum likelihood estimation, 简称MLE)和最大后验概率估计(Maximum a posteriori estimation, 简称MAP)是很常用的两种参数估计方法,如果不理解这两种方法的思路,很

nebulaf91的博客 33万+

FPGA与GPU异构计算:重塑嵌入式AI的算力边界与场景定义

本文深入探讨了FPGA与GPU异构计算如何突破嵌入式AI的算力瓶颈。通过分析工业视觉、智能交通及航天等场景,阐述了FPGA负责高速数据采集与预处理,GPU专注复杂AI推理的协同模式,有效解决了传统单一架构在算力、功耗、接口和实时性上的挑战,为嵌入式AI应用提供了高效能解决方案。

spice的博客 486

php sscanf函数的用法,C++_详解C语言sscanf()函数、vsscanf()函数、vscanf()函数,C语言sscanf()函数:从字符串中 - phpStudy...

详解C语言sscanf()函数、vsscanf()函数、vscanf()函数C语言sscanf()函数:从字符串中读取指定格式的数据头文件:#include sscanf()函数用于从字符串中读取指定格式的数据,其原型如下:int sscanf (char *str, char * format [, argument, ...]);【参数】参数str为要读取数据的字符串;format为用户指定的...

weixin_32645173的博客 334

用Python和sklearn预测NBA比赛胜负:从数据清洗到模型优化的完整流程

本文详细介绍了如何使用Python和sklearn构建NBA比赛胜负预测模型,涵盖从数据清洗、特征工程到模型优化与部署的完整流程。通过对比随机森林、XGBoost等主流算法,提供实战技巧和解决方案,帮助数据爱好者掌握体育数据分析的核心技术。

weixin_30823001的博客 131

容易发生内存泄漏的八个场景,你都知道吗?

这篇文章介绍内存泄漏与内存溢出的区别,并从生命周期变长、不关闭资源、改变哈希值、缓存等多方面举例内存泄漏的场景内存泄漏是指当对象不再使用,但是GC无法回收该对象内存溢出是指当大量对象内存泄漏,没有资源再给新对象分配静态集合、饿汉单例、不合理的设置变量作用域都会使对象生命周期变长,从而导致内存泄漏非静态内部对象有隐式指向外部对象的指针、使用集合不删除元素等都会隐式导致内存泄漏忘记关闭资源导致内存泄漏(try-with-resource自动关闭解决)

m0_71777195的博客 750

把数字化转型真正落到组织里:读懂 SAP 的 OCM 六维框架

摘要: SAP的变革管理框架(OCM)强调数字化转型不仅是技术任务,更需关注组织与人的适应性。OCM包含六大维度:变革战略(明确方向与风险)、变革领导力(统一关键管理者行动)、变革沟通(分层传递信息)、变革实现(细化岗位级影响)、变革赋能(按角色设计培训)和变革有效性(持续评估)。该框架贯穿项目全周期,尤其在云项目中,需从早期规划变革策略,避免后期高代价调整。OCM的核心是将系统设计转化为组织语言,确保业务真正采纳新方式运作。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1433

C3 模块与普通 Bottleneck 堆叠区别

维度普通 Bottleneck 堆叠C3 模块设计理念残差学习CSP + 特征分治信息路径单一路径双路径(主干 + bypass)融合方式相加(Add)拼接(Concat)+ 卷积计算效率较低高(通道减半)特征保留弱(多次非线性)强(直连保留原始信息)梯度传播单一主路径多样化、更稳定任务适配通用(分类为主)专为目标检测优化可扩展性有限极强(即插即用各种模块)实际性能基准线显著优于(尤其在小目标和效率方面)

浩瀚之水的专栏 107

TVBoxOSC开源项目深度解析:构建个性化影视聚合平台的完整指南

你是否曾梦想拥有一个完全由自己掌控的影视聚合平台?一个可以自由定制界面、管理片源、打造专属观影体验的应用?TVBoxOSC正是这样一个让你梦想成真的开源项目。作为一款基于Android的影视聚合应用,TVBoxOSC不仅提供了强大的视频播放功能,更赋予了开发者无限的自定义空间。🎬 ## 为什么选择TVBoxOSC? 在众多影视应用中,TVBoxOSC以其开源特性和高度可定制性脱颖而出。与传统

gitblog_00112的博客 1066

基于STM32L4XX 、HAL库的ATD5984步进电机驱动器驱动程序应用设计

一、简介: ATD5984是一款内部集成了译码器的微特步进电机 驱动器,能使双极步进电机以全、半、1/4、/1/8、1/16 和1/32步进模式工作。步进模式由逻辑输入管脚MSx选 择。其输出驱动能力达到28V±1.6A。 译码器是ATD5984易于使用的关键,通过STEP管脚 输入一个脉冲就可以使电机完成一次步进,省去了相序 表,高频控制线及复杂的编程接口,使其更适于没有复 杂的微处理器或微处理器负担过重的场合。 在步进操作期间,ATD5984的内部电路可以自动

PP_Cottage的博客 406

MuleSoft企业级LLM编排:可治理、可审计、可韧性AI集成

大语言模型(LLM)作为新兴智能组件,正深度融入企业服务总线(ESB)与API治理体系。其核心挑战并非模型能力本身,而是如何实现可治理性、可追溯性、可组合性与可韧性——即让LLM调用服从身份认证、策略管控、全链路审计与熔断降级等SOA级工程规范。MuleSoft凭借API网关策略管理、DataWeave声明式编排与Anypoint可观测性,天然支撑LLM服务的三层抽象封装(能力契约层、模型适配层、治理增强层),使AI从‘黑盒调用’升级为注册在服务目录中的标准企业服务。本文聚焦银行账务、保险理赔、IoT设备预

weixin_30457465的博客 450

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

MuleSoft+LLM企业级AI编排:打通系统孤岛与大模型落地断层

企业级AI编排是指将大语言模型(LLM)深度嵌入现有IT基础设施,而非简单调用API。其核心原理在于利用集成平台构建可信、可控、可审计的服务网络,解决安全合规、数据新鲜度与业务逻辑三大断层。技术价值体现在降低AI落地风险、提升决策实时性、实现端到端流程自治。典型应用场景包括智能报销审核、供应链异常决策、并购尽职调查等需强系统联动的业务流。本文聚焦MuleSoft作为AI编排中枢的关键实践,涵盖DataWeave语义塑形、Anypoint Policies企业级护栏及LLM提示词工程在集成层的协同设计。

weixin_36250541的博客 383

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

K2.5不是模型,是工业级Agent集群架构说明书

Agent系统是将复杂AI任务拆解为可协作、可监控、可替换的专用智能体(Agent)的工程范式,其核心在于任务编排、状态同步与弹性调度。相比单一大模型黑箱,Agent集群通过标准化输入输出、异步发布-订阅通信和轻量级Orchestrator实现高可控性与强容错性。K2.5开源项目首次完整公开了生产级Agent集群的运行时(k2.5-runtime)、注册中心(agent_registry)与状态总线(state_bus)三大基础设施,覆盖任务拆解、健康治理、Schema校验与故障自愈等关键能力,适用于财报分

weixin_30613343的博客 923

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

跨行业的计算安全

Arm 架构的安全功能是与我们的合作伙伴合作创建的,确保规范的制定具有业内最佳的安全专业知识。定期发布新的Arm 安全技术意味着设备可以支持最高级别的安全标准。 Arm 架构是高度标准化的,有助于确保实现兼容。这有助于避免碎片化,并减少合作伙伴为有效对策创建安全服务的自定义实现的需要。 Arm 致力于确保所有最新的架构安全功能得到所有领先操作系统和工具的广泛支持。和开源项目。这使得整个生态系统可以在 Arm 架构上无缝开发。因此,最新的 Arm 安全扩展被广泛采用于各种外形尺寸和市场。

pslyunhai3255的博客 682

内存泄漏的8种情况(附代码示例)

一. 内存泄漏(memroy leak) 严格来说,只有对象不会再被程序用到了,但是GC又不能回收它们的情况,才叫内存泄漏 宽泛的讲,实际情况中很多时候一些不太好的实践会导致对象的生命周期变得很长甚至导致OOM,也叫“内存泄漏” 申请了内存用完了不释放,如申请了1024M内存,分配了512M内存一直不回收,那么可用内存就只有512M,仿佛泄漏掉一部分。 二. 内存溢出(out of memory) 申请内存时,没用足够的内存可以使用。 三. 两者的关系 内存泄漏的增多,最终会导致内存溢出。 .

枫陵的博客 2万+

内存泄漏概念

这种情况下,即使在contains方法使用该对象的当前引用作为的参数去HashSet中集合中检索对象,也将返回找不到对象的结果。改变哈希值,当一个对象被存储进HashSet集合中以后,就不能修改这个对象中那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进行HashSet集合中时的哈希值就不同了。单例模式生命周期和JVM一样长,如果持用外包对象的引用,那么这个外部对象也不会被回收,那么就会造成内存泄露。内部类持有外部类,如果一个外部类的实例对象的方法返回一个内部类的实例对象,

CB_Beginner的博客 749

java中内存泄露8种情况的总结(转载)

由于java的JVM引入了垃圾回收机制,垃圾回收器会自动回收不再使用的对象,了解JVM回收机制的都知道JVM是使用引用计数法和可达性分析算法来判断对象是否是不再使用的对象,本质都是判断一个对象是否还被引用。那么对于这种情况下,由于代码的实现不同就会出现很多种内存泄漏问题(让JVM误以为此对象还在引用中,无法回收,造成内存泄漏)。 1、静态集合类,如HashMap、LinkedList等等。如果这些容器为静态的,那么它们的生命周期与程序一致,则容器中的对象在程序结束之前将不能被释放,从而造成内存泄漏。简单而言

whx_0612的博客 1314

绕过Linux不可执行堆栈保护的方法浅析

很久以前的文章, 虽然很老但其中的技术却能让你学到很多东西,特别是底层方面的,我用4天看完了,由衷感慨黑客的智慧。(我在RH 7.2下实验成功)绕过Linux不可执行堆栈保护的方法浅析                                           by warning3                                           http://www.

zither的专栏 5229

如何设置堆栈不可执行和ASLR

最近,做一个调查,如何在Windows和Linux系统下,做堆栈执行保护,和ASLR(Address Space Layout Randomization)。找了好多材料,才找到,在这里总结一下:   OS Execution space protection ASLR (Address Space Layout Randomization) Description Che

jimmyleeee的专栏 6029

关于堆栈的讲解(我见过的最经典的)

这是一篇转发的文章,我对他进行了格式化而已,原文出处不详。一、预备知识—程序的内存分配一个由c/C++编译的程序占用的内存分为以下几个部分 1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。 2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类

yingms的专栏 16万+

软件安全实验——lab9(缓冲区溢出:return-to-libc绕过非可执行堆栈)

目录标题1、实验室概况2、实验室任务2.1初始设置2.2脆弱程序2.3任务1:利用漏洞(1) 编译程序(2)找到“\bin\sh”的地址(3)查找libc函数的地址:(4)确定输入和bof函数的返回地址的距离(5)攻击代码(6)攻击Task 1附加任务(1)pop %esp(2)按照下图构造地址序列:(3)/bin/sh和/usr/bin/的地址(4)system函数和setuid函数的地址(5)确定输入和bof函数的返回地址的距离(6)修改buf数组大小(7)在Bof函数返回的地址设断点(8)攻击3、指导

Onlyone_1314的博客 1748

java中内存泄露8种情况的总结

由于java的JVM引入了垃圾回收机制,垃圾回收器会自动回收不再使用的对象,了解JVM回收机制的都知道JVM是使用引用计数法和可达性分析算法来判断对象是否是不再使用的对象,本质都是判断一个对象是否还被引用。那么对于这种情况下,由于代码的实现不同就会出现很多种内存泄漏问题(让JVM误以为此对象还在引用中,无法回收,造成内存泄漏)。本文将解析常见8种内存泄露的情况

ratel的博客 7万+
上一篇: C++头文件----<cstdio>(stdio.h)
下一篇: 关于SQLite
henrik_he
博客等级 码龄16年 36粉丝 26原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值