Win XP x64上的段错误,XP x32上没有发生 - strncpy问题?怎么修?

时间:2009-02-25 15:52:56

标签: c++ visual-c++ windows-xp 64-bit

我很缺乏使用C ++的经验,但我正在尝试在64位XP平台上为matlab编译SBML toolbox版本2.0.2。 SBML工具箱取决于Xerces 2.8和libsbml 2.3.5。

我已经能够在32位机器上构建和编译工具箱,并且在我测试时它可以工作。但是,在64位计算机(这是一个巨大的PITA!)上重建它之后,当我尝试用它读取长.xml文件时,我遇到了分段错误。

我怀疑问题是由pointer addresses issues造成的。

分段故障的堆栈跟踪以:

开头
[ 0] 000000003CB3856E libsbml.dll+165230 (StringBuffer_append+000030)
[ 6] 000000003CB1BFAF libsbml.dll+049071 (EventAssignment_createWith+001631)
[ 12] 000000003CB1C1D7 libsbml.dll+049623 (SBML_formulaToString+000039)
[ 18] 000000003CB2C154 libsbml.dll+115028 (

所以我正在查看libsbml代码中的StringBuffer_append函数:

LIBSBML_EXTERN
void
StringBuffer_append (StringBuffer_t *sb, const char *s)
{
  unsigned long len = strlen(s);


  StringBuffer_ensureCapacity(sb, len);

  strncpy(sb->buffer + sb->length, s, len + 1);
  sb->length += len;
}

ensureCapacity看起来像这样:

LIBSBML_EXTERN
void
StringBuffer_ensureCapacity (StringBuffer_t *sb, unsigned long n)
{
  unsigned long wanted = sb->length + n;
  unsigned long c;


  if (wanted > sb->capacity)
  {
    /**
     * Double the total new capacity (c) until it is greater-than wanted.
     * Grow StringBuffer by this amount minus the current capacity.
     */
    for (c = 2 * sb->capacity; c < wanted; c *= 2) ;
    StringBuffer_grow(sb, c - sb->capacity);
  }                   
}

和StringBuffer_grow看起来像这样:

LIBSBML_EXTERN
void
StringBuffer_grow (StringBuffer_t *sb, unsigned long n)
{
  sb->capacity += n;
  sb->buffer    = (char *) safe_realloc(sb->buffer, sb->capacity + 1);
}

可能是

strncpy(sb->buffer + sb->length, s, len + 1);
StringBuffer_append中的

是我的段错误的来源吗?

如果是这样,有人可以建议修复吗?我真的不懂C ++,特别是对指针和内存寻址感到困惑,所以我很可能不知道你在谈论什么 - 我需要一些手持。

另外,我将我的构建过程的详细信息放在网上here,以防其他人正在尝试使用Microsoft Visual C ++ Express Edition为64位系统编译C ++。

提前致谢!

-Ben

8 个答案:

答案 0 :(得分:1)

尝试打印或使用调试器查看您获得的某些中间变量的值。在StringBuffer_append()O / P len中,在StringBuffer_ensureCapacity()中,在循环之前和循环中观察sb-&gt; capacity和c。看看这些数值是否有意义。

通过访问字符串末尾之外的数据可能会导致分段错误。

它在32位机器而不是64位O / S上工作的奇怪事实也是一个线索。两台机器的物理和页面文件内存大小是否相同?此外,在64位计算机中,内核空间可能比32位计算机大,并且占用了32位O / S的内存空间的用户部分中的一些可用内存空间。对于XML,整个文档必须适合内存。如果这是问题,可能有一些开关来设置大小。只有在使用非常大的字符串时才会出现导致问题的机器差异。如果字符串不是很大,那么库或实用程序方法可能会在64位环境中无法正常工作。

另外,如果您没有其他任何可以尝试的话,请使用简单/小的xml文件开始。

你在哪里初始化sb-&gt;长度。你的问题很可能是strncpy(),虽然我不知道为什么32bit - &gt; 64位O / S变化很重要。最好的选择是查看中间值,然后您的问题就会很明显。

答案 1 :(得分:1)

作为libsbml的开发人员之一,我偶然发现了这一点。这对你来说还是个问题吗?与此同时,我们发布了libsbml 5,分别有64位和32位版本以及改进的测试,请看看:

http://sf.net/projects/sbml/files/libsbml

答案 2 :(得分:0)

这个问题几乎可以解决。是的,可能是strncpy做坏事,但最有可能的是,它只是传递了一个坏指针。哪个可能来自任何地方。段错误(或Windows中的访问冲突)仅表示应用程序尝试读取或写入其无权访问的地址。所以真正的问题是,该地址来自哪里?尝试跟随指针的函数可能没问题。但它传递了来自其他地方的坏指针。可能。

不幸的是,在最好的时候调试C代码并非易事。如果代码不是您自己的代码,则不会使代码更容易。 :)

答案 3 :(得分:0)

StringBuffer定义如下:

/**
 * Creates a new StringBuffer and returns a pointer to it.
 */
LIBSBML_EXTERN
StringBuffer_t *
StringBuffer_create (unsigned long capacity)
{
  StringBuffer_t *sb;


  sb           = (StringBuffer_t *) safe_malloc(sizeof(StringBuffer_t));
  sb->buffer   = (char *)           safe_malloc(capacity + 1);
  sb->capacity = capacity;

  StringBuffer_reset(sb);

  return sb;
}

堆栈跟踪的更多内容是:

[  0] 000000003CB3856E              libsbml.dll+165230 (StringBuffer_append+000030)
[  6] 000000003CB1BFAF              libsbml.dll+049071 (EventAssignment_createWith+001631)
[ 12] 000000003CB1C1D7              libsbml.dll+049623 (SBML_formulaToString+000039)
[ 18] 000000003CB2C154              libsbml.dll+115028 (Rule::setFormulaFromMath+000036)
[ 20] 0000000001751913              libmx.dll+137491 (mxCheckMN_700+000723)
[ 25] 000000003CB1E7B2              libsbml.dll+059314 (KineticLaw_getFormula+000018)
[ 37] 0000000035727749              TranslateSBML.mexw64+030537 (mexFunction+009353)

答案 4 :(得分:0)

看起来它是否在任何StringBuffer_ *函数中,它将在堆栈跟踪中。我不同意如何实现_ensureCapacity和_grow。这些函数都没有检查realloc是否有效。 Realloc失败肯定会导致段错误。我会在_ensureCapacity之后插入一个null的检查。使用_ensureCapacity和_grow的方式,似乎有可能得到一个一个错误。如果您在Windows上运行,则64位和32位系统可能具有不同的页面保护机制,导致其失败。 (在页面保护较弱的系统上,你经常会遇到malloc内存中的逐个错误。)

答案 5 :(得分:0)

让我们假设safe_malloc和safe_realloc做了一些明智的事情,比如在程序无法获取请求的内存时中止程序。这样你的程序就不会继续使用无效指针执行。

现在让我们看看与所需容量相比,StringBuffer_ensureCapacity增加了多大的缓冲区。这不是一个错误的错误。这是一个两个因素的错误。

你的程序是如何在x32中运行的,我无法猜测。

答案 6 :(得分:0)

回应bk1e对这个问题的评论 - 不幸的是,我需要2.0.2版本与COBRA工具箱一起使用,它不适用于较新的版本3.所以,我现在仍然坚持使用这个旧版本

我也试图调试一些墙 - 我正在构建一个.dll,所以除了重新编译xerces以确保它在MSVC ++中具有相同的调试设置之外,我还需要附加到Matlab进程到进行调试 - 对于我在这种环境中的有限经验来说,这是一个相当大的跳跃,我还没有深入研究它。

我原本希望缓冲区分配或扩展有一些明显的语法问题。但是看起来我已经忍受了几天的痛苦。

答案 7 :(得分:0)

unsigned long不是用于Windows中64位计算机上的大小的安全类型。与Linux不同,Windows在32位和64位架构上将long定义为32位。因此,如果附加的缓冲区大小超过4 GB(或者如果您尝试追加长度大于4 GB的字符串),则需要将unsigned long类型声明更改为size_t (在所有操作系统中,64位体系结构为64位)。

但是,如果您只读取一个1.5 MB的文件,我看不出你如何让StringBuffer的大小超过4 GB,所以这可能是一条死胡同。